diff -Nru containerd-1.2.6/ADOPTERS.md containerd-1.5.9/ADOPTERS.md --- containerd-1.2.6/ADOPTERS.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/ADOPTERS.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +## containerd Adopters + +A non-exhaustive list of containerd adopters is provided below. + +**_Docker/Moby engine_** - Containerd began life prior to its CNCF adoption as a lower-layer +runtime manager for `runc` processes below the Docker engine. Continuing today, containerd +has extremely broad production usage as a component of the [Docker engine](https://github.com/docker/docker-ce) +stack. Note that this includes any use of the open source [Moby engine project](https://github.com/moby/moby); +including the Balena project listed below. + +**_[IBM Cloud Kubernetes Service (IKS)](https://www.ibm.com/cloud/container-service)_** - offers containerd as the CRI runtime for v1.11 and higher versions. + +**_[IBM Cloud Private (ICP)](https://www.ibm.com/cloud/private)_** - IBM's on-premises cloud offering has containerd as a "tech preview" CRI runtime for the Kubernetes offered within this product for the past two releases, and plans to fully migrate to containerd in a future release. + +**_[Google Cloud Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/)_** - offers containerd as the CRI runtime in **beta** for recent versions of Kubernetes. + +**_[AWS Fargate](https://aws.amazon.com/fargate)_** - uses containerd + Firecracker (noted below) as the runtime and isolation technology for containers run in the Fargate platform. Fargate is a serverless, container-native compute offering from Amazon Web Services. + +**_Cloud Foundry_** - The [Guardian container manager](https://github.com/cloudfoundry/guardian) for CF has been using OCI runC directly with additional code from CF managing the container image and filesystem interactions, but have recently migrated to use containerd as a replacement for the extra code they had written around runC. + +**_Alibaba's PouchContainer_** - The Alibaba [PouchContainer](https://github.com/alibaba/pouch) project uses containerd as its runtime for a cloud native offering that has unique isolation and image distribution capabilities. + +**_Rancher's k3s project_** - Rancher Labs [k3s](https://github.com/rancher/k3s) is a lightweight Kubernetes distribution; in their words: "Easy to install, half the memory, all in a binary less than 40mb." k8s uses containerd as the embedded runtime for this popular lightweight Kubernetes variant. + +**_Rancher's Rio project_** - Rancher Labs [Rio](https://github.com/rancher/rio) project uses containerd as the runtime for a combined Kubernetes, Istio, and container "Cloud Native Container Distribution" platform. + +**_Eliot_** - The [Eliot](https://github.com/ernoaapa/eliot) container project for IoT device container management uses containerd as the runtime. + +**_Balena_** - Resin's [Balena](https://github.com/resin-os/balena) container engine, based on moby/moby but for edge, embedded, and IoT use cases, uses the containerd and runc stack in the same way that the Docker engine uses containerd. + +**_LinuxKit_** - the Moby project's [LinuxKit](https://github.com/linuxkit/linuxkit) for building secure, minimal Linux OS images in a container-native model uses containerd as the core runtime for system and service containers. + +**_BuildKit_** - The Moby project's [BuildKit](https://github.com/moby/buildkit) can use either runC or containerd as build execution backends for building container images. BuildKit support has also been built into the Docker engine in recent releases, making BuildKit provide the backend to the `docker build` command. + +**_Azure acs-engine_** - Microsoft Azure's [acs-engine](https://github.com/Azure/acs-engine) open source project has customizable deployment of Kubernetes clusters, where containerd is a selectable container runtime. At some point in the future Azure's AKS service will default to use containerd as the CRI runtime for deployed Kubernetes clusters. + +**_Amazon Firecracker_** - The AWS [Firecracker VMM project](http://firecracker-microvm.io/) has extended containerd with a new snapshotter and v2 shim to allow containerd to drive virtualized container processes via their VMM implementation. More details on their containerd integration are available in [their GitHub project](https://github.com/firecracker-microvm/firecracker-containerd). + +**_Kata Containers_** - The [Kata containers](https://katacontainers.io/) lightweight-virtualized container runtime project integrates with containerd via a custom v2 shim implementation that drives the Kata container runtime. + +**_D2iQ Konvoy_** - D2iQ Inc [Konvoy](https://d2iq.com/products/konvoy) product uses containerd as the container runtime for its Kubernetes distribution. + +**_Inclavare Containers_** - [Inclavare Containers](https://github.com/alibaba/inclavare-containers) is an innovation of container runtime with the novel approach for launching protected containers in hardware-assisted Trusted Execution Environment (TEE) technology, aka Enclave, which can prevent the untrusted entity, such as Cloud Service Provider (CSP), from accessing the sensitive and confidential assets in use. + +**_Other Projects_** - While the above list provides a cross-section of well known uses of containerd, the simplicity and clear API layer for containerd has inspired many smaller projects around providing simple container management platforms. Several examples of building higher layer functionality on top of the containerd base have come from various containerd community participants: + - Michael Crosby's [boss](https://github.com/crosbymichael/boss) project, + - Evan Hazlett's [stellar](https://github.com/ehazlett/stellar) project, + - Paul Knopf's immutable Linux image builder project: [darch](https://github.com/godarch/darch). diff -Nru containerd-1.2.6/api/events/container.pb.go containerd-1.5.9/api/events/container.pb.go --- containerd-1.2.6/api/events/container.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/container.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,60 +1,20 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/events/container.proto -/* - Package events is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/events/container.proto - github.com/containerd/containerd/api/events/content.proto - github.com/containerd/containerd/api/events/image.proto - github.com/containerd/containerd/api/events/namespace.proto - github.com/containerd/containerd/api/events/snapshot.proto - github.com/containerd/containerd/api/events/task.proto - - It has these top-level messages: - ContainerCreate - ContainerUpdate - ContainerDelete - ContentDelete - ImageCreate - ImageUpdate - ImageDelete - NamespaceCreate - NamespaceUpdate - NamespaceDelete - SnapshotPrepare - SnapshotCommit - SnapshotRemove - TaskCreate - TaskStart - TaskDelete - TaskIO - TaskExit - TaskOOM - TaskExecAdded - TaskExecStarted - TaskPaused - TaskResumed - TaskCheckpointed -*/ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/types" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import typeurl "github.com/containerd/typeurl" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + fmt "fmt" + github_com_containerd_typeurl "github.com/containerd/typeurl" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -65,55 +25,212 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type ContainerCreate struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` - Runtime *ContainerCreate_Runtime `protobuf:"bytes,3,opt,name=runtime" json:"runtime,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` + Runtime *ContainerCreate_Runtime `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ContainerCreate) Reset() { *m = ContainerCreate{} } +func (*ContainerCreate) ProtoMessage() {} +func (*ContainerCreate) Descriptor() ([]byte, []int) { + return fileDescriptor_0d1f05b8626f83ea, []int{0} +} +func (m *ContainerCreate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContainerCreate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContainerCreate) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerCreate.Merge(m, src) +} +func (m *ContainerCreate) XXX_Size() int { + return m.Size() +} +func (m *ContainerCreate) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerCreate.DiscardUnknown(m) } -func (m *ContainerCreate) Reset() { *m = ContainerCreate{} } -func (*ContainerCreate) ProtoMessage() {} -func (*ContainerCreate) Descriptor() ([]byte, []int) { return fileDescriptorContainer, []int{0} } +var xxx_messageInfo_ContainerCreate proto.InternalMessageInfo type ContainerCreate_Runtime struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Options *google_protobuf.Any `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Options *types.Any `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ContainerCreate_Runtime) Reset() { *m = ContainerCreate_Runtime{} } func (*ContainerCreate_Runtime) ProtoMessage() {} func (*ContainerCreate_Runtime) Descriptor() ([]byte, []int) { - return fileDescriptorContainer, []int{0, 0} + return fileDescriptor_0d1f05b8626f83ea, []int{0, 0} +} +func (m *ContainerCreate_Runtime) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerCreate_Runtime) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContainerCreate_Runtime.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContainerCreate_Runtime) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerCreate_Runtime.Merge(m, src) +} +func (m *ContainerCreate_Runtime) XXX_Size() int { + return m.Size() } +func (m *ContainerCreate_Runtime) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerCreate_Runtime.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerCreate_Runtime proto.InternalMessageInfo type ContainerUpdate struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` - Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - SnapshotKey string `protobuf:"bytes,4,opt,name=snapshot_key,json=snapshotKey,proto3" json:"snapshot_key,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Image string `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + SnapshotKey string `protobuf:"bytes,4,opt,name=snapshot_key,json=snapshotKey,proto3" json:"snapshot_key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ContainerUpdate) Reset() { *m = ContainerUpdate{} } +func (*ContainerUpdate) ProtoMessage() {} +func (*ContainerUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_0d1f05b8626f83ea, []int{1} +} +func (m *ContainerUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContainerUpdate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContainerUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerUpdate.Merge(m, src) +} +func (m *ContainerUpdate) XXX_Size() int { + return m.Size() +} +func (m *ContainerUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerUpdate.DiscardUnknown(m) } -func (m *ContainerUpdate) Reset() { *m = ContainerUpdate{} } -func (*ContainerUpdate) ProtoMessage() {} -func (*ContainerUpdate) Descriptor() ([]byte, []int) { return fileDescriptorContainer, []int{1} } +var xxx_messageInfo_ContainerUpdate proto.InternalMessageInfo type ContainerDelete struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ContainerDelete) Reset() { *m = ContainerDelete{} } +func (*ContainerDelete) ProtoMessage() {} +func (*ContainerDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_0d1f05b8626f83ea, []int{2} +} +func (m *ContainerDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContainerDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContainerDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerDelete.Merge(m, src) +} +func (m *ContainerDelete) XXX_Size() int { + return m.Size() +} +func (m *ContainerDelete) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerDelete.DiscardUnknown(m) } -func (m *ContainerDelete) Reset() { *m = ContainerDelete{} } -func (*ContainerDelete) ProtoMessage() {} -func (*ContainerDelete) Descriptor() ([]byte, []int) { return fileDescriptorContainer, []int{2} } +var xxx_messageInfo_ContainerDelete proto.InternalMessageInfo func init() { proto.RegisterType((*ContainerCreate)(nil), "containerd.events.ContainerCreate") proto.RegisterType((*ContainerCreate_Runtime)(nil), "containerd.events.ContainerCreate.Runtime") proto.RegisterType((*ContainerUpdate)(nil), "containerd.events.ContainerUpdate") + proto.RegisterMapType((map[string]string)(nil), "containerd.events.ContainerUpdate.LabelsEntry") proto.RegisterType((*ContainerDelete)(nil), "containerd.events.ContainerDelete") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/container.proto", fileDescriptor_0d1f05b8626f83ea) +} + +var fileDescriptor_0d1f05b8626f83ea = []byte{ + // 413 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x0a, 0xd3, 0x30, + 0x18, 0xc7, 0x97, 0x76, 0x6e, 0x98, 0x0a, 0x6a, 0x18, 0x52, 0x7b, 0xa8, 0x73, 0xa7, 0xe9, 0x21, + 0x85, 0x7a, 0x51, 0x77, 0xd1, 0x6d, 0x0a, 0xa2, 0x82, 0x14, 0x84, 0xe1, 0x45, 0xd2, 0x35, 0xeb, + 0x82, 0x6d, 0x52, 0xda, 0x74, 0xd0, 0x9b, 0x8f, 0xe2, 0xe3, 0xec, 0xe8, 0xc1, 0x83, 0x27, 0x71, + 0x05, 0xdf, 0xc0, 0x07, 0x90, 0x26, 0xeb, 0x56, 0x14, 0x95, 0x9d, 0xfa, 0xcf, 0xd7, 0xff, 0x3f, + 0xdf, 0xf7, 0xfb, 0x08, 0x9c, 0xc5, 0x4c, 0x6e, 0xcb, 0x10, 0xaf, 0x45, 0xea, 0xad, 0x05, 0x97, + 0x84, 0x71, 0x9a, 0x47, 0x5d, 0x49, 0x32, 0xe6, 0xd1, 0x1d, 0xe5, 0xb2, 0x38, 0x57, 0x71, 0x96, + 0x0b, 0x29, 0xd0, 0xcd, 0xb3, 0x0d, 0x6b, 0x8b, 0x73, 0x3b, 0x16, 0x22, 0x4e, 0xa8, 0xa7, 0x0c, + 0x61, 0xb9, 0xf1, 0x08, 0xaf, 0xb4, 0xdb, 0x19, 0xc5, 0x22, 0x16, 0x4a, 0x7a, 0x8d, 0x3a, 0x56, + 0x9f, 0xfc, 0x77, 0x80, 0xd3, 0x55, 0x59, 0x52, 0xc6, 0x8c, 0x7b, 0x1b, 0x46, 0x93, 0x28, 0x23, + 0x72, 0xab, 0x6f, 0x98, 0x7c, 0x01, 0xf0, 0xfa, 0xa2, 0xb5, 0x2f, 0x72, 0x4a, 0x24, 0x45, 0xb7, + 0xa0, 0xc1, 0x22, 0x1b, 0x8c, 0xc1, 0xf4, 0xea, 0x7c, 0x50, 0x7f, 0xbb, 0x63, 0xbc, 0x58, 0x06, + 0x06, 0x8b, 0xd0, 0x08, 0x5e, 0x61, 0x29, 0x89, 0xa9, 0x6d, 0x34, 0xbf, 0x02, 0x7d, 0x40, 0x4b, + 0x38, 0xcc, 0x4b, 0x2e, 0x59, 0x4a, 0x6d, 0x73, 0x0c, 0xa6, 0x96, 0x7f, 0x1f, 0xff, 0x41, 0x86, + 0x7f, 0x6b, 0x81, 0x03, 0x9d, 0x08, 0xda, 0xa8, 0xf3, 0x1a, 0x0e, 0x8f, 0x35, 0x84, 0x60, 0x9f, + 0x93, 0x94, 0xea, 0x01, 0x02, 0xa5, 0x11, 0x86, 0x43, 0x91, 0x49, 0x26, 0x78, 0xa1, 0x9a, 0x5b, + 0xfe, 0x08, 0xeb, 0x5d, 0xe1, 0x16, 0x10, 0x3f, 0xe5, 0x55, 0xd0, 0x9a, 0x26, 0x3f, 0xba, 0x58, + 0x6f, 0xb3, 0xe8, 0x72, 0xac, 0xe7, 0x70, 0x90, 0x90, 0x90, 0x26, 0x85, 0x6d, 0x8e, 0xcd, 0xa9, + 0xe5, 0xe3, 0x7f, 0x51, 0xe9, 0x0e, 0xf8, 0x95, 0x0a, 0x3c, 0xe3, 0x32, 0xaf, 0x82, 0x63, 0x1a, + 0xdd, 0x85, 0xd7, 0x0a, 0x4e, 0xb2, 0x62, 0x2b, 0xe4, 0xfb, 0x0f, 0xb4, 0xb2, 0xfb, 0xaa, 0x89, + 0xd5, 0xd6, 0x5e, 0xd2, 0xca, 0x79, 0x04, 0xad, 0x4e, 0x12, 0xdd, 0x80, 0x66, 0x63, 0xd4, 0xf8, + 0x8d, 0x6c, 0x26, 0xdc, 0x91, 0xa4, 0x3c, 0x4d, 0xa8, 0x0e, 0x8f, 0x8d, 0x87, 0x60, 0x72, 0xaf, + 0x83, 0xb9, 0xa4, 0x09, 0xfd, 0x3b, 0xe6, 0xfc, 0xcd, 0xfe, 0xe0, 0xf6, 0xbe, 0x1e, 0xdc, 0xde, + 0xc7, 0xda, 0x05, 0xfb, 0xda, 0x05, 0x9f, 0x6b, 0x17, 0x7c, 0xaf, 0x5d, 0xf0, 0xe9, 0xa7, 0x0b, + 0xde, 0xf9, 0x17, 0x3c, 0xe5, 0x99, 0xfe, 0xac, 0xc0, 0xca, 0x08, 0x07, 0x6a, 0xff, 0x0f, 0x7e, + 0x05, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x09, 0xe0, 0xd6, 0x0b, 0x03, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *ContainerCreate) Field(fieldpath []string) (string, bool) { @@ -153,7 +270,7 @@ case "name": return string(m.Name), len(m.Name) > 0 case "options": - decoded, err := typeurl.UnmarshalAny(m.Options) + decoded, err := github_com_containerd_typeurl.UnmarshalAny(m.Options) if err != nil { return "", false } @@ -209,7 +326,7 @@ func (m *ContainerCreate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -217,39 +334,52 @@ } func (m *ContainerCreate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Runtime != nil { + { + size, err := m.Runtime.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } if len(m.Image) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Image) + copy(dAtA[i:], m.Image) i = encodeVarintContainer(dAtA, i, uint64(len(m.Image))) - i += copy(dAtA[i:], m.Image) + i-- + dAtA[i] = 0x12 } - if m.Runtime != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintContainer(dAtA, i, uint64(m.Runtime.Size())) - n1, err := m.Runtime.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintContainer(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ContainerCreate_Runtime) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -257,33 +387,45 @@ } func (m *ContainerCreate_Runtime) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerCreate_Runtime) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Options != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintContainer(dAtA, i, uint64(m.Options.Size())) - n2, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainer(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintContainer(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ContainerUpdate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -291,52 +433,66 @@ } func (m *ContainerUpdate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Image) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(m.Image))) - i += copy(dAtA[i:], m.Image) + if len(m.SnapshotKey) > 0 { + i -= len(m.SnapshotKey) + copy(dAtA[i:], m.SnapshotKey) + i = encodeVarintContainer(dAtA, i, uint64(len(m.SnapshotKey))) + i-- + dAtA[i] = 0x22 } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x1a - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovContainer(uint64(len(k))) + 1 + len(v) + sovContainer(uint64(len(v))) - i = encodeVarintContainer(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintContainer(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintContainer(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintContainer(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a } } - if len(m.SnapshotKey) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintContainer(dAtA, i, uint64(len(m.SnapshotKey))) - i += copy(dAtA[i:], m.SnapshotKey) + if len(m.Image) > 0 { + i -= len(m.Image) + copy(dAtA[i:], m.Image) + i = encodeVarintContainer(dAtA, i, uint64(len(m.Image))) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintContainer(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ContainerDelete) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -344,29 +500,44 @@ } func (m *ContainerDelete) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintContainer(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintContainer(dAtA []byte, offset int, v uint64) int { + offset -= sovContainer(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *ContainerCreate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -381,10 +552,16 @@ l = m.Runtime.Size() n += 1 + l + sovContainer(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ContainerCreate_Runtime) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -395,10 +572,16 @@ l = m.Options.Size() n += 1 + l + sovContainer(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ContainerUpdate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -421,28 +604,30 @@ if l > 0 { n += 1 + l + sovContainer(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ContainerDelete) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovContainer(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovContainer(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozContainer(x uint64) (n int) { return sovContainer(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -455,6 +640,7 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Image:` + fmt.Sprintf("%v", this.Image) + `,`, `Runtime:` + strings.Replace(fmt.Sprintf("%v", this.Runtime), "ContainerCreate_Runtime", "ContainerCreate_Runtime", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -465,7 +651,8 @@ } s := strings.Join([]string{`&ContainerCreate_Runtime{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -478,7 +665,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -489,6 +676,7 @@ `Image:` + fmt.Sprintf("%v", this.Image) + `,`, `Labels:` + mapStringForLabels + `,`, `SnapshotKey:` + fmt.Sprintf("%v", this.SnapshotKey) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -499,6 +687,7 @@ } s := strings.Join([]string{`&ContainerDelete{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -526,7 +715,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -554,7 +743,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -564,6 +753,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -583,7 +775,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -593,6 +785,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -612,7 +807,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -621,6 +816,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -637,12 +835,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainer } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -667,7 +866,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -695,7 +894,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -705,6 +904,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -724,7 +926,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -733,11 +935,14 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf.Any{} + m.Options = &types.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -749,12 +954,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainer } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -779,7 +985,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -807,7 +1013,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -817,6 +1023,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -836,7 +1045,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -846,6 +1055,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -865,7 +1077,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -874,6 +1086,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -894,7 +1109,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -911,7 +1126,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -921,6 +1136,9 @@ return ErrInvalidLengthContainer } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthContainer + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -937,7 +1155,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -947,6 +1165,9 @@ return ErrInvalidLengthContainer } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthContainer + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -958,7 +1179,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainer } if (iNdEx + skippy) > postIndex { @@ -983,7 +1204,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -993,6 +1214,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1004,12 +1228,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainer } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1034,7 +1259,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1062,7 +1287,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1072,6 +1297,9 @@ return ErrInvalidLengthContainer } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainer + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1083,12 +1311,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainer } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1101,6 +1330,7 @@ func skipContainer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1132,10 +1362,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1152,87 +1380,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthContainer } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContainer - } - 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 := skipContainer(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupContainer + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthContainer + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthContainer = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowContainer = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthContainer = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowContainer = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupContainer = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/container.proto", fileDescriptorContainer) -} - -var fileDescriptorContainer = []byte{ - // 413 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x0a, 0xd3, 0x30, - 0x18, 0xc7, 0x97, 0x76, 0x6e, 0x98, 0x0a, 0x6a, 0x18, 0x52, 0x7b, 0xa8, 0x73, 0xa7, 0xe9, 0x21, - 0x85, 0x7a, 0x51, 0x77, 0xd1, 0x6d, 0x0a, 0xa2, 0x82, 0x14, 0x84, 0xe1, 0x45, 0xd2, 0x35, 0xeb, - 0x82, 0x6d, 0x52, 0xda, 0x74, 0xd0, 0x9b, 0x8f, 0xe2, 0xe3, 0xec, 0xe8, 0xc1, 0x83, 0x27, 0x71, - 0x05, 0xdf, 0xc0, 0x07, 0x90, 0x26, 0xeb, 0x56, 0x14, 0x95, 0x9d, 0xfa, 0xcf, 0xd7, 0xff, 0x3f, - 0xdf, 0xf7, 0xfb, 0x08, 0x9c, 0xc5, 0x4c, 0x6e, 0xcb, 0x10, 0xaf, 0x45, 0xea, 0xad, 0x05, 0x97, - 0x84, 0x71, 0x9a, 0x47, 0x5d, 0x49, 0x32, 0xe6, 0xd1, 0x1d, 0xe5, 0xb2, 0x38, 0x57, 0x71, 0x96, - 0x0b, 0x29, 0xd0, 0xcd, 0xb3, 0x0d, 0x6b, 0x8b, 0x73, 0x3b, 0x16, 0x22, 0x4e, 0xa8, 0xa7, 0x0c, - 0x61, 0xb9, 0xf1, 0x08, 0xaf, 0xb4, 0xdb, 0x19, 0xc5, 0x22, 0x16, 0x4a, 0x7a, 0x8d, 0x3a, 0x56, - 0x9f, 0xfc, 0x77, 0x80, 0xd3, 0x55, 0x59, 0x52, 0xc6, 0x8c, 0x7b, 0x1b, 0x46, 0x93, 0x28, 0x23, - 0x72, 0xab, 0x6f, 0x98, 0x7c, 0x01, 0xf0, 0xfa, 0xa2, 0xb5, 0x2f, 0x72, 0x4a, 0x24, 0x45, 0xb7, - 0xa0, 0xc1, 0x22, 0x1b, 0x8c, 0xc1, 0xf4, 0xea, 0x7c, 0x50, 0x7f, 0xbb, 0x63, 0xbc, 0x58, 0x06, - 0x06, 0x8b, 0xd0, 0x08, 0x5e, 0x61, 0x29, 0x89, 0xa9, 0x6d, 0x34, 0xbf, 0x02, 0x7d, 0x40, 0x4b, - 0x38, 0xcc, 0x4b, 0x2e, 0x59, 0x4a, 0x6d, 0x73, 0x0c, 0xa6, 0x96, 0x7f, 0x1f, 0xff, 0x41, 0x86, - 0x7f, 0x6b, 0x81, 0x03, 0x9d, 0x08, 0xda, 0xa8, 0xf3, 0x1a, 0x0e, 0x8f, 0x35, 0x84, 0x60, 0x9f, - 0x93, 0x94, 0xea, 0x01, 0x02, 0xa5, 0x11, 0x86, 0x43, 0x91, 0x49, 0x26, 0x78, 0xa1, 0x9a, 0x5b, - 0xfe, 0x08, 0xeb, 0x5d, 0xe1, 0x16, 0x10, 0x3f, 0xe5, 0x55, 0xd0, 0x9a, 0x26, 0x3f, 0xba, 0x58, - 0x6f, 0xb3, 0xe8, 0x72, 0xac, 0xe7, 0x70, 0x90, 0x90, 0x90, 0x26, 0x85, 0x6d, 0x8e, 0xcd, 0xa9, - 0xe5, 0xe3, 0x7f, 0x51, 0xe9, 0x0e, 0xf8, 0x95, 0x0a, 0x3c, 0xe3, 0x32, 0xaf, 0x82, 0x63, 0x1a, - 0xdd, 0x85, 0xd7, 0x0a, 0x4e, 0xb2, 0x62, 0x2b, 0xe4, 0xfb, 0x0f, 0xb4, 0xb2, 0xfb, 0xaa, 0x89, - 0xd5, 0xd6, 0x5e, 0xd2, 0xca, 0x79, 0x04, 0xad, 0x4e, 0x12, 0xdd, 0x80, 0x66, 0x63, 0xd4, 0xf8, - 0x8d, 0x6c, 0x26, 0xdc, 0x91, 0xa4, 0x3c, 0x4d, 0xa8, 0x0e, 0x8f, 0x8d, 0x87, 0x60, 0x72, 0xaf, - 0x83, 0xb9, 0xa4, 0x09, 0xfd, 0x3b, 0xe6, 0xfc, 0xcd, 0xfe, 0xe0, 0xf6, 0xbe, 0x1e, 0xdc, 0xde, - 0xc7, 0xda, 0x05, 0xfb, 0xda, 0x05, 0x9f, 0x6b, 0x17, 0x7c, 0xaf, 0x5d, 0xf0, 0xe9, 0xa7, 0x0b, - 0xde, 0xf9, 0x17, 0x3c, 0xe5, 0x99, 0xfe, 0xac, 0xc0, 0xca, 0x08, 0x07, 0x6a, 0xff, 0x0f, 0x7e, - 0x05, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x09, 0xe0, 0xd6, 0x0b, 0x03, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/container.proto containerd-1.5.9/api/events/container.proto --- containerd-1.2.6/api/events/container.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/container.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.events; diff -Nru containerd-1.2.6/api/events/content.pb.go containerd-1.5.9/api/events/content.pb.go --- containerd-1.2.6/api/events/content.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/content.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,37 +3,94 @@ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type ContentDelete struct { - Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ContentDelete) Reset() { *m = ContentDelete{} } +func (*ContentDelete) ProtoMessage() {} +func (*ContentDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_dfb34b8b808e2ecd, []int{0} +} +func (m *ContentDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContentDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContentDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContentDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContentDelete.Merge(m, src) +} +func (m *ContentDelete) XXX_Size() int { + return m.Size() +} +func (m *ContentDelete) XXX_DiscardUnknown() { + xxx_messageInfo_ContentDelete.DiscardUnknown(m) } -func (m *ContentDelete) Reset() { *m = ContentDelete{} } -func (*ContentDelete) ProtoMessage() {} -func (*ContentDelete) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{0} } +var xxx_messageInfo_ContentDelete proto.InternalMessageInfo func init() { proto.RegisterType((*ContentDelete)(nil), "containerd.events.ContentDelete") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/content.proto", fileDescriptor_dfb34b8b808e2ecd) +} + +var fileDescriptor_dfb34b8b808e2ecd = []byte{ + // 228 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4c, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0x83, 0x45, 0x53, + 0xf3, 0x4a, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x04, 0x11, 0x8a, 0xf4, 0x20, 0x0a, 0xa4, + 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0xb2, 0xfa, 0x20, 0x16, 0x44, 0xa1, 0x94, 0x03, 0x41, 0x3b, + 0xc0, 0xea, 0x92, 0x4a, 0xd3, 0xf4, 0x0b, 0x72, 0x4a, 0xd3, 0x33, 0xf3, 0xf4, 0xd3, 0x32, 0x53, + 0x73, 0x52, 0x0a, 0x12, 0x4b, 0x32, 0x20, 0x26, 0x28, 0x45, 0x73, 0xf1, 0x3a, 0x43, 0xec, 0x76, + 0x49, 0xcd, 0x49, 0x2d, 0x49, 0x15, 0xf2, 0xe2, 0x62, 0x4b, 0xc9, 0x4c, 0x4f, 0x2d, 0x2e, 0x91, + 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x74, 0x32, 0x3a, 0x71, 0x4f, 0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0x2d, + 0x24, 0xab, 0xf2, 0x0b, 0x52, 0xf3, 0xe0, 0x76, 0x14, 0xeb, 0xa7, 0xe7, 0xeb, 0x42, 0xb4, 0xe8, + 0xb9, 0x80, 0xa9, 0x20, 0xa8, 0x09, 0x4e, 0x01, 0x27, 0x1e, 0xca, 0x31, 0xdc, 0x78, 0x28, 0xc7, + 0xd0, 0xf0, 0x48, 0x8e, 0xf1, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, + 0x63, 0x5c, 0xf0, 0x45, 0x8e, 0x31, 0xca, 0x88, 0x84, 0x00, 0xb2, 0x86, 0x50, 0x11, 0x0c, 0x11, + 0x8c, 0x49, 0x6c, 0x60, 0x97, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x78, 0x99, 0xee, + 0x61, 0x01, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *ContentDelete) Field(fieldpath []string) (string, bool) { @@ -50,7 +107,7 @@ func (m *ContentDelete) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -58,47 +115,58 @@ } func (m *ContentDelete) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContentDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Digest) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintContent(dAtA []byte, offset int, v uint64) int { + offset -= sovContent(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *ContentDelete) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Digest) if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovContent(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozContent(x uint64) (n int) { return sovContent(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -109,6 +177,7 @@ } s := strings.Join([]string{`&ContentDelete{`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -136,7 +205,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -164,7 +233,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -174,6 +243,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -185,12 +257,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -203,6 +276,7 @@ func skipContent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -234,10 +308,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -254,76 +326,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthContent } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContent - } - 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 := skipContent(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupContent + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthContent + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthContent = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowContent = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthContent = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowContent = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupContent = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/content.proto", fileDescriptorContent) -} - -var fileDescriptorContent = []byte{ - // 228 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4c, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0x83, 0x45, 0x53, - 0xf3, 0x4a, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x04, 0x11, 0x8a, 0xf4, 0x20, 0x0a, 0xa4, - 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0xb2, 0xfa, 0x20, 0x16, 0x44, 0xa1, 0x94, 0x03, 0x41, 0x3b, - 0xc0, 0xea, 0x92, 0x4a, 0xd3, 0xf4, 0x0b, 0x72, 0x4a, 0xd3, 0x33, 0xf3, 0xf4, 0xd3, 0x32, 0x53, - 0x73, 0x52, 0x0a, 0x12, 0x4b, 0x32, 0x20, 0x26, 0x28, 0x45, 0x73, 0xf1, 0x3a, 0x43, 0xec, 0x76, - 0x49, 0xcd, 0x49, 0x2d, 0x49, 0x15, 0xf2, 0xe2, 0x62, 0x4b, 0xc9, 0x4c, 0x4f, 0x2d, 0x2e, 0x91, - 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x74, 0x32, 0x3a, 0x71, 0x4f, 0x9e, 0xe1, 0xd6, 0x3d, 0x79, 0x2d, - 0x24, 0xab, 0xf2, 0x0b, 0x52, 0xf3, 0xe0, 0x76, 0x14, 0xeb, 0xa7, 0xe7, 0xeb, 0x42, 0xb4, 0xe8, - 0xb9, 0x80, 0xa9, 0x20, 0xa8, 0x09, 0x4e, 0x01, 0x27, 0x1e, 0xca, 0x31, 0xdc, 0x78, 0x28, 0xc7, - 0xd0, 0xf0, 0x48, 0x8e, 0xf1, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, - 0x63, 0x5c, 0xf0, 0x45, 0x8e, 0x31, 0xca, 0x88, 0x84, 0x00, 0xb2, 0x86, 0x50, 0x11, 0x0c, 0x11, - 0x8c, 0x49, 0x6c, 0x60, 0x97, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x78, 0x99, 0xee, - 0x61, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/content.proto containerd-1.5.9/api/events/content.proto --- containerd-1.2.6/api/events/content.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/content.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.events; diff -Nru containerd-1.2.6/api/events/image.pb.go containerd-1.5.9/api/events/image.pb.go --- containerd-1.2.6/api/events/image.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/image.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,55 +3,182 @@ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type ImageCreate struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ImageCreate) Reset() { *m = ImageCreate{} } -func (*ImageCreate) ProtoMessage() {} -func (*ImageCreate) Descriptor() ([]byte, []int) { return fileDescriptorImage, []int{0} } +func (m *ImageCreate) Reset() { *m = ImageCreate{} } +func (*ImageCreate) ProtoMessage() {} +func (*ImageCreate) Descriptor() ([]byte, []int) { + return fileDescriptor_7085610f7b33e042, []int{0} +} +func (m *ImageCreate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ImageCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ImageCreate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ImageCreate) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImageCreate.Merge(m, src) +} +func (m *ImageCreate) XXX_Size() int { + return m.Size() +} +func (m *ImageCreate) XXX_DiscardUnknown() { + xxx_messageInfo_ImageCreate.DiscardUnknown(m) +} + +var xxx_messageInfo_ImageCreate proto.InternalMessageInfo type ImageUpdate struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ImageUpdate) Reset() { *m = ImageUpdate{} } +func (*ImageUpdate) ProtoMessage() {} +func (*ImageUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_7085610f7b33e042, []int{1} +} +func (m *ImageUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ImageUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ImageUpdate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ImageUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImageUpdate.Merge(m, src) +} +func (m *ImageUpdate) XXX_Size() int { + return m.Size() +} +func (m *ImageUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_ImageUpdate.DiscardUnknown(m) } -func (m *ImageUpdate) Reset() { *m = ImageUpdate{} } -func (*ImageUpdate) ProtoMessage() {} -func (*ImageUpdate) Descriptor() ([]byte, []int) { return fileDescriptorImage, []int{1} } +var xxx_messageInfo_ImageUpdate proto.InternalMessageInfo type ImageDelete struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ImageDelete) Reset() { *m = ImageDelete{} } -func (*ImageDelete) ProtoMessage() {} -func (*ImageDelete) Descriptor() ([]byte, []int) { return fileDescriptorImage, []int{2} } +func (m *ImageDelete) Reset() { *m = ImageDelete{} } +func (*ImageDelete) ProtoMessage() {} +func (*ImageDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_7085610f7b33e042, []int{2} +} +func (m *ImageDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ImageDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ImageDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ImageDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_ImageDelete.Merge(m, src) +} +func (m *ImageDelete) XXX_Size() int { + return m.Size() +} +func (m *ImageDelete) XXX_DiscardUnknown() { + xxx_messageInfo_ImageDelete.DiscardUnknown(m) +} + +var xxx_messageInfo_ImageDelete proto.InternalMessageInfo func init() { proto.RegisterType((*ImageCreate)(nil), "containerd.services.images.v1.ImageCreate") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.images.v1.ImageCreate.LabelsEntry") proto.RegisterType((*ImageUpdate)(nil), "containerd.services.images.v1.ImageUpdate") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.images.v1.ImageUpdate.LabelsEntry") proto.RegisterType((*ImageDelete)(nil), "containerd.services.images.v1.ImageDelete") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/image.proto", fileDescriptor_7085610f7b33e042) +} + +var fileDescriptor_7085610f7b33e042 = []byte{ + // 292 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4f, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0x67, 0xe6, + 0x26, 0xa6, 0xa7, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0xc9, 0x22, 0x94, 0xe8, 0x15, 0xa7, + 0x16, 0x95, 0x65, 0x26, 0xa7, 0x16, 0xeb, 0x81, 0x15, 0x14, 0xeb, 0x95, 0x19, 0x4a, 0x39, 0x10, + 0x34, 0x17, 0x6c, 0x4c, 0x52, 0x69, 0x9a, 0x7e, 0x41, 0x4e, 0x69, 0x7a, 0x66, 0x9e, 0x7e, 0x5a, + 0x66, 0x6a, 0x4e, 0x4a, 0x41, 0x62, 0x49, 0x06, 0xc4, 0x02, 0xa5, 0x35, 0x8c, 0x5c, 0xdc, 0x9e, + 0x20, 0xf3, 0x9c, 0x8b, 0x52, 0x13, 0x4b, 0x52, 0x85, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, + 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x21, 0x3f, 0x2e, 0xb6, 0x9c, 0xc4, 0xa4, + 0xd4, 0x9c, 0x62, 0x09, 0x26, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x33, 0x3d, 0xbc, 0xae, 0xd2, 0x43, + 0x32, 0x4f, 0xcf, 0x07, 0xac, 0xd1, 0x35, 0xaf, 0xa4, 0xa8, 0x32, 0x08, 0x6a, 0x8a, 0x94, 0x25, + 0x17, 0x37, 0x92, 0xb0, 0x90, 0x00, 0x17, 0x73, 0x76, 0x6a, 0x25, 0xd4, 0x46, 0x10, 0x53, 0x48, + 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x09, 0x2c, 0x06, 0xe1, 0x58, 0x31, 0x59, + 0x30, 0x22, 0x9c, 0x1b, 0x5a, 0x90, 0x42, 0x55, 0xe7, 0x42, 0xcc, 0xa3, 0xb6, 0x73, 0x15, 0xa1, + 0xae, 0x75, 0x49, 0xcd, 0x49, 0xc5, 0xee, 0x5a, 0xa7, 0x80, 0x13, 0x0f, 0xe5, 0x18, 0x6e, 0x3c, + 0x94, 0x63, 0x68, 0x78, 0x24, 0xc7, 0x78, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, + 0x1e, 0xc9, 0x31, 0x2e, 0xf8, 0x22, 0xc7, 0x18, 0x65, 0x44, 0x42, 0xc2, 0xb1, 0x86, 0x50, 0x11, + 0x0c, 0x49, 0x6c, 0xe0, 0xb8, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x41, 0x80, 0x92, 0x17, + 0x77, 0x02, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *ImageCreate) Field(fieldpath []string) (string, bool) { @@ -112,7 +239,7 @@ func (m *ImageCreate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -120,40 +247,52 @@ } func (m *ImageCreate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ImageCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintImage(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovImage(uint64(len(k))) + 1 + len(v) + sovImage(uint64(len(v))) - i = encodeVarintImage(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintImage(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintImage(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintImage(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintImage(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintImage(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ImageUpdate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -161,40 +300,52 @@ } func (m *ImageUpdate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ImageUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintImage(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovImage(uint64(len(k))) + 1 + len(v) + sovImage(uint64(len(v))) - i = encodeVarintImage(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintImage(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintImage(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintImage(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintImage(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintImage(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ImageDelete) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -202,29 +353,44 @@ } func (m *ImageDelete) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ImageDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintImage(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintImage(dAtA []byte, offset int, v uint64) int { + offset -= sovImage(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *ImageCreate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -239,10 +405,16 @@ n += mapEntrySize + 1 + sovImage(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ImageUpdate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -257,28 +429,30 @@ n += mapEntrySize + 1 + sovImage(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ImageDelete) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovImage(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovImage(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozImage(x uint64) (n int) { return sovImage(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -291,7 +465,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -300,6 +474,7 @@ s := strings.Join([]string{`&ImageCreate{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -312,7 +487,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -321,6 +496,7 @@ s := strings.Join([]string{`&ImageUpdate{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -331,6 +507,7 @@ } s := strings.Join([]string{`&ImageDelete{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -358,7 +535,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -386,7 +563,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -396,6 +573,9 @@ return ErrInvalidLengthImage } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImage + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -415,7 +595,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -424,6 +604,9 @@ return ErrInvalidLengthImage } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImage + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -444,7 +627,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -461,7 +644,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -471,6 +654,9 @@ return ErrInvalidLengthImage } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthImage + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -487,7 +673,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -497,6 +683,9 @@ return ErrInvalidLengthImage } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthImage + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -508,7 +697,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImage } if (iNdEx + skippy) > postIndex { @@ -525,12 +714,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImage } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -555,7 +745,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -583,7 +773,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -593,6 +783,9 @@ return ErrInvalidLengthImage } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImage + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -612,7 +805,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -621,6 +814,9 @@ return ErrInvalidLengthImage } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImage + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -641,7 +837,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -658,7 +854,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -668,6 +864,9 @@ return ErrInvalidLengthImage } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthImage + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -684,7 +883,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -694,6 +893,9 @@ return ErrInvalidLengthImage } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthImage + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -705,7 +907,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImage } if (iNdEx + skippy) > postIndex { @@ -722,12 +924,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImage } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -752,7 +955,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -780,7 +983,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -790,6 +993,9 @@ return ErrInvalidLengthImage } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImage + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -801,12 +1007,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImage } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -819,6 +1026,7 @@ func skipImage(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -850,10 +1058,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -870,80 +1076,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthImage } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowImage - } - 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 := skipImage(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupImage + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthImage + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthImage = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowImage = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthImage = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowImage = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupImage = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/image.proto", fileDescriptorImage) -} - -var fileDescriptorImage = []byte{ - // 292 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4f, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0x67, 0xe6, - 0x26, 0xa6, 0xa7, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0xc9, 0x22, 0x94, 0xe8, 0x15, 0xa7, - 0x16, 0x95, 0x65, 0x26, 0xa7, 0x16, 0xeb, 0x81, 0x15, 0x14, 0xeb, 0x95, 0x19, 0x4a, 0x39, 0x10, - 0x34, 0x17, 0x6c, 0x4c, 0x52, 0x69, 0x9a, 0x7e, 0x41, 0x4e, 0x69, 0x7a, 0x66, 0x9e, 0x7e, 0x5a, - 0x66, 0x6a, 0x4e, 0x4a, 0x41, 0x62, 0x49, 0x06, 0xc4, 0x02, 0xa5, 0x35, 0x8c, 0x5c, 0xdc, 0x9e, - 0x20, 0xf3, 0x9c, 0x8b, 0x52, 0x13, 0x4b, 0x52, 0x85, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, - 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x21, 0x3f, 0x2e, 0xb6, 0x9c, 0xc4, 0xa4, - 0xd4, 0x9c, 0x62, 0x09, 0x26, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x33, 0x3d, 0xbc, 0xae, 0xd2, 0x43, - 0x32, 0x4f, 0xcf, 0x07, 0xac, 0xd1, 0x35, 0xaf, 0xa4, 0xa8, 0x32, 0x08, 0x6a, 0x8a, 0x94, 0x25, - 0x17, 0x37, 0x92, 0xb0, 0x90, 0x00, 0x17, 0x73, 0x76, 0x6a, 0x25, 0xd4, 0x46, 0x10, 0x53, 0x48, - 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x82, 0x09, 0x2c, 0x06, 0xe1, 0x58, 0x31, 0x59, - 0x30, 0x22, 0x9c, 0x1b, 0x5a, 0x90, 0x42, 0x55, 0xe7, 0x42, 0xcc, 0xa3, 0xb6, 0x73, 0x15, 0xa1, - 0xae, 0x75, 0x49, 0xcd, 0x49, 0xc5, 0xee, 0x5a, 0xa7, 0x80, 0x13, 0x0f, 0xe5, 0x18, 0x6e, 0x3c, - 0x94, 0x63, 0x68, 0x78, 0x24, 0xc7, 0x78, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, - 0x1e, 0xc9, 0x31, 0x2e, 0xf8, 0x22, 0xc7, 0x18, 0x65, 0x44, 0x42, 0xc2, 0xb1, 0x86, 0x50, 0x11, - 0x0c, 0x49, 0x6c, 0xe0, 0xb8, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x41, 0x80, 0x92, 0x17, - 0x77, 0x02, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/image.proto containerd-1.5.9/api/events/image.proto --- containerd-1.2.6/api/events/image.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/image.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.images.v1; diff -Nru containerd-1.2.6/api/events/namespace.pb.go containerd-1.5.9/api/events/namespace.pb.go --- containerd-1.2.6/api/events/namespace.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/namespace.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,56 +3,182 @@ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type NamespaceCreate struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NamespaceCreate) Reset() { *m = NamespaceCreate{} } +func (*NamespaceCreate) ProtoMessage() {} +func (*NamespaceCreate) Descriptor() ([]byte, []int) { + return fileDescriptor_6cd45d1d5adffe29, []int{0} +} +func (m *NamespaceCreate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NamespaceCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NamespaceCreate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NamespaceCreate) XXX_Merge(src proto.Message) { + xxx_messageInfo_NamespaceCreate.Merge(m, src) +} +func (m *NamespaceCreate) XXX_Size() int { + return m.Size() +} +func (m *NamespaceCreate) XXX_DiscardUnknown() { + xxx_messageInfo_NamespaceCreate.DiscardUnknown(m) } -func (m *NamespaceCreate) Reset() { *m = NamespaceCreate{} } -func (*NamespaceCreate) ProtoMessage() {} -func (*NamespaceCreate) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{0} } +var xxx_messageInfo_NamespaceCreate proto.InternalMessageInfo type NamespaceUpdate struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *NamespaceUpdate) Reset() { *m = NamespaceUpdate{} } -func (*NamespaceUpdate) ProtoMessage() {} -func (*NamespaceUpdate) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{1} } +func (m *NamespaceUpdate) Reset() { *m = NamespaceUpdate{} } +func (*NamespaceUpdate) ProtoMessage() {} +func (*NamespaceUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_6cd45d1d5adffe29, []int{1} +} +func (m *NamespaceUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NamespaceUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NamespaceUpdate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NamespaceUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_NamespaceUpdate.Merge(m, src) +} +func (m *NamespaceUpdate) XXX_Size() int { + return m.Size() +} +func (m *NamespaceUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_NamespaceUpdate.DiscardUnknown(m) +} + +var xxx_messageInfo_NamespaceUpdate proto.InternalMessageInfo type NamespaceDelete struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NamespaceDelete) Reset() { *m = NamespaceDelete{} } +func (*NamespaceDelete) ProtoMessage() {} +func (*NamespaceDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_6cd45d1d5adffe29, []int{2} +} +func (m *NamespaceDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NamespaceDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NamespaceDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NamespaceDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_NamespaceDelete.Merge(m, src) +} +func (m *NamespaceDelete) XXX_Size() int { + return m.Size() +} +func (m *NamespaceDelete) XXX_DiscardUnknown() { + xxx_messageInfo_NamespaceDelete.DiscardUnknown(m) } -func (m *NamespaceDelete) Reset() { *m = NamespaceDelete{} } -func (*NamespaceDelete) ProtoMessage() {} -func (*NamespaceDelete) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{2} } +var xxx_messageInfo_NamespaceDelete proto.InternalMessageInfo func init() { proto.RegisterType((*NamespaceCreate)(nil), "containerd.events.NamespaceCreate") + proto.RegisterMapType((map[string]string)(nil), "containerd.events.NamespaceCreate.LabelsEntry") proto.RegisterType((*NamespaceUpdate)(nil), "containerd.events.NamespaceUpdate") + proto.RegisterMapType((map[string]string)(nil), "containerd.events.NamespaceUpdate.LabelsEntry") proto.RegisterType((*NamespaceDelete)(nil), "containerd.events.NamespaceDelete") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/namespace.proto", fileDescriptor_6cd45d1d5adffe29) +} + +var fileDescriptor_6cd45d1d5adffe29 = []byte{ + // 296 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4e, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0xe7, 0x25, + 0xe6, 0xa6, 0x16, 0x17, 0x24, 0x26, 0xa7, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x22, + 0x94, 0xe9, 0x41, 0x94, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x65, 0xf5, 0x41, 0x2c, 0x88, + 0x42, 0x29, 0x07, 0x82, 0xb6, 0x80, 0xd5, 0x25, 0x95, 0xa6, 0xe9, 0x17, 0xe4, 0x94, 0xa6, 0x67, + 0xe6, 0xe9, 0xa7, 0x65, 0xa6, 0xe6, 0xa4, 0x14, 0x24, 0x96, 0x64, 0x40, 0x4c, 0x50, 0x5a, 0xc1, + 0xc8, 0xc5, 0xef, 0x07, 0xb3, 0xde, 0xb9, 0x28, 0x35, 0xb1, 0x24, 0x55, 0x48, 0x88, 0x8b, 0x05, + 0xe4, 0x22, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0xc8, 0x8d, 0x8b, 0x2d, 0x27, + 0x31, 0x29, 0x35, 0xa7, 0x58, 0x82, 0x49, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x4f, 0x0f, 0xc3, 0x8d, + 0x7a, 0x68, 0xe6, 0xe8, 0xf9, 0x80, 0x35, 0xb8, 0xe6, 0x95, 0x14, 0x55, 0x06, 0x41, 0x75, 0x4b, + 0x59, 0x72, 0x71, 0x23, 0x09, 0x0b, 0x09, 0x70, 0x31, 0x67, 0xa7, 0x56, 0x42, 0x6d, 0x02, 0x31, + 0x85, 0x44, 0xb8, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53, 0x25, 0x98, 0xc0, 0x62, 0x10, 0x8e, 0x15, + 0x93, 0x05, 0x23, 0xaa, 0x53, 0x43, 0x0b, 0x52, 0xa8, 0xe2, 0x54, 0x88, 0x39, 0xd4, 0x76, 0xaa, + 0x2a, 0x92, 0x4b, 0x5d, 0x52, 0x73, 0x52, 0xb1, 0xbb, 0xd4, 0x29, 0xe0, 0xc4, 0x43, 0x39, 0x86, + 0x1b, 0x0f, 0xe5, 0x18, 0x1a, 0x1e, 0xc9, 0x31, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, + 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x0b, 0xbe, 0xc8, 0x31, 0x46, 0x19, 0x91, 0x90, 0x84, 0xac, 0x21, + 0x54, 0x04, 0x43, 0x04, 0x63, 0x12, 0x1b, 0x38, 0x66, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x50, 0x87, 0x59, 0x83, 0x02, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *NamespaceCreate) Field(fieldpath []string) (string, bool) { @@ -113,7 +239,7 @@ func (m *NamespaceCreate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -121,40 +247,52 @@ } func (m *NamespaceCreate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NamespaceCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovNamespace(uint64(len(k))) + 1 + len(v) + sovNamespace(uint64(len(v))) - i = encodeVarintNamespace(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintNamespace(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintNamespace(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintNamespace(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *NamespaceUpdate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -162,40 +300,52 @@ } func (m *NamespaceUpdate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NamespaceUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovNamespace(uint64(len(k))) + 1 + len(v) + sovNamespace(uint64(len(v))) - i = encodeVarintNamespace(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintNamespace(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintNamespace(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintNamespace(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *NamespaceDelete) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -203,29 +353,44 @@ } func (m *NamespaceDelete) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NamespaceDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintNamespace(dAtA []byte, offset int, v uint64) int { + offset -= sovNamespace(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *NamespaceCreate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -240,10 +405,16 @@ n += mapEntrySize + 1 + sovNamespace(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *NamespaceUpdate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -258,28 +429,30 @@ n += mapEntrySize + 1 + sovNamespace(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *NamespaceDelete) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovNamespace(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovNamespace(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozNamespace(x uint64) (n int) { return sovNamespace(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -292,7 +465,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -301,6 +474,7 @@ s := strings.Join([]string{`&NamespaceCreate{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -313,7 +487,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -322,6 +496,7 @@ s := strings.Join([]string{`&NamespaceUpdate{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -332,6 +507,7 @@ } s := strings.Join([]string{`&NamespaceDelete{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -359,7 +535,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -387,7 +563,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -397,6 +573,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -416,7 +595,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -425,6 +604,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -445,7 +627,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -462,7 +644,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -472,6 +654,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -488,7 +673,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -498,6 +683,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -509,7 +697,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > postIndex { @@ -526,12 +714,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -556,7 +745,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -584,7 +773,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -594,6 +783,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -613,7 +805,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -622,6 +814,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -642,7 +837,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -659,7 +854,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -669,6 +864,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -685,7 +883,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -695,6 +893,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -706,7 +907,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > postIndex { @@ -723,12 +924,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -753,7 +955,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -781,7 +983,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -791,6 +993,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -802,12 +1007,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -820,6 +1026,7 @@ func skipNamespace(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -851,10 +1058,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -871,80 +1076,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthNamespace } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowNamespace - } - 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 := skipNamespace(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupNamespace + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthNamespace + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthNamespace = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowNamespace = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthNamespace = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowNamespace = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupNamespace = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/namespace.proto", fileDescriptorNamespace) -} - -var fileDescriptorNamespace = []byte{ - // 296 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4e, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0xe7, 0x25, - 0xe6, 0xa6, 0x16, 0x17, 0x24, 0x26, 0xa7, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x22, - 0x94, 0xe9, 0x41, 0x94, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x65, 0xf5, 0x41, 0x2c, 0x88, - 0x42, 0x29, 0x07, 0x82, 0xb6, 0x80, 0xd5, 0x25, 0x95, 0xa6, 0xe9, 0x17, 0xe4, 0x94, 0xa6, 0x67, - 0xe6, 0xe9, 0xa7, 0x65, 0xa6, 0xe6, 0xa4, 0x14, 0x24, 0x96, 0x64, 0x40, 0x4c, 0x50, 0x5a, 0xc1, - 0xc8, 0xc5, 0xef, 0x07, 0xb3, 0xde, 0xb9, 0x28, 0x35, 0xb1, 0x24, 0x55, 0x48, 0x88, 0x8b, 0x05, - 0xe4, 0x22, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0xc8, 0x8d, 0x8b, 0x2d, 0x27, - 0x31, 0x29, 0x35, 0xa7, 0x58, 0x82, 0x49, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x4f, 0x0f, 0xc3, 0x8d, - 0x7a, 0x68, 0xe6, 0xe8, 0xf9, 0x80, 0x35, 0xb8, 0xe6, 0x95, 0x14, 0x55, 0x06, 0x41, 0x75, 0x4b, - 0x59, 0x72, 0x71, 0x23, 0x09, 0x0b, 0x09, 0x70, 0x31, 0x67, 0xa7, 0x56, 0x42, 0x6d, 0x02, 0x31, - 0x85, 0x44, 0xb8, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53, 0x25, 0x98, 0xc0, 0x62, 0x10, 0x8e, 0x15, - 0x93, 0x05, 0x23, 0xaa, 0x53, 0x43, 0x0b, 0x52, 0xa8, 0xe2, 0x54, 0x88, 0x39, 0xd4, 0x76, 0xaa, - 0x2a, 0x92, 0x4b, 0x5d, 0x52, 0x73, 0x52, 0xb1, 0xbb, 0xd4, 0x29, 0xe0, 0xc4, 0x43, 0x39, 0x86, - 0x1b, 0x0f, 0xe5, 0x18, 0x1a, 0x1e, 0xc9, 0x31, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, - 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x0b, 0xbe, 0xc8, 0x31, 0x46, 0x19, 0x91, 0x90, 0x84, 0xac, 0x21, - 0x54, 0x04, 0x43, 0x04, 0x63, 0x12, 0x1b, 0x38, 0x66, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x50, 0x87, 0x59, 0x83, 0x02, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/namespace.proto containerd-1.5.9/api/events/namespace.proto --- containerd-1.2.6/api/events/namespace.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/namespace.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.events; diff -Nru containerd-1.2.6/api/events/snapshot.pb.go containerd-1.5.9/api/events/snapshot.pb.go --- containerd-1.2.6/api/events/snapshot.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/snapshot.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,47 +3,145 @@ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type SnapshotPrepare struct { - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SnapshotPrepare) Reset() { *m = SnapshotPrepare{} } +func (*SnapshotPrepare) ProtoMessage() {} +func (*SnapshotPrepare) Descriptor() ([]byte, []int) { + return fileDescriptor_bd6c184d3d9aa5f2, []int{0} +} +func (m *SnapshotPrepare) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SnapshotPrepare) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SnapshotPrepare.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SnapshotPrepare) XXX_Merge(src proto.Message) { + xxx_messageInfo_SnapshotPrepare.Merge(m, src) +} +func (m *SnapshotPrepare) XXX_Size() int { + return m.Size() +} +func (m *SnapshotPrepare) XXX_DiscardUnknown() { + xxx_messageInfo_SnapshotPrepare.DiscardUnknown(m) } -func (m *SnapshotPrepare) Reset() { *m = SnapshotPrepare{} } -func (*SnapshotPrepare) ProtoMessage() {} -func (*SnapshotPrepare) Descriptor() ([]byte, []int) { return fileDescriptorSnapshot, []int{0} } +var xxx_messageInfo_SnapshotPrepare proto.InternalMessageInfo type SnapshotCommit struct { - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SnapshotCommit) Reset() { *m = SnapshotCommit{} } +func (*SnapshotCommit) ProtoMessage() {} +func (*SnapshotCommit) Descriptor() ([]byte, []int) { + return fileDescriptor_bd6c184d3d9aa5f2, []int{1} +} +func (m *SnapshotCommit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SnapshotCommit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SnapshotCommit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SnapshotCommit) XXX_Merge(src proto.Message) { + xxx_messageInfo_SnapshotCommit.Merge(m, src) +} +func (m *SnapshotCommit) XXX_Size() int { + return m.Size() +} +func (m *SnapshotCommit) XXX_DiscardUnknown() { + xxx_messageInfo_SnapshotCommit.DiscardUnknown(m) } -func (m *SnapshotCommit) Reset() { *m = SnapshotCommit{} } -func (*SnapshotCommit) ProtoMessage() {} -func (*SnapshotCommit) Descriptor() ([]byte, []int) { return fileDescriptorSnapshot, []int{1} } +var xxx_messageInfo_SnapshotCommit proto.InternalMessageInfo type SnapshotRemove struct { - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SnapshotRemove) Reset() { *m = SnapshotRemove{} } +func (*SnapshotRemove) ProtoMessage() {} +func (*SnapshotRemove) Descriptor() ([]byte, []int) { + return fileDescriptor_bd6c184d3d9aa5f2, []int{2} +} +func (m *SnapshotRemove) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SnapshotRemove) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SnapshotRemove.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SnapshotRemove) XXX_Merge(src proto.Message) { + xxx_messageInfo_SnapshotRemove.Merge(m, src) +} +func (m *SnapshotRemove) XXX_Size() int { + return m.Size() +} +func (m *SnapshotRemove) XXX_DiscardUnknown() { + xxx_messageInfo_SnapshotRemove.DiscardUnknown(m) } -func (m *SnapshotRemove) Reset() { *m = SnapshotRemove{} } -func (*SnapshotRemove) ProtoMessage() {} -func (*SnapshotRemove) Descriptor() ([]byte, []int) { return fileDescriptorSnapshot, []int{2} } +var xxx_messageInfo_SnapshotRemove proto.InternalMessageInfo func init() { proto.RegisterType((*SnapshotPrepare)(nil), "containerd.events.SnapshotPrepare") @@ -51,6 +149,29 @@ proto.RegisterType((*SnapshotRemove)(nil), "containerd.events.SnapshotRemove") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/snapshot.proto", fileDescriptor_bd6c184d3d9aa5f2) +} + +var fileDescriptor_bd6c184d3d9aa5f2 = []byte{ + // 235 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4a, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0x17, 0xe7, + 0x25, 0x16, 0x14, 0x67, 0xe4, 0x97, 0xe8, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x22, 0x54, + 0xe9, 0x41, 0x54, 0x48, 0x39, 0x10, 0x34, 0x0e, 0xac, 0x35, 0xa9, 0x34, 0x4d, 0xbf, 0x20, 0xa7, + 0x34, 0x3d, 0x33, 0x4f, 0x3f, 0x2d, 0x33, 0x35, 0x27, 0xa5, 0x20, 0xb1, 0x24, 0x03, 0x62, 0xa8, + 0x92, 0x35, 0x17, 0x7f, 0x30, 0xd4, 0x9a, 0x80, 0xa2, 0xd4, 0x82, 0xc4, 0xa2, 0x54, 0x21, 0x01, + 0x2e, 0xe6, 0xec, 0xd4, 0x4a, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x10, 0x53, 0x48, 0x8c, + 0x8b, 0x0d, 0x24, 0x93, 0x57, 0x22, 0xc1, 0x04, 0x16, 0x84, 0xf2, 0x94, 0xcc, 0xb8, 0xf8, 0x60, + 0x9a, 0x9d, 0xf3, 0x73, 0x73, 0x33, 0x4b, 0xb0, 0xe8, 0x15, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, + 0x85, 0xea, 0x04, 0xb3, 0x95, 0x94, 0x10, 0xfa, 0x82, 0x52, 0x73, 0xf3, 0xcb, 0xb0, 0xd8, 0xe9, + 0x14, 0x70, 0xe2, 0xa1, 0x1c, 0xc3, 0x8d, 0x87, 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, + 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x05, 0x5f, 0xe4, 0x18, 0xa3, + 0x8c, 0x48, 0x08, 0x47, 0x6b, 0x08, 0x15, 0xc1, 0x90, 0xc4, 0x06, 0xf6, 0xb3, 0x31, 0x20, 0x00, + 0x00, 0xff, 0xff, 0x69, 0x66, 0xa9, 0x2a, 0x86, 0x01, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *SnapshotPrepare) Field(fieldpath []string) (string, bool) { @@ -99,7 +220,7 @@ func (m *SnapshotPrepare) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -107,29 +228,40 @@ } func (m *SnapshotPrepare) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SnapshotPrepare) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Key) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Parent) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Parent) + copy(dAtA[i:], m.Parent) i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *SnapshotCommit) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -137,29 +269,40 @@ } func (m *SnapshotCommit) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SnapshotCommit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Key) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Name) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *SnapshotRemove) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -167,29 +310,44 @@ } func (m *SnapshotRemove) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SnapshotRemove) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Key) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Key) + copy(dAtA[i:], m.Key) i = encodeVarintSnapshot(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintSnapshot(dAtA []byte, offset int, v uint64) int { + offset -= sovSnapshot(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *SnapshotPrepare) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Key) @@ -200,10 +358,16 @@ if l > 0 { n += 1 + l + sovSnapshot(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *SnapshotCommit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Key) @@ -214,28 +378,30 @@ if l > 0 { n += 1 + l + sovSnapshot(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *SnapshotRemove) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Key) if l > 0 { n += 1 + l + sovSnapshot(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovSnapshot(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozSnapshot(x uint64) (n int) { return sovSnapshot(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -247,6 +413,7 @@ s := strings.Join([]string{`&SnapshotPrepare{`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -258,6 +425,7 @@ s := strings.Join([]string{`&SnapshotCommit{`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -268,6 +436,7 @@ } s := strings.Join([]string{`&SnapshotRemove{`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -295,7 +464,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -323,7 +492,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -333,6 +502,9 @@ return ErrInvalidLengthSnapshot } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshot + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -352,7 +524,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -362,6 +534,9 @@ return ErrInvalidLengthSnapshot } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshot + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -373,12 +548,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshot } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -403,7 +579,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -431,7 +607,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -441,6 +617,9 @@ return ErrInvalidLengthSnapshot } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshot + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -460,7 +639,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -470,6 +649,9 @@ return ErrInvalidLengthSnapshot } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshot + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -481,12 +663,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshot } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -511,7 +694,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -539,7 +722,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -549,6 +732,9 @@ return ErrInvalidLengthSnapshot } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshot + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -560,12 +746,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshot } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -578,6 +765,7 @@ func skipSnapshot(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -609,10 +797,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -629,76 +815,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthSnapshot } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSnapshot - } - 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 := skipSnapshot(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSnapshot + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthSnapshot + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthSnapshot = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowSnapshot = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthSnapshot = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSnapshot = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSnapshot = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/snapshot.proto", fileDescriptorSnapshot) -} - -var fileDescriptorSnapshot = []byte{ - // 235 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4a, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0xa7, 0x96, 0xa5, 0xe6, 0x95, 0x14, 0xeb, 0x17, 0xe7, - 0x25, 0x16, 0x14, 0x67, 0xe4, 0x97, 0xe8, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x22, 0x54, - 0xe9, 0x41, 0x54, 0x48, 0x39, 0x10, 0x34, 0x0e, 0xac, 0x35, 0xa9, 0x34, 0x4d, 0xbf, 0x20, 0xa7, - 0x34, 0x3d, 0x33, 0x4f, 0x3f, 0x2d, 0x33, 0x35, 0x27, 0xa5, 0x20, 0xb1, 0x24, 0x03, 0x62, 0xa8, - 0x92, 0x35, 0x17, 0x7f, 0x30, 0xd4, 0x9a, 0x80, 0xa2, 0xd4, 0x82, 0xc4, 0xa2, 0x54, 0x21, 0x01, - 0x2e, 0xe6, 0xec, 0xd4, 0x4a, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x10, 0x53, 0x48, 0x8c, - 0x8b, 0x0d, 0x24, 0x93, 0x57, 0x22, 0xc1, 0x04, 0x16, 0x84, 0xf2, 0x94, 0xcc, 0xb8, 0xf8, 0x60, - 0x9a, 0x9d, 0xf3, 0x73, 0x73, 0x33, 0x4b, 0xb0, 0xe8, 0x15, 0xe2, 0x62, 0xc9, 0x4b, 0xcc, 0x4d, - 0x85, 0xea, 0x04, 0xb3, 0x95, 0x94, 0x10, 0xfa, 0x82, 0x52, 0x73, 0xf3, 0xcb, 0xb0, 0xd8, 0xe9, - 0x14, 0x70, 0xe2, 0xa1, 0x1c, 0xc3, 0x8d, 0x87, 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, - 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x05, 0x5f, 0xe4, 0x18, 0xa3, - 0x8c, 0x48, 0x08, 0x47, 0x6b, 0x08, 0x15, 0xc1, 0x90, 0xc4, 0x06, 0xf6, 0xb3, 0x31, 0x20, 0x00, - 0x00, 0xff, 0xff, 0x69, 0x66, 0xa9, 0x2a, 0x86, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/snapshot.proto containerd-1.5.9/api/events/snapshot.proto --- containerd-1.2.6/api/events/snapshot.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/snapshot.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.events; diff -Nru containerd-1.2.6/api/events/task.pb.go containerd-1.5.9/api/events/task.pb.go --- containerd-1.2.6/api/events/task.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/task.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,24 +3,19 @@ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import _ "github.com/gogo/protobuf/types" -import containerd_types "github.com/containerd/containerd/api/types" - -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" - -import time "time" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + types "github.com/containerd/containerd/api/types" + proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -28,113 +23,463 @@ var _ = math.Inf var _ = time.Kitchen +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type TaskCreate struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` - Rootfs []*containerd_types.Mount `protobuf:"bytes,3,rep,name=rootfs" json:"rootfs,omitempty"` - IO *TaskIO `protobuf:"bytes,4,opt,name=io" json:"io,omitempty"` - Checkpoint string `protobuf:"bytes,5,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` - Pid uint32 `protobuf:"varint,6,opt,name=pid,proto3" json:"pid,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Rootfs []*types.Mount `protobuf:"bytes,3,rep,name=rootfs,proto3" json:"rootfs,omitempty"` + IO *TaskIO `protobuf:"bytes,4,opt,name=io,proto3" json:"io,omitempty"` + Checkpoint string `protobuf:"bytes,5,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + Pid uint32 `protobuf:"varint,6,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskCreate) Reset() { *m = TaskCreate{} } +func (*TaskCreate) ProtoMessage() {} +func (*TaskCreate) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{0} +} +func (m *TaskCreate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskCreate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskCreate) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskCreate.Merge(m, src) +} +func (m *TaskCreate) XXX_Size() int { + return m.Size() +} +func (m *TaskCreate) XXX_DiscardUnknown() { + xxx_messageInfo_TaskCreate.DiscardUnknown(m) } -func (m *TaskCreate) Reset() { *m = TaskCreate{} } -func (*TaskCreate) ProtoMessage() {} -func (*TaskCreate) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{0} } +var xxx_messageInfo_TaskCreate proto.InternalMessageInfo type TaskStart struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskStart) Reset() { *m = TaskStart{} } +func (*TaskStart) ProtoMessage() {} +func (*TaskStart) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{1} +} +func (m *TaskStart) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskStart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskStart.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskStart) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskStart.Merge(m, src) +} +func (m *TaskStart) XXX_Size() int { + return m.Size() +} +func (m *TaskStart) XXX_DiscardUnknown() { + xxx_messageInfo_TaskStart.DiscardUnknown(m) } -func (m *TaskStart) Reset() { *m = TaskStart{} } -func (*TaskStart) ProtoMessage() {} -func (*TaskStart) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{1} } +var xxx_messageInfo_TaskStart proto.InternalMessageInfo type TaskDelete struct { ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` ExitStatus uint32 `protobuf:"varint,3,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,4,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ExitedAt time.Time `protobuf:"bytes,4,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + // id is the specific exec. By default if omitted will be `""` thus matches + // the init exec of the task matching `container_id`. + ID string `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskDelete) Reset() { *m = TaskDelete{} } +func (*TaskDelete) ProtoMessage() {} +func (*TaskDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{2} +} +func (m *TaskDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskDelete.Merge(m, src) +} +func (m *TaskDelete) XXX_Size() int { + return m.Size() +} +func (m *TaskDelete) XXX_DiscardUnknown() { + xxx_messageInfo_TaskDelete.DiscardUnknown(m) } -func (m *TaskDelete) Reset() { *m = TaskDelete{} } -func (*TaskDelete) ProtoMessage() {} -func (*TaskDelete) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{2} } +var xxx_messageInfo_TaskDelete proto.InternalMessageInfo type TaskIO struct { - Stdin string `protobuf:"bytes,1,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,2,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,3,opt,name=stderr,proto3" json:"stderr,omitempty"` - Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,1,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,2,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,3,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskIO) Reset() { *m = TaskIO{} } +func (*TaskIO) ProtoMessage() {} +func (*TaskIO) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{3} +} +func (m *TaskIO) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskIO) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskIO.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskIO) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskIO.Merge(m, src) +} +func (m *TaskIO) XXX_Size() int { + return m.Size() +} +func (m *TaskIO) XXX_DiscardUnknown() { + xxx_messageInfo_TaskIO.DiscardUnknown(m) } -func (m *TaskIO) Reset() { *m = TaskIO{} } -func (*TaskIO) ProtoMessage() {} -func (*TaskIO) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{3} } +var xxx_messageInfo_TaskIO proto.InternalMessageInfo type TaskExit struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` - ExitStatus uint32 `protobuf:"varint,4,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,5,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + ExitStatus uint32 `protobuf:"varint,4,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,5,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskExit) Reset() { *m = TaskExit{} } +func (*TaskExit) ProtoMessage() {} +func (*TaskExit) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{4} +} +func (m *TaskExit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskExit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskExit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskExit) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskExit.Merge(m, src) +} +func (m *TaskExit) XXX_Size() int { + return m.Size() +} +func (m *TaskExit) XXX_DiscardUnknown() { + xxx_messageInfo_TaskExit.DiscardUnknown(m) } -func (m *TaskExit) Reset() { *m = TaskExit{} } -func (*TaskExit) ProtoMessage() {} -func (*TaskExit) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{4} } +var xxx_messageInfo_TaskExit proto.InternalMessageInfo type TaskOOM struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskOOM) Reset() { *m = TaskOOM{} } +func (*TaskOOM) ProtoMessage() {} +func (*TaskOOM) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{5} +} +func (m *TaskOOM) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskOOM) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskOOM.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskOOM) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskOOM.Merge(m, src) +} +func (m *TaskOOM) XXX_Size() int { + return m.Size() +} +func (m *TaskOOM) XXX_DiscardUnknown() { + xxx_messageInfo_TaskOOM.DiscardUnknown(m) } -func (m *TaskOOM) Reset() { *m = TaskOOM{} } -func (*TaskOOM) ProtoMessage() {} -func (*TaskOOM) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{5} } +var xxx_messageInfo_TaskOOM proto.InternalMessageInfo type TaskExecAdded struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskExecAdded) Reset() { *m = TaskExecAdded{} } +func (*TaskExecAdded) ProtoMessage() {} +func (*TaskExecAdded) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{6} +} +func (m *TaskExecAdded) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskExecAdded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskExecAdded.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskExecAdded) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskExecAdded.Merge(m, src) +} +func (m *TaskExecAdded) XXX_Size() int { + return m.Size() +} +func (m *TaskExecAdded) XXX_DiscardUnknown() { + xxx_messageInfo_TaskExecAdded.DiscardUnknown(m) } -func (m *TaskExecAdded) Reset() { *m = TaskExecAdded{} } -func (*TaskExecAdded) ProtoMessage() {} -func (*TaskExecAdded) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{6} } +var xxx_messageInfo_TaskExecAdded proto.InternalMessageInfo type TaskExecStarted struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskExecStarted) Reset() { *m = TaskExecStarted{} } +func (*TaskExecStarted) ProtoMessage() {} +func (*TaskExecStarted) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{7} +} +func (m *TaskExecStarted) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskExecStarted) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskExecStarted.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskExecStarted) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskExecStarted.Merge(m, src) +} +func (m *TaskExecStarted) XXX_Size() int { + return m.Size() +} +func (m *TaskExecStarted) XXX_DiscardUnknown() { + xxx_messageInfo_TaskExecStarted.DiscardUnknown(m) } -func (m *TaskExecStarted) Reset() { *m = TaskExecStarted{} } -func (*TaskExecStarted) ProtoMessage() {} -func (*TaskExecStarted) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{7} } +var xxx_messageInfo_TaskExecStarted proto.InternalMessageInfo type TaskPaused struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskPaused) Reset() { *m = TaskPaused{} } +func (*TaskPaused) ProtoMessage() {} +func (*TaskPaused) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{8} +} +func (m *TaskPaused) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskPaused) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskPaused.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskPaused) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskPaused.Merge(m, src) +} +func (m *TaskPaused) XXX_Size() int { + return m.Size() +} +func (m *TaskPaused) XXX_DiscardUnknown() { + xxx_messageInfo_TaskPaused.DiscardUnknown(m) } -func (m *TaskPaused) Reset() { *m = TaskPaused{} } -func (*TaskPaused) ProtoMessage() {} -func (*TaskPaused) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{8} } +var xxx_messageInfo_TaskPaused proto.InternalMessageInfo type TaskResumed struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskResumed) Reset() { *m = TaskResumed{} } +func (*TaskResumed) ProtoMessage() {} +func (*TaskResumed) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{9} +} +func (m *TaskResumed) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskResumed) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskResumed.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskResumed) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskResumed.Merge(m, src) +} +func (m *TaskResumed) XXX_Size() int { + return m.Size() +} +func (m *TaskResumed) XXX_DiscardUnknown() { + xxx_messageInfo_TaskResumed.DiscardUnknown(m) } -func (m *TaskResumed) Reset() { *m = TaskResumed{} } -func (*TaskResumed) ProtoMessage() {} -func (*TaskResumed) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{9} } +var xxx_messageInfo_TaskResumed proto.InternalMessageInfo type TaskCheckpointed struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Checkpoint string `protobuf:"bytes,2,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Checkpoint string `protobuf:"bytes,2,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TaskCheckpointed) Reset() { *m = TaskCheckpointed{} } +func (*TaskCheckpointed) ProtoMessage() {} +func (*TaskCheckpointed) Descriptor() ([]byte, []int) { + return fileDescriptor_8db0813f7adfb63c, []int{10} +} +func (m *TaskCheckpointed) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TaskCheckpointed) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TaskCheckpointed.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TaskCheckpointed) XXX_Merge(src proto.Message) { + xxx_messageInfo_TaskCheckpointed.Merge(m, src) +} +func (m *TaskCheckpointed) XXX_Size() int { + return m.Size() +} +func (m *TaskCheckpointed) XXX_DiscardUnknown() { + xxx_messageInfo_TaskCheckpointed.DiscardUnknown(m) } -func (m *TaskCheckpointed) Reset() { *m = TaskCheckpointed{} } -func (*TaskCheckpointed) ProtoMessage() {} -func (*TaskCheckpointed) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{10} } +var xxx_messageInfo_TaskCheckpointed proto.InternalMessageInfo func init() { proto.RegisterType((*TaskCreate)(nil), "containerd.events.TaskCreate") @@ -150,6 +495,55 @@ proto.RegisterType((*TaskCheckpointed)(nil), "containerd.events.TaskCheckpointed") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/events/task.proto", fileDescriptor_8db0813f7adfb63c) +} + +var fileDescriptor_8db0813f7adfb63c = []byte{ + // 644 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xc7, 0x63, 0xa7, 0x75, 0xd3, 0x09, 0x55, 0x8b, 0x55, 0x95, 0x90, 0x83, 0x1d, 0x99, 0x4b, + 0x4e, 0xb6, 0x08, 0x12, 0x17, 0x84, 0xd4, 0xa4, 0xe1, 0x90, 0x43, 0x95, 0xe2, 0xf6, 0x50, 0x71, + 0x89, 0x36, 0xd9, 0x4d, 0xb2, 0x34, 0xf1, 0x5a, 0xf6, 0x18, 0x15, 0x89, 0x03, 0x8f, 0xc0, 0x23, + 0xf0, 0x38, 0x3d, 0x20, 0xc4, 0x91, 0x53, 0xa0, 0x7e, 0x00, 0x4e, 0x3c, 0x00, 0x5a, 0xaf, 0x93, + 0xb6, 0x54, 0x7c, 0x59, 0xe2, 0x94, 0x9d, 0xd9, 0xd9, 0xff, 0xec, 0xfc, 0x76, 0x3c, 0x81, 0xc7, + 0x13, 0x8e, 0xd3, 0x64, 0xe8, 0x8e, 0xc4, 0xdc, 0x1b, 0x89, 0x00, 0x09, 0x0f, 0x58, 0x44, 0xaf, + 0x2f, 0x49, 0xc8, 0x3d, 0xf6, 0x8a, 0x05, 0x18, 0x7b, 0x48, 0xe2, 0x33, 0x37, 0x8c, 0x04, 0x0a, + 0xf3, 0xee, 0x55, 0x84, 0xab, 0x76, 0xeb, 0xbb, 0x13, 0x31, 0x11, 0xd9, 0xae, 0x27, 0x57, 0x2a, + 0xb0, 0x6e, 0x4f, 0x84, 0x98, 0xcc, 0x98, 0x97, 0x59, 0xc3, 0x64, 0xec, 0x21, 0x9f, 0xb3, 0x18, + 0xc9, 0x3c, 0xcc, 0x03, 0xfe, 0xee, 0x06, 0xf8, 0x3a, 0x64, 0xb1, 0x37, 0x17, 0x49, 0x80, 0xf9, + 0xb9, 0xfd, 0x3f, 0x9e, 0x5b, 0xa5, 0x0c, 0x67, 0xc9, 0x84, 0x07, 0xde, 0x98, 0xb3, 0x19, 0x0d, + 0x09, 0x4e, 0x95, 0x82, 0xf3, 0x4d, 0x03, 0x38, 0x21, 0xf1, 0xd9, 0x41, 0xc4, 0x08, 0x32, 0xb3, + 0x05, 0x77, 0x56, 0x87, 0x07, 0x9c, 0xd6, 0xb4, 0x86, 0xd6, 0xdc, 0xec, 0x6c, 0xa7, 0x0b, 0xbb, + 0x7a, 0xb0, 0xf4, 0xf7, 0xba, 0x7e, 0x75, 0x15, 0xd4, 0xa3, 0xe6, 0x1e, 0x18, 0xc3, 0x24, 0xa0, + 0x33, 0x56, 0xd3, 0x65, 0xb4, 0x9f, 0x5b, 0xa6, 0x07, 0x46, 0x24, 0x04, 0x8e, 0xe3, 0x5a, 0xb9, + 0x51, 0x6e, 0x56, 0x5b, 0xf7, 0xdc, 0x6b, 0xbc, 0xb2, 0x5a, 0xdc, 0x43, 0x59, 0x8b, 0x9f, 0x87, + 0x99, 0x0f, 0x41, 0xe7, 0xa2, 0xb6, 0xd6, 0xd0, 0x9a, 0xd5, 0xd6, 0x7d, 0xf7, 0x16, 0x5c, 0x57, + 0xde, 0xb3, 0xd7, 0xef, 0x18, 0xe9, 0xc2, 0xd6, 0x7b, 0x7d, 0x5f, 0xe7, 0xc2, 0xb4, 0x00, 0x46, + 0x53, 0x36, 0x3a, 0x0b, 0x05, 0x0f, 0xb0, 0xb6, 0x9e, 0xe5, 0xbf, 0xe6, 0x31, 0x77, 0xa0, 0x1c, + 0x72, 0x5a, 0x33, 0x1a, 0x5a, 0x73, 0xcb, 0x97, 0x4b, 0xe7, 0x39, 0x6c, 0x4a, 0x9d, 0x63, 0x24, + 0x11, 0x16, 0x2a, 0x37, 0x97, 0xd4, 0xaf, 0x24, 0x3f, 0xe6, 0x0c, 0xbb, 0x6c, 0xc6, 0x0a, 0x32, + 0xbc, 0x25, 0x6a, 0xda, 0x50, 0x65, 0xe7, 0x1c, 0x07, 0x31, 0x12, 0x4c, 0x24, 0x42, 0xb9, 0x03, + 0xd2, 0x75, 0x9c, 0x79, 0xcc, 0x36, 0x6c, 0x4a, 0x8b, 0xd1, 0x01, 0xc1, 0x1c, 0x5a, 0xdd, 0x55, + 0x8d, 0xe6, 0x2e, 0x5f, 0xdd, 0x3d, 0x59, 0x36, 0x5a, 0xa7, 0x72, 0xb1, 0xb0, 0x4b, 0xef, 0xbe, + 0xd8, 0x9a, 0x5f, 0x51, 0xc7, 0xda, 0x68, 0xee, 0x81, 0xce, 0xa9, 0xa2, 0x96, 0x53, 0xed, 0xfa, + 0x3a, 0xa7, 0xce, 0x4b, 0x30, 0x14, 0x6b, 0x73, 0x17, 0xd6, 0x63, 0xa4, 0x3c, 0x50, 0x45, 0xf8, + 0xca, 0x90, 0x2f, 0x1e, 0x23, 0x15, 0x09, 0x2e, 0x5f, 0x5c, 0x59, 0xb9, 0x9f, 0x45, 0x51, 0x76, + 0x5d, 0xe5, 0x67, 0x51, 0x64, 0xd6, 0xa1, 0x82, 0x2c, 0x9a, 0xf3, 0x80, 0xcc, 0xb2, 0x9b, 0x56, + 0xfc, 0x95, 0xed, 0x7c, 0xd0, 0xa0, 0x22, 0x93, 0x3d, 0x3b, 0xe7, 0x58, 0xb0, 0xfd, 0xf4, 0x9c, + 0xdc, 0x8d, 0x22, 0x96, 0x48, 0xcb, 0xbf, 0x44, 0xba, 0xf6, 0x7b, 0xa4, 0xeb, 0x45, 0x90, 0x3a, + 0x4f, 0x61, 0x43, 0x56, 0xd3, 0xef, 0x1f, 0x16, 0x29, 0xc6, 0x99, 0xc2, 0x96, 0x82, 0xc1, 0x46, + 0x6d, 0x4a, 0x19, 0x2d, 0x44, 0xe4, 0x01, 0x6c, 0xb0, 0x73, 0x36, 0x1a, 0xac, 0xb0, 0x40, 0xba, + 0xb0, 0x0d, 0xa9, 0xd9, 0xeb, 0xfa, 0x86, 0xdc, 0xea, 0x51, 0xe7, 0x0d, 0x6c, 0x2f, 0x33, 0x65, + 0xdf, 0xc2, 0x7f, 0xcc, 0x75, 0xfb, 0x29, 0x9c, 0x7d, 0xf5, 0xc5, 0x1c, 0x91, 0x24, 0x2e, 0x96, + 0xd8, 0x69, 0x43, 0x55, 0x2a, 0xf8, 0x2c, 0x4e, 0xe6, 0x05, 0x25, 0xc6, 0xb0, 0x93, 0x8d, 0xbe, + 0xd5, 0xb8, 0x28, 0xc8, 0xe0, 0xe6, 0x10, 0xd2, 0x7f, 0x1e, 0x42, 0x9d, 0xa3, 0x8b, 0x4b, 0xab, + 0xf4, 0xf9, 0xd2, 0x2a, 0xbd, 0x4d, 0x2d, 0xed, 0x22, 0xb5, 0xb4, 0x4f, 0xa9, 0xa5, 0x7d, 0x4d, + 0x2d, 0xed, 0xfd, 0x77, 0x4b, 0x7b, 0xd1, 0xfa, 0x87, 0x7f, 0x9f, 0x27, 0xea, 0xe7, 0xb4, 0x74, + 0x5a, 0x1e, 0x1a, 0x59, 0x47, 0x3e, 0xfa, 0x11, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x58, 0x0f, 0xec, + 0xbe, 0x06, 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *TaskCreate) Field(fieldpath []string) (string, bool) { @@ -210,6 +604,8 @@ // unhandled: exited_at case "container_id": return string(m.ContainerID), len(m.ContainerID) > 0 + case "id": + return string(m.ID), len(m.ID) > 0 } return "", false } @@ -346,7 +742,7 @@ func (m *TaskCreate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -354,62 +750,78 @@ } func (m *TaskCreate) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Bundle) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Bundle))) - i += copy(dAtA[i:], m.Bundle) + if m.Pid != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x30 } - if len(m.Rootfs) > 0 { - for _, msg := range m.Rootfs { - dAtA[i] = 0x1a - i++ - i = encodeVarintTask(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + if len(m.Checkpoint) > 0 { + i -= len(m.Checkpoint) + copy(dAtA[i:], m.Checkpoint) + i = encodeVarintTask(dAtA, i, uint64(len(m.Checkpoint))) + i-- + dAtA[i] = 0x2a + } + if m.IO != nil { + { + size, err := m.IO.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintTask(dAtA, i, uint64(size)) } - } - if m.IO != nil { + i-- dAtA[i] = 0x22 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.IO.Size())) - n1, err := m.IO.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + } + if len(m.Rootfs) > 0 { + for iNdEx := len(m.Rootfs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rootfs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTask(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i += n1 } - if len(m.Checkpoint) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Checkpoint))) - i += copy(dAtA[i:], m.Checkpoint) + if len(m.Bundle) > 0 { + i -= len(m.Bundle) + copy(dAtA[i:], m.Bundle) + i = encodeVarintTask(dAtA, i, uint64(len(m.Bundle))) + i-- + dAtA[i] = 0x12 } - if m.Pid != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *TaskStart) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -417,28 +829,38 @@ } func (m *TaskStart) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskStart) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Pid != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x10 } - return i, nil + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *TaskDelete) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -446,41 +868,58 @@ } func (m *TaskDelete) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if m.Pid != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0x2a } + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintTask(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x22 if m.ExitStatus != 0 { - dAtA[i] = 0x18 - i++ i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x18 } - dAtA[i] = 0x22 - i++ - i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n2, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.Pid != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x10 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - i += n2 - return i, nil + return len(dAtA) - i, nil } func (m *TaskIO) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -488,45 +927,57 @@ } func (m *TaskIO) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskIO) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Stdin) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) - } - if len(m.Stderr) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Terminal { - dAtA[i] = 0x20 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 + } + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x1a + } + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintTask(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *TaskExit) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -534,47 +985,58 @@ } func (m *TaskExit) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskExit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) - } - if len(m.ID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintTask(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x2a + if m.ExitStatus != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x20 } if m.Pid != 0 { - dAtA[i] = 0x18 - i++ i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x18 } - if m.ExitStatus != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus)) + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0x12 } - dAtA[i] = 0x2a - i++ - i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n3, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - i += n3 - return i, nil + return len(dAtA) - i, nil } func (m *TaskOOM) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -582,23 +1044,33 @@ } func (m *TaskOOM) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskOOM) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *TaskExecAdded) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -606,29 +1078,40 @@ } func (m *TaskExecAdded) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskExecAdded) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTask(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *TaskExecStarted) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -636,34 +1119,45 @@ } func (m *TaskExecStarted) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskExecStarted) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Pid != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x18 } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTask(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 } - if m.Pid != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *TaskPaused) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -671,23 +1165,33 @@ } func (m *TaskPaused) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskPaused) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *TaskResumed) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -695,23 +1199,33 @@ } func (m *TaskResumed) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskResumed) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *TaskCheckpointed) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -719,35 +1233,51 @@ } func (m *TaskCheckpointed) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TaskCheckpointed) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Checkpoint) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Checkpoint) + copy(dAtA[i:], m.Checkpoint) i = encodeVarintTask(dAtA, i, uint64(len(m.Checkpoint))) - i += copy(dAtA[i:], m.Checkpoint) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintTask(dAtA []byte, offset int, v uint64) int { + offset -= sovTask(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *TaskCreate) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -775,10 +1305,16 @@ if m.Pid != 0 { n += 1 + sovTask(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskStart) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -788,10 +1324,16 @@ if m.Pid != 0 { n += 1 + sovTask(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskDelete) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -804,12 +1346,22 @@ if m.ExitStatus != 0 { n += 1 + sovTask(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovTask(uint64(l)) + l = len(m.ID) + if l > 0 { + n += 1 + l + sovTask(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskIO) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Stdin) @@ -827,10 +1379,16 @@ if m.Terminal { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskExit) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -847,22 +1405,34 @@ if m.ExitStatus != 0 { n += 1 + sovTask(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovTask(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskOOM) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskExecAdded) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -873,10 +1443,16 @@ if l > 0 { n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskExecStarted) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -890,30 +1466,48 @@ if m.Pid != 0 { n += 1 + sovTask(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskPaused) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskResumed) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *TaskCheckpointed) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -924,18 +1518,14 @@ if l > 0 { n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovTask(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozTask(x uint64) (n int) { return sovTask(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -944,13 +1534,19 @@ if this == nil { return "nil" } + repeatedStringForRootfs := "[]*Mount{" + for _, f := range this.Rootfs { + repeatedStringForRootfs += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForRootfs += "}" s := strings.Join([]string{`&TaskCreate{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `Bundle:` + fmt.Sprintf("%v", this.Bundle) + `,`, - `Rootfs:` + strings.Replace(fmt.Sprintf("%v", this.Rootfs), "Mount", "containerd_types.Mount", 1) + `,`, - `IO:` + strings.Replace(fmt.Sprintf("%v", this.IO), "TaskIO", "TaskIO", 1) + `,`, + `Rootfs:` + repeatedStringForRootfs + `,`, + `IO:` + strings.Replace(this.IO.String(), "TaskIO", "TaskIO", 1) + `,`, `Checkpoint:` + fmt.Sprintf("%v", this.Checkpoint) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -962,6 +1558,7 @@ s := strings.Join([]string{`&TaskStart{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -974,7 +1571,9 @@ `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -988,6 +1587,7 @@ `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1001,7 +1601,8 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1012,6 +1613,7 @@ } s := strings.Join([]string{`&TaskOOM{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1023,6 +1625,7 @@ s := strings.Join([]string{`&TaskExecAdded{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1035,6 +1638,7 @@ `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1045,6 +1649,7 @@ } s := strings.Join([]string{`&TaskPaused{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1055,6 +1660,7 @@ } s := strings.Join([]string{`&TaskResumed{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1066,6 +1672,7 @@ s := strings.Join([]string{`&TaskCheckpointed{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `Checkpoint:` + fmt.Sprintf("%v", this.Checkpoint) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1093,7 +1700,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1121,7 +1728,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1131,6 +1738,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1150,7 +1760,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1160,6 +1770,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1179,7 +1792,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1188,10 +1801,13 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Rootfs = append(m.Rootfs, &containerd_types.Mount{}) + m.Rootfs = append(m.Rootfs, &types.Mount{}) if err := m.Rootfs[len(m.Rootfs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1210,7 +1826,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1219,6 +1835,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1243,7 +1862,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1253,6 +1872,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1272,7 +1894,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1283,12 +1905,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1313,7 +1936,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1341,7 +1964,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1351,6 +1974,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1370,7 +1996,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1381,12 +2007,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1411,7 +2038,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1439,7 +2066,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1449,6 +2076,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1468,7 +2098,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1487,7 +2117,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1506,7 +2136,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1515,25 +2145,61 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTask + } + 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 ErrInvalidLengthTask + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTask(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1558,7 +2224,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1586,7 +2252,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1596,6 +2262,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1615,7 +2284,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1625,6 +2294,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1644,7 +2316,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1654,6 +2326,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1673,7 +2348,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1685,12 +2360,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1715,7 +2391,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1743,7 +2419,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1753,6 +2429,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1772,7 +2451,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1782,6 +2461,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1801,7 +2483,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1820,7 +2502,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -1839,7 +2521,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1848,10 +2530,13 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1861,12 +2546,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1891,7 +2577,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1919,7 +2605,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1929,6 +2615,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1940,12 +2629,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1970,7 +2660,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1998,7 +2688,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2008,6 +2698,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2027,7 +2720,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2037,6 +2730,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2048,12 +2744,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2078,7 +2775,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2106,7 +2803,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2116,6 +2813,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2135,7 +2835,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2145,6 +2845,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2164,7 +2867,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2175,12 +2878,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2205,7 +2909,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2233,7 +2937,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2243,6 +2947,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2254,12 +2961,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2284,7 +2992,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2312,7 +3020,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2322,6 +3030,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2333,12 +3044,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2363,7 +3075,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2391,7 +3103,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2401,6 +3113,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2420,7 +3135,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2430,6 +3145,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2441,12 +3159,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2459,6 +3178,7 @@ func skipTask(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -2490,10 +3210,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -2510,101 +3228,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthTask } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTask - } - 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 := skipTask(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTask + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthTask + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthTask = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTask = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthTask = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTask = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTask = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/events/task.proto", fileDescriptorTask) -} - -var fileDescriptorTask = []byte{ - // 637 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xc7, 0x63, 0xa7, 0x75, 0x93, 0x09, 0x55, 0x8b, 0x55, 0x41, 0xc8, 0xc1, 0x8e, 0xcc, 0x25, - 0x27, 0x5b, 0x04, 0x89, 0x0b, 0x42, 0x6a, 0xd2, 0x70, 0xc8, 0xa1, 0x4a, 0x71, 0x7b, 0xa8, 0xb8, - 0x44, 0x4e, 0x76, 0x93, 0x2c, 0x8d, 0xbd, 0x96, 0x3d, 0x46, 0x45, 0xe2, 0xc0, 0x23, 0xf0, 0x08, - 0x3c, 0x05, 0xcf, 0xd0, 0x03, 0x07, 0x8e, 0x9c, 0x02, 0xf5, 0x03, 0x70, 0xe2, 0x01, 0xd0, 0x7a, - 0x1d, 0xb7, 0x50, 0xf1, 0x65, 0x89, 0x53, 0x76, 0x66, 0x67, 0xff, 0x33, 0xf3, 0xdb, 0xc9, 0x1a, - 0x1e, 0xcd, 0x19, 0x2e, 0x92, 0x89, 0x3d, 0xe5, 0xbe, 0x33, 0xe5, 0x01, 0x7a, 0x2c, 0xa0, 0x11, - 0xb9, 0xbe, 0xf4, 0x42, 0xe6, 0xd0, 0x97, 0x34, 0xc0, 0xd8, 0x41, 0x2f, 0x3e, 0xb3, 0xc3, 0x88, - 0x23, 0xd7, 0x6f, 0x5f, 0x45, 0xd8, 0x72, 0xb7, 0xb5, 0x37, 0xe7, 0x73, 0x9e, 0xed, 0x3a, 0x62, - 0x25, 0x03, 0x5b, 0xe6, 0x9c, 0xf3, 0xf9, 0x92, 0x3a, 0x99, 0x35, 0x49, 0x66, 0x0e, 0x32, 0x9f, - 0xc6, 0xe8, 0xf9, 0x61, 0x1e, 0xf0, 0x77, 0x15, 0xe0, 0xab, 0x90, 0xc6, 0x8e, 0xcf, 0x93, 0x00, - 0xf3, 0x73, 0xfb, 0x7f, 0x3c, 0x57, 0xa4, 0x0c, 0x97, 0xc9, 0x9c, 0x05, 0xce, 0x8c, 0xd1, 0x25, - 0x09, 0x3d, 0x5c, 0x48, 0x05, 0xeb, 0xab, 0x02, 0x70, 0xe2, 0xc5, 0x67, 0x07, 0x11, 0xf5, 0x90, - 0xea, 0x5d, 0xb8, 0x55, 0x1c, 0x1e, 0x33, 0xd2, 0x54, 0xda, 0x4a, 0xa7, 0xde, 0xdf, 0x49, 0x57, - 0x66, 0xe3, 0x60, 0xed, 0x1f, 0x0e, 0xdc, 0x46, 0x11, 0x34, 0x24, 0xfa, 0x1d, 0xd0, 0x26, 0x49, - 0x40, 0x96, 0xb4, 0xa9, 0x8a, 0x68, 0x37, 0xb7, 0x74, 0x07, 0xb4, 0x88, 0x73, 0x9c, 0xc5, 0xcd, - 0x6a, 0xbb, 0xda, 0x69, 0x74, 0xef, 0xda, 0xd7, 0x78, 0x65, 0xbd, 0xd8, 0x87, 0xa2, 0x17, 0x37, - 0x0f, 0xd3, 0x1f, 0x80, 0xca, 0x78, 0x73, 0xa3, 0xad, 0x74, 0x1a, 0xdd, 0x7b, 0xf6, 0x0d, 0xb8, - 0xb6, 0xa8, 0x73, 0x38, 0xea, 0x6b, 0xe9, 0xca, 0x54, 0x87, 0x23, 0x57, 0x65, 0x5c, 0x37, 0x00, - 0xa6, 0x0b, 0x3a, 0x3d, 0x0b, 0x39, 0x0b, 0xb0, 0xb9, 0x99, 0xe5, 0xbf, 0xe6, 0xd1, 0x77, 0xa1, - 0x1a, 0x32, 0xd2, 0xd4, 0xda, 0x4a, 0x67, 0xdb, 0x15, 0x4b, 0xeb, 0x19, 0xd4, 0x85, 0xce, 0x31, - 0x7a, 0x11, 0x96, 0x6a, 0x37, 0x97, 0x54, 0xaf, 0x24, 0xdf, 0xe7, 0x0c, 0x07, 0x74, 0x49, 0x4b, - 0x32, 0xbc, 0x21, 0xaa, 0x9b, 0xd0, 0xa0, 0xe7, 0x0c, 0xc7, 0x31, 0x7a, 0x98, 0x08, 0x84, 0x62, - 0x07, 0x84, 0xeb, 0x38, 0xf3, 0xe8, 0x3d, 0xa8, 0x0b, 0x8b, 0x92, 0xb1, 0x87, 0x39, 0xb4, 0x96, - 0x2d, 0x07, 0xcd, 0x5e, 0xdf, 0xba, 0x7d, 0xb2, 0x1e, 0xb4, 0x7e, 0xed, 0x62, 0x65, 0x56, 0xde, - 0x7e, 0x36, 0x15, 0xb7, 0x26, 0x8f, 0xf5, 0xd0, 0x7a, 0x01, 0x9a, 0x64, 0xaa, 0xef, 0xc1, 0x66, - 0x8c, 0x84, 0x05, 0xb2, 0x58, 0x57, 0x1a, 0xe2, 0x66, 0x63, 0x24, 0x3c, 0xc1, 0xf5, 0xcd, 0x4a, - 0x2b, 0xf7, 0xd3, 0x28, 0xca, 0xca, 0x92, 0x7e, 0x1a, 0x45, 0x7a, 0x0b, 0x6a, 0x48, 0x23, 0x9f, - 0x05, 0xde, 0x32, 0xab, 0xa8, 0xe6, 0x16, 0xb6, 0xf5, 0x41, 0x81, 0x9a, 0x48, 0xf6, 0xf4, 0x9c, - 0x61, 0xc9, 0x31, 0x53, 0x73, 0x42, 0xf5, 0x7c, 0x04, 0x06, 0xae, 0xca, 0x0a, 0x74, 0xd5, 0x5f, - 0xa2, 0xdb, 0xf8, 0x3d, 0xba, 0xcd, 0x52, 0xe8, 0x9e, 0xc0, 0x96, 0xe8, 0x66, 0x34, 0x3a, 0x2c, - 0xd3, 0x8c, 0xb5, 0x80, 0x6d, 0x09, 0x83, 0x4e, 0x7b, 0x84, 0x50, 0x52, 0x8a, 0xc8, 0x7d, 0xd8, - 0xa2, 0xe7, 0x74, 0x3a, 0x2e, 0xb0, 0x40, 0xba, 0x32, 0x35, 0xa1, 0x39, 0x1c, 0xb8, 0x9a, 0xd8, - 0x1a, 0x12, 0xeb, 0x35, 0xec, 0xac, 0x33, 0x65, 0x33, 0xff, 0x1f, 0x73, 0xdd, 0xbc, 0x0a, 0x6b, - 0x5f, 0xfe, 0x33, 0x8e, 0xbc, 0x24, 0x2e, 0x97, 0xd8, 0xea, 0x41, 0x43, 0x28, 0xb8, 0x34, 0x4e, - 0xfc, 0x92, 0x12, 0x33, 0xd8, 0xcd, 0x9e, 0xb8, 0xe2, 0x59, 0x28, 0xc9, 0xe0, 0xc7, 0xc7, 0x46, - 0xfd, 0xf9, 0xb1, 0xe9, 0x1f, 0x5d, 0x5c, 0x1a, 0x95, 0x4f, 0x97, 0x46, 0xe5, 0x4d, 0x6a, 0x28, - 0x17, 0xa9, 0xa1, 0x7c, 0x4c, 0x0d, 0xe5, 0x4b, 0x6a, 0x28, 0xef, 0xbe, 0x19, 0xca, 0xf3, 0xee, - 0x3f, 0x7c, 0x65, 0x1e, 0xcb, 0x9f, 0xd3, 0xca, 0x69, 0x75, 0xa2, 0x65, 0x13, 0xf9, 0xf0, 0x7b, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x69, 0x62, 0x9d, 0xa6, 0x06, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/events/task.proto containerd-1.5.9/api/events/task.proto --- containerd-1.2.6/api/events/task.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/events/task.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.events; @@ -29,6 +45,9 @@ uint32 pid = 2; uint32 exit_status = 3; google.protobuf.Timestamp exited_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + // id is the specific exec. By default if omitted will be `""` thus matches + // the init exec of the task matching `container_id`. + string id = 5; } message TaskIO { diff -Nru containerd-1.2.6/api/next.pb.txt containerd-1.5.9/api/next.pb.txt --- containerd-1.2.6/api/next.pb.txt 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/next.pb.txt 2022-01-05 17:30:58.000000000 +0000 @@ -627,6 +627,13 @@ } json_name: "exitedAt" } + field { + name: "id" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } } message_type { name: "TaskIO" @@ -833,6 +840,7 @@ java_outer_classname: "FieldMaskProto" java_multiple_files: true go_package: "google.golang.org/genproto/protobuf/field_mask;field_mask" + cc_enable_arenas: true objc_class_prefix: "GPB" csharp_namespace: "Google.Protobuf.WellKnownTypes" } @@ -1764,6 +1772,34 @@ type: TYPE_INT64 json_name: "size" } + field { + name: "annotations" + number: 5 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.types.Descriptor.AnnotationsEntry" + json_name: "annotations" + } + nested_type { + name: "AnnotationsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "value" + } + options { + map_entry: true + } + } } options { go_package: "github.com/containerd/containerd/api/types;types" @@ -1775,6 +1811,7 @@ name: "github.com/containerd/containerd/api/services/diff/v1/diff.proto" package: "containerd.services.diff.v1" dependency: "gogoproto/gogo.proto" + dependency: "google/protobuf/any.proto" dependency: "github.com/containerd/containerd/api/types/mount.proto" dependency: "github.com/containerd/containerd/api/types/descriptor.proto" message_type { @@ -1795,6 +1832,35 @@ type_name: ".containerd.types.Mount" json_name: "mounts" } + field { + name: "payloads" + number: 3 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.diff.v1.ApplyRequest.PayloadsEntry" + json_name: "payloads" + } + nested_type { + name: "PayloadsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "value" + } + options { + map_entry: true + } + } } message_type { name: "ApplyResponse" @@ -2332,6 +2398,7 @@ package: "containerd.services.introspection.v1" dependency: "github.com/containerd/containerd/api/types/platform.proto" dependency: "google/rpc/status.proto" + dependency: "google/protobuf/empty.proto" dependency: "gogoproto/gogo.proto" message_type { name: "Plugin" @@ -2435,6 +2502,19 @@ json_name: "plugins" } } + message_type { + name: "ServerResponse" + field { + name: "uuid" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + options { + 65004: "UUID" + } + json_name: "uuid" + } + } service { name: "Introspection" method { @@ -2442,11 +2522,16 @@ input_type: ".containerd.services.introspection.v1.PluginsRequest" output_type: ".containerd.services.introspection.v1.PluginsResponse" } + method { + name: "Server" + input_type: ".google.protobuf.Empty" + output_type: ".containerd.services.introspection.v1.ServerResponse" + } } options { go_package: "github.com/containerd/containerd/api/services/introspection/v1;introspection" } - weak_dependency: 2 + weak_dependency: 3 syntax: "proto3" } file { @@ -2592,6 +2677,89 @@ json_name: "leases" } } + message_type { + name: "Resource" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "type" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "type" + } + } + message_type { + name: "AddResourceRequest" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "resource" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.services.leases.v1.Resource" + options { + 65001: 0 + } + json_name: "resource" + } + } + message_type { + name: "DeleteResourceRequest" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "resource" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.services.leases.v1.Resource" + options { + 65001: 0 + } + json_name: "resource" + } + } + message_type { + name: "ListResourcesRequest" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + } + message_type { + name: "ListResourcesResponse" + field { + name: "resources" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.leases.v1.Resource" + options { + 65001: 0 + } + json_name: "resources" + } + } service { name: "Leases" method { @@ -2609,6 +2777,21 @@ input_type: ".containerd.services.leases.v1.ListRequest" output_type: ".containerd.services.leases.v1.ListResponse" } + method { + name: "AddResource" + input_type: ".containerd.services.leases.v1.AddResourceRequest" + output_type: ".google.protobuf.Empty" + } + method { + name: "DeleteResource" + input_type: ".containerd.services.leases.v1.DeleteResourceRequest" + output_type: ".google.protobuf.Empty" + } + method { + name: "ListResources" + input_type: ".containerd.services.leases.v1.ListResourcesRequest" + output_type: ".containerd.services.leases.v1.ListResourcesResponse" + } } options { go_package: "github.com/containerd/containerd/api/services/leases/v1;leases" @@ -3207,6 +3390,13 @@ type: TYPE_STRING json_name: "snapshotter" } + field { + name: "filters" + number: 2 + label: LABEL_REPEATED + type: TYPE_STRING + json_name: "filters" + } } message_type { name: "ListSnapshotsResponse" @@ -3256,6 +3446,16 @@ json_name: "inodes" } } + message_type { + name: "CleanupRequest" + field { + name: "snapshotter" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "snapshotter" + } + } enum_type { name: "Kind" value { @@ -3339,6 +3539,11 @@ input_type: ".containerd.services.snapshots.v1.UsageRequest" output_type: ".containerd.services.snapshots.v1.UsageResponse" } + method { + name: "Cleanup" + input_type: ".containerd.services.snapshots.v1.CleanupRequest" + output_type: ".google.protobuf.Empty" + } } options { go_package: "github.com/containerd/containerd/api/services/snapshots/v1;snapshots" @@ -4012,6 +4217,34 @@ type_name: ".google.protobuf.Any" json_name: "resources" } + field { + name: "annotations" + number: 3 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.tasks.v1.UpdateTaskRequest.AnnotationsEntry" + json_name: "annotations" + } + nested_type { + name: "AnnotationsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "value" + } + options { + map_entry: true + } + } } message_type { name: "MetricsRequest" @@ -4168,6 +4401,80 @@ syntax: "proto3" } file { + name: "github.com/containerd/containerd/api/services/ttrpc/events/v1/events.proto" + package: "containerd.services.events.ttrpc.v1" + dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "gogoproto/gogo.proto" + dependency: "google/protobuf/any.proto" + dependency: "google/protobuf/empty.proto" + dependency: "google/protobuf/timestamp.proto" + message_type { + name: "ForwardRequest" + field { + name: "envelope" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.services.events.ttrpc.v1.Envelope" + json_name: "envelope" + } + } + message_type { + name: "Envelope" + field { + name: "timestamp" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Timestamp" + options { + 65001: 0 + 65010: 1 + } + json_name: "timestamp" + } + field { + name: "namespace" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "namespace" + } + field { + name: "topic" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "topic" + } + field { + name: "event" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "event" + } + options { + 64400: 1 + } + } + service { + name: "Events" + method { + name: "Forward" + input_type: ".containerd.services.events.ttrpc.v1.ForwardRequest" + output_type: ".google.protobuf.Empty" + } + } + options { + go_package: "github.com/containerd/containerd/api/services/ttrpc/events/v1;events" + } + weak_dependency: 0 + weak_dependency: 1 + syntax: "proto3" +} +file { name: "github.com/containerd/containerd/api/services/version/v1/version.proto" package: "containerd.services.version.v1" dependency: "google/protobuf/empty.proto" diff -Nru containerd-1.2.6/api/services/containers/v1/containers.pb.go containerd-1.5.9/api/services/containers/v1/containers.pb.go --- containerd-1.2.6/api/services/containers/v1/containers.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/containers/v1/containers.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,49 +1,25 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/containers/v1/containers.proto -/* - Package containers is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/containers/v1/containers.proto - - It has these top-level messages: - Container - GetContainerRequest - GetContainerResponse - ListContainersRequest - ListContainersResponse - CreateContainerRequest - CreateContainerResponse - UpdateContainerRequest - UpdateContainerResponse - DeleteContainerRequest - ListContainerMessage -*/ package containers -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" -import google_protobuf3 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" - -import time "time" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -55,7 +31,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Container struct { // ID is the user-specified identifier. @@ -68,16 +44,16 @@ // // Note that to add a new value to this field, read the existing set and // include the entire result in the update call. - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Image contains the reference of the image used to build the // specification and snapshots for running this container. // // If this field is updated, the spec and rootfs needed to updated, as well. Image string `protobuf:"bytes,3,opt,name=image,proto3" json:"image,omitempty"` // Runtime specifies which runtime to use for executing this container. - Runtime *Container_Runtime `protobuf:"bytes,4,opt,name=runtime" json:"runtime,omitempty"` + Runtime *Container_Runtime `protobuf:"bytes,4,opt,name=runtime,proto3" json:"runtime,omitempty"` // Spec to be used when creating the container. This is runtime specific. - Spec *google_protobuf1.Any `protobuf:"bytes,5,opt,name=spec" json:"spec,omitempty"` + Spec *types.Any `protobuf:"bytes,5,opt,name=spec,proto3" json:"spec,omitempty"` // Snapshotter specifies the snapshotter name used for rootfs Snapshotter string `protobuf:"bytes,6,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` // SnapshotKey specifies the snapshot key to use for the container's root @@ -92,9 +68,9 @@ // This field may be updated. SnapshotKey string `protobuf:"bytes,7,opt,name=snapshot_key,json=snapshotKey,proto3" json:"snapshot_key,omitempty"` // CreatedAt is the time the container was first created. - CreatedAt time.Time `protobuf:"bytes,8,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + CreatedAt time.Time `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` // UpdatedAt is the last time the container was mutated. - UpdatedAt time.Time `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + UpdatedAt time.Time `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` // Extensions allow clients to provide zero or more blobs that are directly // associated with the container. One may provide protobuf, json, or other // encoding formats. The primary use of this is to further decorate the @@ -104,39 +80,163 @@ // that should be unique against other extensions. When updating extension // data, one should only update the specified extension using field paths // to select a specific map key. - Extensions map[string]google_protobuf1.Any `protobuf:"bytes,10,rep,name=extensions" json:"extensions" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` + Extensions map[string]types.Any `protobuf:"bytes,10,rep,name=extensions,proto3" json:"extensions" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Container) Reset() { *m = Container{} } +func (*Container) ProtoMessage() {} +func (*Container) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{0} +} +func (m *Container) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Container) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Container.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Container) XXX_Merge(src proto.Message) { + xxx_messageInfo_Container.Merge(m, src) +} +func (m *Container) XXX_Size() int { + return m.Size() +} +func (m *Container) XXX_DiscardUnknown() { + xxx_messageInfo_Container.DiscardUnknown(m) } -func (m *Container) Reset() { *m = Container{} } -func (*Container) ProtoMessage() {} -func (*Container) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{0} } +var xxx_messageInfo_Container proto.InternalMessageInfo type Container_Runtime struct { // Name is the name of the runtime. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Options specify additional runtime initialization options. - Options *google_protobuf1.Any `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + Options *types.Any `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Container_Runtime) Reset() { *m = Container_Runtime{} } +func (*Container_Runtime) ProtoMessage() {} +func (*Container_Runtime) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{0, 1} +} +func (m *Container_Runtime) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Container_Runtime) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Container_Runtime.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Container_Runtime) XXX_Merge(src proto.Message) { + xxx_messageInfo_Container_Runtime.Merge(m, src) +} +func (m *Container_Runtime) XXX_Size() int { + return m.Size() +} +func (m *Container_Runtime) XXX_DiscardUnknown() { + xxx_messageInfo_Container_Runtime.DiscardUnknown(m) } -func (m *Container_Runtime) Reset() { *m = Container_Runtime{} } -func (*Container_Runtime) ProtoMessage() {} -func (*Container_Runtime) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{0, 1} } +var xxx_messageInfo_Container_Runtime proto.InternalMessageInfo type GetContainerRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetContainerRequest) Reset() { *m = GetContainerRequest{} } +func (*GetContainerRequest) ProtoMessage() {} +func (*GetContainerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{1} +} +func (m *GetContainerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetContainerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetContainerRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetContainerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetContainerRequest.Merge(m, src) +} +func (m *GetContainerRequest) XXX_Size() int { + return m.Size() +} +func (m *GetContainerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetContainerRequest.DiscardUnknown(m) } -func (m *GetContainerRequest) Reset() { *m = GetContainerRequest{} } -func (*GetContainerRequest) ProtoMessage() {} -func (*GetContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{1} } +var xxx_messageInfo_GetContainerRequest proto.InternalMessageInfo type GetContainerResponse struct { - Container Container `protobuf:"bytes,1,opt,name=container" json:"container"` + Container Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetContainerResponse) Reset() { *m = GetContainerResponse{} } +func (*GetContainerResponse) ProtoMessage() {} +func (*GetContainerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{2} +} +func (m *GetContainerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetContainerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetContainerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetContainerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetContainerResponse.Merge(m, src) +} +func (m *GetContainerResponse) XXX_Size() int { + return m.Size() +} +func (m *GetContainerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetContainerResponse.DiscardUnknown(m) } -func (m *GetContainerResponse) Reset() { *m = GetContainerResponse{} } -func (*GetContainerResponse) ProtoMessage() {} -func (*GetContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{2} } +var xxx_messageInfo_GetContainerResponse proto.InternalMessageInfo type ListContainersRequest struct { // Filters contains one or more filters using the syntax defined in the @@ -149,39 +249,161 @@ // filters[0] or filters[1] or ... or filters[n-1] or filters[n] // // If filters is zero-length or nil, all items will be returned. - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListContainersRequest) Reset() { *m = ListContainersRequest{} } +func (*ListContainersRequest) ProtoMessage() {} +func (*ListContainersRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{3} +} +func (m *ListContainersRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListContainersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListContainersRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListContainersRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListContainersRequest.Merge(m, src) +} +func (m *ListContainersRequest) XXX_Size() int { + return m.Size() +} +func (m *ListContainersRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListContainersRequest.DiscardUnknown(m) } -func (m *ListContainersRequest) Reset() { *m = ListContainersRequest{} } -func (*ListContainersRequest) ProtoMessage() {} -func (*ListContainersRequest) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{3} } +var xxx_messageInfo_ListContainersRequest proto.InternalMessageInfo type ListContainersResponse struct { - Containers []Container `protobuf:"bytes,1,rep,name=containers" json:"containers"` + Containers []Container `protobuf:"bytes,1,rep,name=containers,proto3" json:"containers"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListContainersResponse) Reset() { *m = ListContainersResponse{} } +func (*ListContainersResponse) ProtoMessage() {} +func (*ListContainersResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{4} +} +func (m *ListContainersResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListContainersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListContainersResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListContainersResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListContainersResponse.Merge(m, src) +} +func (m *ListContainersResponse) XXX_Size() int { + return m.Size() +} +func (m *ListContainersResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListContainersResponse.DiscardUnknown(m) } -func (m *ListContainersResponse) Reset() { *m = ListContainersResponse{} } -func (*ListContainersResponse) ProtoMessage() {} -func (*ListContainersResponse) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{4} } +var xxx_messageInfo_ListContainersResponse proto.InternalMessageInfo type CreateContainerRequest struct { - Container Container `protobuf:"bytes,1,opt,name=container" json:"container"` + Container Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateContainerRequest) Reset() { *m = CreateContainerRequest{} } +func (*CreateContainerRequest) ProtoMessage() {} +func (*CreateContainerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{5} +} +func (m *CreateContainerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateContainerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateContainerRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateContainerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateContainerRequest.Merge(m, src) +} +func (m *CreateContainerRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateContainerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateContainerRequest.DiscardUnknown(m) } -func (m *CreateContainerRequest) Reset() { *m = CreateContainerRequest{} } -func (*CreateContainerRequest) ProtoMessage() {} -func (*CreateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{5} } +var xxx_messageInfo_CreateContainerRequest proto.InternalMessageInfo type CreateContainerResponse struct { - Container Container `protobuf:"bytes,1,opt,name=container" json:"container"` + Container Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CreateContainerResponse) Reset() { *m = CreateContainerResponse{} } func (*CreateContainerResponse) ProtoMessage() {} func (*CreateContainerResponse) Descriptor() ([]byte, []int) { - return fileDescriptorContainers, []int{6} + return fileDescriptor_311afb8e15951042, []int{6} +} +func (m *CreateContainerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateContainerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateContainerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateContainerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateContainerResponse.Merge(m, src) +} +func (m *CreateContainerResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateContainerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateContainerResponse.DiscardUnknown(m) } +var xxx_messageInfo_CreateContainerResponse proto.InternalMessageInfo + // UpdateContainerRequest updates the metadata on one or more container. // // The operation should follow semantics described in @@ -191,44 +413,168 @@ // Container provides the target values, as declared by the mask, for the update. // // The ID field must be set. - Container Container `protobuf:"bytes,1,opt,name=container" json:"container"` + Container Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container"` // UpdateMask specifies which fields to perform the update on. If empty, // the operation applies to all fields. - UpdateMask *google_protobuf3.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` + UpdateMask *types.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateContainerRequest) Reset() { *m = UpdateContainerRequest{} } +func (*UpdateContainerRequest) ProtoMessage() {} +func (*UpdateContainerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{7} +} +func (m *UpdateContainerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateContainerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateContainerRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateContainerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateContainerRequest.Merge(m, src) +} +func (m *UpdateContainerRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateContainerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateContainerRequest.DiscardUnknown(m) } -func (m *UpdateContainerRequest) Reset() { *m = UpdateContainerRequest{} } -func (*UpdateContainerRequest) ProtoMessage() {} -func (*UpdateContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{7} } +var xxx_messageInfo_UpdateContainerRequest proto.InternalMessageInfo type UpdateContainerResponse struct { - Container Container `protobuf:"bytes,1,opt,name=container" json:"container"` + Container Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *UpdateContainerResponse) Reset() { *m = UpdateContainerResponse{} } func (*UpdateContainerResponse) ProtoMessage() {} func (*UpdateContainerResponse) Descriptor() ([]byte, []int) { - return fileDescriptorContainers, []int{8} + return fileDescriptor_311afb8e15951042, []int{8} +} +func (m *UpdateContainerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateContainerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateContainerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateContainerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateContainerResponse.Merge(m, src) +} +func (m *UpdateContainerResponse) XXX_Size() int { + return m.Size() +} +func (m *UpdateContainerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateContainerResponse.DiscardUnknown(m) } +var xxx_messageInfo_UpdateContainerResponse proto.InternalMessageInfo + type DeleteContainerRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteContainerRequest) Reset() { *m = DeleteContainerRequest{} } +func (*DeleteContainerRequest) ProtoMessage() {} +func (*DeleteContainerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{9} +} +func (m *DeleteContainerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteContainerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteContainerRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteContainerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteContainerRequest.Merge(m, src) +} +func (m *DeleteContainerRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteContainerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteContainerRequest.DiscardUnknown(m) } -func (m *DeleteContainerRequest) Reset() { *m = DeleteContainerRequest{} } -func (*DeleteContainerRequest) ProtoMessage() {} -func (*DeleteContainerRequest) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{9} } +var xxx_messageInfo_DeleteContainerRequest proto.InternalMessageInfo type ListContainerMessage struct { - Container *Container `protobuf:"bytes,1,opt,name=container" json:"container,omitempty"` + Container *Container `protobuf:"bytes,1,opt,name=container,proto3" json:"container,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListContainerMessage) Reset() { *m = ListContainerMessage{} } +func (*ListContainerMessage) ProtoMessage() {} +func (*ListContainerMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_311afb8e15951042, []int{10} +} +func (m *ListContainerMessage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListContainerMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListContainerMessage.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListContainerMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListContainerMessage.Merge(m, src) +} +func (m *ListContainerMessage) XXX_Size() int { + return m.Size() +} +func (m *ListContainerMessage) XXX_DiscardUnknown() { + xxx_messageInfo_ListContainerMessage.DiscardUnknown(m) } -func (m *ListContainerMessage) Reset() { *m = ListContainerMessage{} } -func (*ListContainerMessage) ProtoMessage() {} -func (*ListContainerMessage) Descriptor() ([]byte, []int) { return fileDescriptorContainers, []int{10} } +var xxx_messageInfo_ListContainerMessage proto.InternalMessageInfo func init() { proto.RegisterType((*Container)(nil), "containerd.services.containers.v1.Container") + proto.RegisterMapType((map[string]types.Any)(nil), "containerd.services.containers.v1.Container.ExtensionsEntry") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.containers.v1.Container.LabelsEntry") proto.RegisterType((*Container_Runtime)(nil), "containerd.services.containers.v1.Container.Runtime") proto.RegisterType((*GetContainerRequest)(nil), "containerd.services.containers.v1.GetContainerRequest") proto.RegisterType((*GetContainerResponse)(nil), "containerd.services.containers.v1.GetContainerResponse") @@ -242,6 +588,66 @@ proto.RegisterType((*ListContainerMessage)(nil), "containerd.services.containers.v1.ListContainerMessage") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/containers/v1/containers.proto", fileDescriptor_311afb8e15951042) +} + +var fileDescriptor_311afb8e15951042 = []byte{ + // 820 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6e, 0x13, 0x49, + 0x14, 0x75, 0xdb, 0x4e, 0x3b, 0xbe, 0x1e, 0x69, 0x46, 0x35, 0x1e, 0x4f, 0x4f, 0x8f, 0x64, 0x3b, + 0x5e, 0x59, 0xa3, 0xa1, 0x9d, 0x18, 0x44, 0x5e, 0x6c, 0xe2, 0xbc, 0x04, 0x24, 0x28, 0xea, 0x80, + 0x84, 0x60, 0x11, 0xda, 0x76, 0xc5, 0x69, 0xdc, 0x2f, 0xba, 0xca, 0x16, 0x16, 0x8b, 0xc0, 0x1f, + 0xb0, 0xe3, 0x13, 0xf8, 0x95, 0x2c, 0x59, 0xb2, 0x0a, 0xc4, 0xe2, 0x43, 0x50, 0x57, 0x57, 0xbb, + 0x3b, 0x7e, 0x80, 0x9d, 0x90, 0x5d, 0x5d, 0xd7, 0x3d, 0xf7, 0x9e, 0x3a, 0xb7, 0x4e, 0xb9, 0x61, + 0xaf, 0xa5, 0xd3, 0x93, 0x4e, 0x5d, 0x69, 0xd8, 0x66, 0xa5, 0x61, 0x5b, 0x54, 0xd3, 0x2d, 0xec, + 0x36, 0xa3, 0x4b, 0xcd, 0xd1, 0x2b, 0x04, 0xbb, 0x5d, 0xbd, 0x81, 0x49, 0xf8, 0x3b, 0xa9, 0x74, + 0x97, 0x22, 0x91, 0xe2, 0xb8, 0x36, 0xb5, 0xd1, 0x42, 0x88, 0x53, 0x02, 0x8c, 0x12, 0xc9, 0xea, + 0x2e, 0xc9, 0xd9, 0x96, 0xdd, 0xb2, 0x59, 0x76, 0xc5, 0x5b, 0xf9, 0x40, 0xf9, 0x9f, 0x96, 0x6d, + 0xb7, 0x0c, 0x5c, 0x61, 0x51, 0xbd, 0x73, 0x5c, 0xd1, 0xac, 0x1e, 0xdf, 0xfa, 0x77, 0x78, 0x0b, + 0x9b, 0x0e, 0x0d, 0x36, 0x8b, 0xc3, 0x9b, 0xc7, 0x3a, 0x36, 0x9a, 0x47, 0xa6, 0x46, 0xda, 0x3c, + 0xa3, 0x30, 0x9c, 0x41, 0x75, 0x13, 0x13, 0xaa, 0x99, 0x8e, 0x9f, 0x50, 0xfa, 0x20, 0x42, 0x7a, + 0x33, 0xa0, 0x88, 0x72, 0x10, 0xd7, 0x9b, 0x92, 0x50, 0x14, 0xca, 0xe9, 0x9a, 0xd8, 0x3f, 0x2f, + 0xc4, 0xef, 0x6f, 0xa9, 0x71, 0xbd, 0x89, 0x0e, 0x40, 0x34, 0xb4, 0x3a, 0x36, 0x88, 0x14, 0x2f, + 0x26, 0xca, 0x99, 0xea, 0x8a, 0xf2, 0xd3, 0xa3, 0x2a, 0x83, 0xaa, 0xca, 0x1e, 0x83, 0x6e, 0x5b, + 0xd4, 0xed, 0xa9, 0xbc, 0x0e, 0xca, 0xc2, 0x9c, 0x6e, 0x6a, 0x2d, 0x2c, 0x25, 0xbc, 0x66, 0xaa, + 0x1f, 0xa0, 0x47, 0x90, 0x72, 0x3b, 0x96, 0xc7, 0x51, 0x4a, 0x16, 0x85, 0x72, 0xa6, 0x7a, 0x67, + 0xa6, 0x46, 0xaa, 0x8f, 0x55, 0x83, 0x22, 0xa8, 0x0c, 0x49, 0xe2, 0xe0, 0x86, 0x34, 0xc7, 0x8a, + 0x65, 0x15, 0x5f, 0x0d, 0x25, 0x50, 0x43, 0xd9, 0xb0, 0x7a, 0x2a, 0xcb, 0x40, 0x45, 0xc8, 0x10, + 0x4b, 0x73, 0xc8, 0x89, 0x4d, 0x29, 0x76, 0x25, 0x91, 0xb1, 0x8a, 0xfe, 0x84, 0x16, 0xe0, 0xb7, + 0x20, 0x3c, 0x6a, 0xe3, 0x9e, 0x94, 0xba, 0x9c, 0xf2, 0x10, 0xf7, 0xd0, 0x26, 0x40, 0xc3, 0xc5, + 0x1a, 0xc5, 0xcd, 0x23, 0x8d, 0x4a, 0xf3, 0xac, 0xa9, 0x3c, 0xd2, 0xf4, 0x71, 0x30, 0x82, 0xda, + 0xfc, 0xd9, 0x79, 0x21, 0xf6, 0xfe, 0x4b, 0x41, 0x50, 0xd3, 0x1c, 0xb7, 0x41, 0xbd, 0x22, 0x1d, + 0xa7, 0x19, 0x14, 0x49, 0xcf, 0x52, 0x84, 0xe3, 0x36, 0x28, 0xaa, 0x03, 0xe0, 0xd7, 0x14, 0x5b, + 0x44, 0xb7, 0x2d, 0x22, 0x01, 0x1b, 0xda, 0xbd, 0x99, 0xb4, 0xdc, 0x1e, 0xc0, 0xd9, 0xe0, 0x6a, + 0x49, 0xaf, 0x8d, 0x1a, 0xa9, 0x2a, 0xaf, 0x42, 0x26, 0x32, 0x59, 0xf4, 0x07, 0x24, 0x3c, 0x59, + 0xd8, 0xe5, 0x51, 0xbd, 0xa5, 0x37, 0xe3, 0xae, 0x66, 0x74, 0xb0, 0x14, 0xf7, 0x67, 0xcc, 0x82, + 0xb5, 0xf8, 0x8a, 0x20, 0xef, 0x43, 0x8a, 0xcf, 0x0a, 0x21, 0x48, 0x5a, 0x9a, 0x89, 0x39, 0x8e, + 0xad, 0x91, 0x02, 0x29, 0xdb, 0xa1, 0x8c, 0x7a, 0xfc, 0x07, 0x93, 0x0b, 0x92, 0xe4, 0x43, 0xf8, + 0x7d, 0x88, 0xee, 0x18, 0x36, 0xff, 0x45, 0xd9, 0x4c, 0x2a, 0x19, 0x72, 0x2c, 0xdd, 0x82, 0x3f, + 0x77, 0x31, 0x1d, 0x08, 0xa2, 0xe2, 0x57, 0x1d, 0x4c, 0xe8, 0x24, 0x8b, 0x94, 0x4e, 0x20, 0x7b, + 0x39, 0x9d, 0x38, 0xb6, 0x45, 0x30, 0x3a, 0x80, 0xf4, 0x40, 0x62, 0x06, 0xcb, 0x54, 0xff, 0x9f, + 0x65, 0x10, 0x5c, 0xf8, 0xb0, 0x48, 0x69, 0x09, 0xfe, 0xda, 0xd3, 0x49, 0xd8, 0x8a, 0x04, 0xd4, + 0x24, 0x48, 0x1d, 0xeb, 0x06, 0xc5, 0x2e, 0x91, 0x84, 0x62, 0xa2, 0x9c, 0x56, 0x83, 0xb0, 0x64, + 0x40, 0x6e, 0x18, 0xc2, 0xe9, 0xa9, 0x00, 0x61, 0x63, 0x06, 0xbb, 0x1a, 0xbf, 0x48, 0x95, 0xd2, + 0x4b, 0xc8, 0x6d, 0xb2, 0xeb, 0x3c, 0x22, 0xde, 0xaf, 0x17, 0xa3, 0x0d, 0x7f, 0x8f, 0xf4, 0xba, + 0x31, 0xe5, 0x3f, 0x0a, 0x90, 0x7b, 0xc2, 0x3c, 0x76, 0xf3, 0x27, 0x43, 0xeb, 0x90, 0xf1, 0xfd, + 0xcc, 0xde, 0x73, 0x7e, 0x6b, 0x47, 0x1f, 0x82, 0x1d, 0xef, 0xc9, 0xdf, 0xd7, 0x48, 0x5b, 0xe5, + 0xcf, 0x86, 0xb7, 0xf6, 0x64, 0x19, 0x21, 0x7a, 0x63, 0xb2, 0x2c, 0x42, 0x6e, 0x0b, 0x1b, 0x78, + 0x8c, 0x2a, 0x93, 0xcc, 0x52, 0x87, 0xec, 0xa5, 0xfb, 0xb8, 0x8f, 0x09, 0xf1, 0xde, 0xff, 0x07, + 0xd7, 0xe4, 0x16, 0x61, 0x55, 0xfd, 0x36, 0x07, 0x10, 0x5e, 0x78, 0xd4, 0x85, 0xc4, 0x2e, 0xa6, + 0xe8, 0xee, 0x14, 0xe5, 0xc6, 0xd8, 0x5e, 0x5e, 0x9e, 0x19, 0xc7, 0xe5, 0x7e, 0x03, 0x49, 0xef, + 0xa8, 0x68, 0x9a, 0xbf, 0xcc, 0xb1, 0xb6, 0x96, 0x57, 0xaf, 0x80, 0xe4, 0xcd, 0xdf, 0x09, 0x00, + 0xde, 0xd6, 0x21, 0x75, 0xb1, 0x66, 0x5e, 0x83, 0xc3, 0xf2, 0xac, 0x48, 0x3e, 0xd1, 0x45, 0x01, + 0x9d, 0x82, 0xe8, 0x3b, 0x14, 0x4d, 0x73, 0x90, 0xf1, 0x0f, 0x87, 0xbc, 0x76, 0x15, 0x28, 0x17, + 0xe1, 0x14, 0x44, 0xdf, 0x0b, 0x53, 0x11, 0x18, 0xef, 0xef, 0xa9, 0x08, 0x4c, 0x72, 0xdc, 0x73, + 0x10, 0x7d, 0x7f, 0x4c, 0x45, 0x60, 0xbc, 0x95, 0xe4, 0xdc, 0x88, 0xf3, 0xb7, 0xbd, 0x2f, 0xc1, + 0xda, 0x8b, 0xb3, 0x8b, 0x7c, 0xec, 0xf3, 0x45, 0x3e, 0xf6, 0xb6, 0x9f, 0x17, 0xce, 0xfa, 0x79, + 0xe1, 0x53, 0x3f, 0x2f, 0x7c, 0xed, 0xe7, 0x85, 0x67, 0x3b, 0xd7, 0xf8, 0xb8, 0x5d, 0x0f, 0xa3, + 0xa7, 0xb1, 0xba, 0xc8, 0x7a, 0xde, 0xfe, 0x1e, 0x00, 0x00, 0xff, 0xff, 0xd0, 0xae, 0xca, 0xcb, + 0x2f, 0x0b, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -250,15 +656,16 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Containers service - +// ContainersClient is the client API for Containers service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type ContainersClient interface { Get(ctx context.Context, in *GetContainerRequest, opts ...grpc.CallOption) (*GetContainerResponse, error) List(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (*ListContainersResponse, error) ListStream(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (Containers_ListStreamClient, error) Create(ctx context.Context, in *CreateContainerRequest, opts ...grpc.CallOption) (*CreateContainerResponse, error) Update(ctx context.Context, in *UpdateContainerRequest, opts ...grpc.CallOption) (*UpdateContainerResponse, error) - Delete(ctx context.Context, in *DeleteContainerRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) + Delete(ctx context.Context, in *DeleteContainerRequest, opts ...grpc.CallOption) (*types.Empty, error) } type containersClient struct { @@ -271,7 +678,7 @@ func (c *containersClient) Get(ctx context.Context, in *GetContainerRequest, opts ...grpc.CallOption) (*GetContainerResponse, error) { out := new(GetContainerResponse) - err := grpc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Get", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Get", in, out, opts...) if err != nil { return nil, err } @@ -280,7 +687,7 @@ func (c *containersClient) List(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (*ListContainersResponse, error) { out := new(ListContainersResponse) - err := grpc.Invoke(ctx, "/containerd.services.containers.v1.Containers/List", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/List", in, out, opts...) if err != nil { return nil, err } @@ -288,7 +695,7 @@ } func (c *containersClient) ListStream(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (Containers_ListStreamClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Containers_serviceDesc.Streams[0], c.cc, "/containerd.services.containers.v1.Containers/ListStream", opts...) + stream, err := c.cc.NewStream(ctx, &_Containers_serviceDesc.Streams[0], "/containerd.services.containers.v1.Containers/ListStream", opts...) if err != nil { return nil, err } @@ -321,7 +728,7 @@ func (c *containersClient) Create(ctx context.Context, in *CreateContainerRequest, opts ...grpc.CallOption) (*CreateContainerResponse, error) { out := new(CreateContainerResponse) - err := grpc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Create", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Create", in, out, opts...) if err != nil { return nil, err } @@ -330,31 +737,53 @@ func (c *containersClient) Update(ctx context.Context, in *UpdateContainerRequest, opts ...grpc.CallOption) (*UpdateContainerResponse, error) { out := new(UpdateContainerResponse) - err := grpc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Update", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Update", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *containersClient) Delete(ctx context.Context, in *DeleteContainerRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) { - out := new(google_protobuf2.Empty) - err := grpc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Delete", in, out, c.cc, opts...) +func (c *containersClient) Delete(ctx context.Context, in *DeleteContainerRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.containers.v1.Containers/Delete", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Containers service - +// ContainersServer is the server API for Containers service. type ContainersServer interface { Get(context.Context, *GetContainerRequest) (*GetContainerResponse, error) List(context.Context, *ListContainersRequest) (*ListContainersResponse, error) ListStream(*ListContainersRequest, Containers_ListStreamServer) error Create(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error) Update(context.Context, *UpdateContainerRequest) (*UpdateContainerResponse, error) - Delete(context.Context, *DeleteContainerRequest) (*google_protobuf2.Empty, error) + Delete(context.Context, *DeleteContainerRequest) (*types.Empty, error) +} + +// UnimplementedContainersServer can be embedded to have forward compatible implementations. +type UnimplementedContainersServer struct { +} + +func (*UnimplementedContainersServer) Get(ctx context.Context, req *GetContainerRequest) (*GetContainerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") +} +func (*UnimplementedContainersServer) List(ctx context.Context, req *ListContainersRequest) (*ListContainersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedContainersServer) ListStream(req *ListContainersRequest, srv Containers_ListStreamServer) error { + return status.Errorf(codes.Unimplemented, "method ListStream not implemented") +} +func (*UnimplementedContainersServer) Create(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (*UnimplementedContainersServer) Update(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedContainersServer) Delete(ctx context.Context, req *DeleteContainerRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func RegisterContainersServer(s *grpc.Server, srv ContainersServer) { @@ -510,7 +939,7 @@ func (m *Container) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -518,120 +947,137 @@ } func (m *Container) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Container) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Labels) > 0 { - for k, _ := range m.Labels { + if len(m.Extensions) > 0 { + for k := range m.Extensions { + v := m.Extensions[k] + baseI := i + { + size, err := (&v).MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - v := m.Labels[k] - mapSize := 1 + len(k) + sovContainers(uint64(len(k))) + 1 + len(v) + sovContainers(uint64(len(v))) - i = encodeVarintContainers(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintContainers(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ - i = encodeVarintContainers(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) - } - } - if len(m.Image) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintContainers(dAtA, i, uint64(len(m.Image))) - i += copy(dAtA[i:], m.Image) - } - if m.Runtime != nil { - dAtA[i] = 0x22 - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Runtime.Size())) - n1, err := m.Runtime.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + i-- + dAtA[i] = 0xa + i = encodeVarintContainers(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x52 } - i += n1 } - if m.Spec != nil { - dAtA[i] = 0x2a - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Spec.Size())) - n2, err := m.Spec.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintContainers(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x4a + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintContainers(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x42 + if len(m.SnapshotKey) > 0 { + i -= len(m.SnapshotKey) + copy(dAtA[i:], m.SnapshotKey) + i = encodeVarintContainers(dAtA, i, uint64(len(m.SnapshotKey))) + i-- + dAtA[i] = 0x3a } if len(m.Snapshotter) > 0 { - dAtA[i] = 0x32 - i++ + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) i = encodeVarintContainers(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + i-- + dAtA[i] = 0x32 } - if len(m.SnapshotKey) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintContainers(dAtA, i, uint64(len(m.SnapshotKey))) - i += copy(dAtA[i:], m.SnapshotKey) + if m.Spec != nil { + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a } - dAtA[i] = 0x42 - i++ - i = encodeVarintContainers(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt))) - n3, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.Runtime != nil { + { + size, err := m.Runtime.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } - i += n3 - dAtA[i] = 0x4a - i++ - i = encodeVarintContainers(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n4, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.Image) > 0 { + i -= len(m.Image) + copy(dAtA[i:], m.Image) + i = encodeVarintContainers(dAtA, i, uint64(len(m.Image))) + i-- + dAtA[i] = 0x1a } - i += n4 - if len(m.Extensions) > 0 { - for k, _ := range m.Extensions { - dAtA[i] = 0x52 - i++ - v := m.Extensions[k] - msgSize := 0 - if (&v) != nil { - msgSize = (&v).Size() - msgSize += 1 + sovContainers(uint64(msgSize)) - } - mapSize := 1 + len(k) + sovContainers(uint64(len(k))) + msgSize - i = encodeVarintContainers(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + if len(m.Labels) > 0 { + for k := range m.Labels { + v := m.Labels[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintContainers(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintContainers(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintContainers(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintContainers(dAtA, i, uint64((&v).Size())) - n5, err := (&v).MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n5 } } - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintContainers(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *Container_Runtime) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -639,33 +1085,45 @@ } func (m *Container_Runtime) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Container_Runtime) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Options != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Options.Size())) - n6, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n6 + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintContainers(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetContainerRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -673,23 +1131,33 @@ } func (m *GetContainerRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetContainerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintContainers(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetContainerResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -697,58 +1165,72 @@ } func (m *GetContainerResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetContainerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n7, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n7 - return i, nil + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ListContainersRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil } -func (m *ListContainersRequest) MarshalTo(dAtA []byte) (int, error) { - var i int +func (m *ListContainersRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListContainersRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintContainers(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *ListContainersResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -756,29 +1238,40 @@ } func (m *ListContainersResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListContainersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Containers) > 0 { - for _, msg := range m.Containers { - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Containers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Containers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *CreateContainerRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -786,25 +1279,36 @@ } func (m *CreateContainerRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateContainerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n8, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n8 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CreateContainerResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -812,25 +1316,36 @@ } func (m *CreateContainerResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateContainerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n9, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n9 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateContainerRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -838,35 +1353,48 @@ } func (m *UpdateContainerRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateContainerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n10, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n10 if m.UpdateMask != nil { + { + size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.UpdateMask.Size())) - n11, err := m.UpdateMask.MarshalTo(dAtA[i:]) + } + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n11 + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateContainerResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -874,25 +1402,36 @@ } func (m *UpdateContainerResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateContainerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n12, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n12 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *DeleteContainerRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -900,23 +1439,33 @@ } func (m *DeleteContainerRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteContainerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintContainers(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListContainerMessage) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -924,33 +1473,49 @@ } func (m *ListContainerMessage) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListContainerMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Container != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintContainers(dAtA, i, uint64(m.Container.Size())) - n13, err := m.Container.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Container.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContainers(dAtA, i, uint64(size)) } - i += n13 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintContainers(dAtA []byte, offset int, v uint64) int { + offset -= sovContainers(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Container) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -985,9 +1550,9 @@ if l > 0 { n += 1 + l + sovContainers(uint64(l)) } - l = types.SizeOfStdTime(m.CreatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovContainers(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovContainers(uint64(l)) if len(m.Extensions) > 0 { for k, v := range m.Extensions { @@ -998,10 +1563,16 @@ n += mapEntrySize + 1 + sovContainers(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *Container_Runtime) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -1012,28 +1583,46 @@ l = m.Options.Size() n += 1 + l + sovContainers(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetContainerRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovContainers(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetContainerResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Container.Size() n += 1 + l + sovContainers(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListContainersRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -1042,10 +1631,16 @@ n += 1 + l + sovContainers(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListContainersResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Containers) > 0 { @@ -1054,26 +1649,44 @@ n += 1 + l + sovContainers(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateContainerRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Container.Size() n += 1 + l + sovContainers(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateContainerResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Container.Size() n += 1 + l + sovContainers(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateContainerRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Container.Size() @@ -1082,46 +1695,60 @@ l = m.UpdateMask.Size() n += 1 + l + sovContainers(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateContainerResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Container.Size() n += 1 + l + sovContainers(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteContainerRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovContainers(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListContainerMessage) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Container != nil { l = m.Container.Size() n += 1 + l + sovContainers(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovContainers(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozContainers(x uint64) (n int) { return sovContainers(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1134,7 +1761,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1144,8 +1771,8 @@ for k, _ := range this.Extensions { keysForExtensions = append(keysForExtensions, k) } - sortkeys.Strings(keysForExtensions) - mapStringForExtensions := "map[string]google_protobuf1.Any{" + github_com_gogo_protobuf_sortkeys.Strings(keysForExtensions) + mapStringForExtensions := "map[string]types.Any{" for _, k := range keysForExtensions { mapStringForExtensions += fmt.Sprintf("%v: %v,", k, this.Extensions[k]) } @@ -1155,12 +1782,13 @@ `Labels:` + mapStringForLabels + `,`, `Image:` + fmt.Sprintf("%v", this.Image) + `,`, `Runtime:` + strings.Replace(fmt.Sprintf("%v", this.Runtime), "Container_Runtime", "Container_Runtime", 1) + `,`, - `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`, + `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "types.Any", 1) + `,`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `SnapshotKey:` + fmt.Sprintf("%v", this.SnapshotKey) + `,`, - `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf4.Timestamp", 1), `&`, ``, 1) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Extensions:` + mapStringForExtensions + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1171,7 +1799,8 @@ } s := strings.Join([]string{`&Container_Runtime{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf1.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1182,6 +1811,7 @@ } s := strings.Join([]string{`&GetContainerRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1192,6 +1822,7 @@ } s := strings.Join([]string{`&GetContainerResponse{`, `Container:` + strings.Replace(strings.Replace(this.Container.String(), "Container", "Container", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1202,6 +1833,7 @@ } s := strings.Join([]string{`&ListContainersRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1210,8 +1842,14 @@ if this == nil { return "nil" } + repeatedStringForContainers := "[]Container{" + for _, f := range this.Containers { + repeatedStringForContainers += strings.Replace(strings.Replace(f.String(), "Container", "Container", 1), `&`, ``, 1) + "," + } + repeatedStringForContainers += "}" s := strings.Join([]string{`&ListContainersResponse{`, - `Containers:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Containers), "Container", "Container", 1), `&`, ``, 1) + `,`, + `Containers:` + repeatedStringForContainers + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1222,6 +1860,7 @@ } s := strings.Join([]string{`&CreateContainerRequest{`, `Container:` + strings.Replace(strings.Replace(this.Container.String(), "Container", "Container", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1232,6 +1871,7 @@ } s := strings.Join([]string{`&CreateContainerResponse{`, `Container:` + strings.Replace(strings.Replace(this.Container.String(), "Container", "Container", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1242,7 +1882,8 @@ } s := strings.Join([]string{`&UpdateContainerRequest{`, `Container:` + strings.Replace(strings.Replace(this.Container.String(), "Container", "Container", 1), `&`, ``, 1) + `,`, - `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf3.FieldMask", 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types.FieldMask", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1253,6 +1894,7 @@ } s := strings.Join([]string{`&UpdateContainerResponse{`, `Container:` + strings.Replace(strings.Replace(this.Container.String(), "Container", "Container", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1263,6 +1905,7 @@ } s := strings.Join([]string{`&DeleteContainerRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1272,7 +1915,8 @@ return "nil" } s := strings.Join([]string{`&ListContainerMessage{`, - `Container:` + strings.Replace(fmt.Sprintf("%v", this.Container), "Container", "Container", 1) + `,`, + `Container:` + strings.Replace(this.Container.String(), "Container", "Container", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1300,7 +1944,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1328,7 +1972,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1338,6 +1982,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1357,7 +2004,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1366,6 +2013,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1386,7 +2036,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1403,7 +2053,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1413,6 +2063,9 @@ return ErrInvalidLengthContainers } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthContainers + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1429,7 +2082,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1439,6 +2092,9 @@ return ErrInvalidLengthContainers } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthContainers + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1450,7 +2106,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > postIndex { @@ -1475,7 +2131,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1485,6 +2141,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1504,7 +2163,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1513,6 +2172,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1537,7 +2199,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1546,11 +2208,14 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Spec == nil { - m.Spec = &google_protobuf1.Any{} + m.Spec = &types.Any{} } if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1570,7 +2235,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1580,6 +2245,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1599,7 +2267,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1609,6 +2277,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1628,7 +2299,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1637,10 +2308,13 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1658,7 +2332,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1667,10 +2341,13 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1688,7 +2365,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1697,14 +2374,17 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Extensions == nil { - m.Extensions = make(map[string]google_protobuf1.Any) + m.Extensions = make(map[string]types.Any) } var mapkey string - mapvalue := &google_protobuf1.Any{} + mapvalue := &types.Any{} for iNdEx < postIndex { entryPreIndex := iNdEx var wire uint64 @@ -1717,7 +2397,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1734,7 +2414,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1744,6 +2424,9 @@ return ErrInvalidLengthContainers } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthContainers + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1760,7 +2443,7 @@ } b := dAtA[iNdEx] iNdEx++ - mapmsglen |= (int(b) & 0x7F) << shift + mapmsglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1769,13 +2452,13 @@ return ErrInvalidLengthContainers } postmsgIndex := iNdEx + mapmsglen - if mapmsglen < 0 { + if postmsgIndex < 0 { return ErrInvalidLengthContainers } if postmsgIndex > l { return io.ErrUnexpectedEOF } - mapvalue = &google_protobuf1.Any{} + mapvalue = &types.Any{} if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { return err } @@ -1786,7 +2469,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > postIndex { @@ -1803,12 +2486,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1833,7 +2517,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1861,7 +2545,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1871,6 +2555,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1890,7 +2577,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1899,11 +2586,14 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf1.Any{} + m.Options = &types.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1915,12 +2605,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1945,7 +2636,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1973,7 +2664,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1983,6 +2674,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1994,12 +2688,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2024,7 +2719,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2052,7 +2747,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2061,6 +2756,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2074,12 +2772,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2104,7 +2803,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2132,7 +2831,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2142,6 +2841,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2153,12 +2855,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2183,7 +2886,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2211,7 +2914,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2220,6 +2923,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2234,12 +2940,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2264,7 +2971,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2292,7 +2999,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2301,6 +3008,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2314,12 +3024,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2344,7 +3055,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2372,7 +3083,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2381,6 +3092,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2394,12 +3108,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2424,7 +3139,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2452,7 +3167,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2461,6 +3176,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2482,7 +3200,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2491,11 +3209,14 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } if m.UpdateMask == nil { - m.UpdateMask = &google_protobuf3.FieldMask{} + m.UpdateMask = &types.FieldMask{} } if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2507,12 +3228,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2537,7 +3259,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2565,7 +3287,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2574,6 +3296,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2587,12 +3312,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2617,7 +3343,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2645,7 +3371,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2655,6 +3381,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2666,12 +3395,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2696,7 +3426,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2724,7 +3454,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2733,6 +3463,9 @@ return ErrInvalidLengthContainers } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContainers + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2749,12 +3482,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContainers } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2767,6 +3501,7 @@ func skipContainers(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -2798,10 +3533,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -2818,113 +3551,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthContainers } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContainers - } - 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 := skipContainers(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupContainers + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthContainers + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthContainers = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowContainers = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthContainers = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowContainers = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupContainers = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/containers/v1/containers.proto", fileDescriptorContainers) -} - -var fileDescriptorContainers = []byte{ - // 820 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6e, 0x13, 0x49, - 0x14, 0x75, 0xdb, 0x4e, 0x3b, 0xbe, 0x1e, 0x69, 0x46, 0x35, 0x1e, 0x4f, 0x4f, 0x8f, 0x64, 0x3b, - 0x5e, 0x59, 0xa3, 0xa1, 0x9d, 0x18, 0x44, 0x5e, 0x6c, 0xe2, 0xbc, 0x04, 0x24, 0x28, 0xea, 0x80, - 0x84, 0x60, 0x11, 0xda, 0x76, 0xc5, 0x69, 0xdc, 0x2f, 0xba, 0xca, 0x16, 0x16, 0x8b, 0xc0, 0x1f, - 0xb0, 0xe3, 0x13, 0xf8, 0x95, 0x2c, 0x59, 0xb2, 0x0a, 0xc4, 0xe2, 0x43, 0x50, 0x57, 0x57, 0xbb, - 0x3b, 0x7e, 0x80, 0x9d, 0x90, 0x5d, 0x5d, 0xd7, 0x3d, 0xf7, 0x9e, 0x3a, 0xb7, 0x4e, 0xb9, 0x61, - 0xaf, 0xa5, 0xd3, 0x93, 0x4e, 0x5d, 0x69, 0xd8, 0x66, 0xa5, 0x61, 0x5b, 0x54, 0xd3, 0x2d, 0xec, - 0x36, 0xa3, 0x4b, 0xcd, 0xd1, 0x2b, 0x04, 0xbb, 0x5d, 0xbd, 0x81, 0x49, 0xf8, 0x3b, 0xa9, 0x74, - 0x97, 0x22, 0x91, 0xe2, 0xb8, 0x36, 0xb5, 0xd1, 0x42, 0x88, 0x53, 0x02, 0x8c, 0x12, 0xc9, 0xea, - 0x2e, 0xc9, 0xd9, 0x96, 0xdd, 0xb2, 0x59, 0x76, 0xc5, 0x5b, 0xf9, 0x40, 0xf9, 0x9f, 0x96, 0x6d, - 0xb7, 0x0c, 0x5c, 0x61, 0x51, 0xbd, 0x73, 0x5c, 0xd1, 0xac, 0x1e, 0xdf, 0xfa, 0x77, 0x78, 0x0b, - 0x9b, 0x0e, 0x0d, 0x36, 0x8b, 0xc3, 0x9b, 0xc7, 0x3a, 0x36, 0x9a, 0x47, 0xa6, 0x46, 0xda, 0x3c, - 0xa3, 0x30, 0x9c, 0x41, 0x75, 0x13, 0x13, 0xaa, 0x99, 0x8e, 0x9f, 0x50, 0xfa, 0x20, 0x42, 0x7a, - 0x33, 0xa0, 0x88, 0x72, 0x10, 0xd7, 0x9b, 0x92, 0x50, 0x14, 0xca, 0xe9, 0x9a, 0xd8, 0x3f, 0x2f, - 0xc4, 0xef, 0x6f, 0xa9, 0x71, 0xbd, 0x89, 0x0e, 0x40, 0x34, 0xb4, 0x3a, 0x36, 0x88, 0x14, 0x2f, - 0x26, 0xca, 0x99, 0xea, 0x8a, 0xf2, 0xd3, 0xa3, 0x2a, 0x83, 0xaa, 0xca, 0x1e, 0x83, 0x6e, 0x5b, - 0xd4, 0xed, 0xa9, 0xbc, 0x0e, 0xca, 0xc2, 0x9c, 0x6e, 0x6a, 0x2d, 0x2c, 0x25, 0xbc, 0x66, 0xaa, - 0x1f, 0xa0, 0x47, 0x90, 0x72, 0x3b, 0x96, 0xc7, 0x51, 0x4a, 0x16, 0x85, 0x72, 0xa6, 0x7a, 0x67, - 0xa6, 0x46, 0xaa, 0x8f, 0x55, 0x83, 0x22, 0xa8, 0x0c, 0x49, 0xe2, 0xe0, 0x86, 0x34, 0xc7, 0x8a, - 0x65, 0x15, 0x5f, 0x0d, 0x25, 0x50, 0x43, 0xd9, 0xb0, 0x7a, 0x2a, 0xcb, 0x40, 0x45, 0xc8, 0x10, - 0x4b, 0x73, 0xc8, 0x89, 0x4d, 0x29, 0x76, 0x25, 0x91, 0xb1, 0x8a, 0xfe, 0x84, 0x16, 0xe0, 0xb7, - 0x20, 0x3c, 0x6a, 0xe3, 0x9e, 0x94, 0xba, 0x9c, 0xf2, 0x10, 0xf7, 0xd0, 0x26, 0x40, 0xc3, 0xc5, - 0x1a, 0xc5, 0xcd, 0x23, 0x8d, 0x4a, 0xf3, 0xac, 0xa9, 0x3c, 0xd2, 0xf4, 0x71, 0x30, 0x82, 0xda, - 0xfc, 0xd9, 0x79, 0x21, 0xf6, 0xfe, 0x4b, 0x41, 0x50, 0xd3, 0x1c, 0xb7, 0x41, 0xbd, 0x22, 0x1d, - 0xa7, 0x19, 0x14, 0x49, 0xcf, 0x52, 0x84, 0xe3, 0x36, 0x28, 0xaa, 0x03, 0xe0, 0xd7, 0x14, 0x5b, - 0x44, 0xb7, 0x2d, 0x22, 0x01, 0x1b, 0xda, 0xbd, 0x99, 0xb4, 0xdc, 0x1e, 0xc0, 0xd9, 0xe0, 0x6a, - 0x49, 0xaf, 0x8d, 0x1a, 0xa9, 0x2a, 0xaf, 0x42, 0x26, 0x32, 0x59, 0xf4, 0x07, 0x24, 0x3c, 0x59, - 0xd8, 0xe5, 0x51, 0xbd, 0xa5, 0x37, 0xe3, 0xae, 0x66, 0x74, 0xb0, 0x14, 0xf7, 0x67, 0xcc, 0x82, - 0xb5, 0xf8, 0x8a, 0x20, 0xef, 0x43, 0x8a, 0xcf, 0x0a, 0x21, 0x48, 0x5a, 0x9a, 0x89, 0x39, 0x8e, - 0xad, 0x91, 0x02, 0x29, 0xdb, 0xa1, 0x8c, 0x7a, 0xfc, 0x07, 0x93, 0x0b, 0x92, 0xe4, 0x43, 0xf8, - 0x7d, 0x88, 0xee, 0x18, 0x36, 0xff, 0x45, 0xd9, 0x4c, 0x2a, 0x19, 0x72, 0x2c, 0xdd, 0x82, 0x3f, - 0x77, 0x31, 0x1d, 0x08, 0xa2, 0xe2, 0x57, 0x1d, 0x4c, 0xe8, 0x24, 0x8b, 0x94, 0x4e, 0x20, 0x7b, - 0x39, 0x9d, 0x38, 0xb6, 0x45, 0x30, 0x3a, 0x80, 0xf4, 0x40, 0x62, 0x06, 0xcb, 0x54, 0xff, 0x9f, - 0x65, 0x10, 0x5c, 0xf8, 0xb0, 0x48, 0x69, 0x09, 0xfe, 0xda, 0xd3, 0x49, 0xd8, 0x8a, 0x04, 0xd4, - 0x24, 0x48, 0x1d, 0xeb, 0x06, 0xc5, 0x2e, 0x91, 0x84, 0x62, 0xa2, 0x9c, 0x56, 0x83, 0xb0, 0x64, - 0x40, 0x6e, 0x18, 0xc2, 0xe9, 0xa9, 0x00, 0x61, 0x63, 0x06, 0xbb, 0x1a, 0xbf, 0x48, 0x95, 0xd2, - 0x4b, 0xc8, 0x6d, 0xb2, 0xeb, 0x3c, 0x22, 0xde, 0xaf, 0x17, 0xa3, 0x0d, 0x7f, 0x8f, 0xf4, 0xba, - 0x31, 0xe5, 0x3f, 0x0a, 0x90, 0x7b, 0xc2, 0x3c, 0x76, 0xf3, 0x27, 0x43, 0xeb, 0x90, 0xf1, 0xfd, - 0xcc, 0xde, 0x73, 0x7e, 0x6b, 0x47, 0x1f, 0x82, 0x1d, 0xef, 0xc9, 0xdf, 0xd7, 0x48, 0x5b, 0xe5, - 0xcf, 0x86, 0xb7, 0xf6, 0x64, 0x19, 0x21, 0x7a, 0x63, 0xb2, 0x2c, 0x42, 0x6e, 0x0b, 0x1b, 0x78, - 0x8c, 0x2a, 0x93, 0xcc, 0x52, 0x87, 0xec, 0xa5, 0xfb, 0xb8, 0x8f, 0x09, 0xf1, 0xde, 0xff, 0x07, - 0xd7, 0xe4, 0x16, 0x61, 0x55, 0xfd, 0x36, 0x07, 0x10, 0x5e, 0x78, 0xd4, 0x85, 0xc4, 0x2e, 0xa6, - 0xe8, 0xee, 0x14, 0xe5, 0xc6, 0xd8, 0x5e, 0x5e, 0x9e, 0x19, 0xc7, 0xe5, 0x7e, 0x03, 0x49, 0xef, - 0xa8, 0x68, 0x9a, 0xbf, 0xcc, 0xb1, 0xb6, 0x96, 0x57, 0xaf, 0x80, 0xe4, 0xcd, 0xdf, 0x09, 0x00, - 0xde, 0xd6, 0x21, 0x75, 0xb1, 0x66, 0x5e, 0x83, 0xc3, 0xf2, 0xac, 0x48, 0x3e, 0xd1, 0x45, 0x01, - 0x9d, 0x82, 0xe8, 0x3b, 0x14, 0x4d, 0x73, 0x90, 0xf1, 0x0f, 0x87, 0xbc, 0x76, 0x15, 0x28, 0x17, - 0xe1, 0x14, 0x44, 0xdf, 0x0b, 0x53, 0x11, 0x18, 0xef, 0xef, 0xa9, 0x08, 0x4c, 0x72, 0xdc, 0x73, - 0x10, 0x7d, 0x7f, 0x4c, 0x45, 0x60, 0xbc, 0x95, 0xe4, 0xdc, 0x88, 0xf3, 0xb7, 0xbd, 0x2f, 0xc1, - 0xda, 0x8b, 0xb3, 0x8b, 0x7c, 0xec, 0xf3, 0x45, 0x3e, 0xf6, 0xb6, 0x9f, 0x17, 0xce, 0xfa, 0x79, - 0xe1, 0x53, 0x3f, 0x2f, 0x7c, 0xed, 0xe7, 0x85, 0x67, 0x3b, 0xd7, 0xf8, 0xb8, 0x5d, 0x0f, 0xa3, - 0xa7, 0xb1, 0xba, 0xc8, 0x7a, 0xde, 0xfe, 0x1e, 0x00, 0x00, 0xff, 0xff, 0xd0, 0xae, 0xca, 0xcb, - 0x2f, 0x0b, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/containers/v1/containers.proto containerd-1.5.9/api/services/containers/v1/containers.proto --- containerd-1.2.6/api/services/containers/v1/containers.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/containers/v1/containers.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.containers.v1; diff -Nru containerd-1.2.6/api/services/content/v1/content.pb.go containerd-1.5.9/api/services/content/v1/content.pb.go --- containerd-1.2.6/api/services/content/v1/content.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/content/v1/content.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,56 +1,26 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/content/v1/content.proto -/* - Package content is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/content/v1/content.proto - - It has these top-level messages: - Info - InfoRequest - InfoResponse - UpdateRequest - UpdateResponse - ListContentRequest - ListContentResponse - DeleteContentRequest - ReadContentRequest - ReadContentResponse - Status - StatusRequest - StatusResponse - ListStatusesRequest - ListStatusesResponse - WriteContentRequest - WriteContentResponse - AbortRequest -*/ package content -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" -import google_protobuf3 "github.com/gogo/protobuf/types" - -import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" -import time "time" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -62,7 +32,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // WriteAction defines the behavior of a WriteRequest. type WriteAction int32 @@ -93,6 +63,7 @@ 1: "WRITE", 2: "COMMIT", } + var WriteAction_value = map[string]int32{ "STAT": 0, "WRITE": 1, @@ -102,7 +73,10 @@ func (x WriteAction) String() string { return proto.EnumName(WriteAction_name, int32(x)) } -func (WriteAction) EnumDescriptor() ([]byte, []int) { return fileDescriptorContent, []int{0} } + +func (WriteAction) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{0} +} type Info struct { // Digest is the hash identity of the blob. @@ -110,57 +84,212 @@ // Size is the total number of bytes in the blob. Size_ int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` // CreatedAt provides the time at which the blob was committed. - CreatedAt time.Time `protobuf:"bytes,3,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + CreatedAt time.Time `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` // UpdatedAt provides the time the info was last updated. - UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Info) Reset() { *m = Info{} } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{0} +} +func (m *Info) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Info.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Info) XXX_Merge(src proto.Message) { + xxx_messageInfo_Info.Merge(m, src) +} +func (m *Info) XXX_Size() int { + return m.Size() +} +func (m *Info) XXX_DiscardUnknown() { + xxx_messageInfo_Info.DiscardUnknown(m) } -func (m *Info) Reset() { *m = Info{} } -func (*Info) ProtoMessage() {} -func (*Info) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{0} } +var xxx_messageInfo_Info proto.InternalMessageInfo type InfoRequest struct { - Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InfoRequest) Reset() { *m = InfoRequest{} } +func (*InfoRequest) ProtoMessage() {} +func (*InfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{1} +} +func (m *InfoRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InfoRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_InfoRequest.Merge(m, src) +} +func (m *InfoRequest) XXX_Size() int { + return m.Size() +} +func (m *InfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_InfoRequest.DiscardUnknown(m) } -func (m *InfoRequest) Reset() { *m = InfoRequest{} } -func (*InfoRequest) ProtoMessage() {} -func (*InfoRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{1} } +var xxx_messageInfo_InfoRequest proto.InternalMessageInfo type InfoResponse struct { - Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InfoResponse) Reset() { *m = InfoResponse{} } +func (*InfoResponse) ProtoMessage() {} +func (*InfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{2} +} +func (m *InfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InfoResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_InfoResponse.Merge(m, src) +} +func (m *InfoResponse) XXX_Size() int { + return m.Size() +} +func (m *InfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_InfoResponse.DiscardUnknown(m) } -func (m *InfoResponse) Reset() { *m = InfoResponse{} } -func (*InfoResponse) ProtoMessage() {} -func (*InfoResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{2} } +var xxx_messageInfo_InfoResponse proto.InternalMessageInfo type UpdateRequest struct { - Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` // UpdateMask specifies which fields to perform the update on. If empty, // the operation applies to all fields. // // In info, Digest, Size, and CreatedAt are immutable, // other field may be updated using this mask. // If no mask is provided, all mutable field are updated. - UpdateMask *google_protobuf1.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` + UpdateMask *types.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateRequest) Reset() { *m = UpdateRequest{} } +func (*UpdateRequest) ProtoMessage() {} +func (*UpdateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{3} +} +func (m *UpdateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateRequest.Merge(m, src) +} +func (m *UpdateRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateRequest.DiscardUnknown(m) } -func (m *UpdateRequest) Reset() { *m = UpdateRequest{} } -func (*UpdateRequest) ProtoMessage() {} -func (*UpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{3} } +var xxx_messageInfo_UpdateRequest proto.InternalMessageInfo type UpdateResponse struct { - Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } +func (*UpdateResponse) ProtoMessage() {} +func (*UpdateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{4} +} +func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateResponse.Merge(m, src) +} +func (m *UpdateResponse) XXX_Size() int { + return m.Size() +} +func (m *UpdateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateResponse.DiscardUnknown(m) } -func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } -func (*UpdateResponse) ProtoMessage() {} -func (*UpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{4} } +var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo type ListContentRequest struct { // Filters contains one or more filters using the syntax defined in the @@ -173,29 +302,122 @@ // filters[0] or filters[1] or ... or filters[n-1] or filters[n] // // If filters is zero-length or nil, all items will be returned. - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListContentRequest) Reset() { *m = ListContentRequest{} } +func (*ListContentRequest) ProtoMessage() {} +func (*ListContentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{5} +} +func (m *ListContentRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListContentRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListContentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListContentRequest.Merge(m, src) +} +func (m *ListContentRequest) XXX_Size() int { + return m.Size() +} +func (m *ListContentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListContentRequest.DiscardUnknown(m) } -func (m *ListContentRequest) Reset() { *m = ListContentRequest{} } -func (*ListContentRequest) ProtoMessage() {} -func (*ListContentRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{5} } +var xxx_messageInfo_ListContentRequest proto.InternalMessageInfo type ListContentResponse struct { - Info []Info `protobuf:"bytes,1,rep,name=info" json:"info"` + Info []Info `protobuf:"bytes,1,rep,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListContentResponse) Reset() { *m = ListContentResponse{} } +func (*ListContentResponse) ProtoMessage() {} +func (*ListContentResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{6} +} +func (m *ListContentResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListContentResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListContentResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListContentResponse.Merge(m, src) +} +func (m *ListContentResponse) XXX_Size() int { + return m.Size() +} +func (m *ListContentResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListContentResponse.DiscardUnknown(m) } -func (m *ListContentResponse) Reset() { *m = ListContentResponse{} } -func (*ListContentResponse) ProtoMessage() {} -func (*ListContentResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{6} } +var xxx_messageInfo_ListContentResponse proto.InternalMessageInfo type DeleteContentRequest struct { // Digest specifies which content to delete. - Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteContentRequest) Reset() { *m = DeleteContentRequest{} } +func (*DeleteContentRequest) ProtoMessage() {} +func (*DeleteContentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{7} +} +func (m *DeleteContentRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteContentRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteContentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteContentRequest.Merge(m, src) +} +func (m *DeleteContentRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteContentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteContentRequest.DiscardUnknown(m) } -func (m *DeleteContentRequest) Reset() { *m = DeleteContentRequest{} } -func (*DeleteContentRequest) ProtoMessage() {} -func (*DeleteContentRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{7} } +var xxx_messageInfo_DeleteContentRequest proto.InternalMessageInfo // ReadContentRequest defines the fields that make up a request to read a portion of // data from a stored object. @@ -208,67 +430,284 @@ Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` // size is the total size of the read. If zero, the entire blob will be // returned by the service. - Size_ int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + Size_ int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadContentRequest) Reset() { *m = ReadContentRequest{} } +func (*ReadContentRequest) ProtoMessage() {} +func (*ReadContentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{8} +} +func (m *ReadContentRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReadContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReadContentRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReadContentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadContentRequest.Merge(m, src) +} +func (m *ReadContentRequest) XXX_Size() int { + return m.Size() +} +func (m *ReadContentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ReadContentRequest.DiscardUnknown(m) } -func (m *ReadContentRequest) Reset() { *m = ReadContentRequest{} } -func (*ReadContentRequest) ProtoMessage() {} -func (*ReadContentRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{8} } +var xxx_messageInfo_ReadContentRequest proto.InternalMessageInfo // ReadContentResponse carries byte data for a read request. type ReadContentResponse struct { - Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadContentResponse) Reset() { *m = ReadContentResponse{} } +func (*ReadContentResponse) ProtoMessage() {} +func (*ReadContentResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{9} +} +func (m *ReadContentResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ReadContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ReadContentResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ReadContentResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadContentResponse.Merge(m, src) +} +func (m *ReadContentResponse) XXX_Size() int { + return m.Size() +} +func (m *ReadContentResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ReadContentResponse.DiscardUnknown(m) } -func (m *ReadContentResponse) Reset() { *m = ReadContentResponse{} } -func (*ReadContentResponse) ProtoMessage() {} -func (*ReadContentResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{9} } +var xxx_messageInfo_ReadContentResponse proto.InternalMessageInfo type Status struct { - StartedAt time.Time `protobuf:"bytes,1,opt,name=started_at,json=startedAt,stdtime" json:"started_at"` - UpdatedAt time.Time `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` - Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` - Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` - Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"` - Expected github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=expected,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected"` + StartedAt time.Time `protobuf:"bytes,1,opt,name=started_at,json=startedAt,proto3,stdtime" json:"started_at"` + UpdatedAt time.Time `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` + Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"` + Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` + Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"` + Expected github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=expected,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Status) Reset() { *m = Status{} } +func (*Status) ProtoMessage() {} +func (*Status) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{10} +} +func (m *Status) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Status.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Status) XXX_Merge(src proto.Message) { + xxx_messageInfo_Status.Merge(m, src) +} +func (m *Status) XXX_Size() int { + return m.Size() +} +func (m *Status) XXX_DiscardUnknown() { + xxx_messageInfo_Status.DiscardUnknown(m) } -func (m *Status) Reset() { *m = Status{} } -func (*Status) ProtoMessage() {} -func (*Status) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{10} } +var xxx_messageInfo_Status proto.InternalMessageInfo type StatusRequest struct { - Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"` + Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatusRequest) Reset() { *m = StatusRequest{} } +func (*StatusRequest) ProtoMessage() {} +func (*StatusRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{11} +} +func (m *StatusRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatusRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatusRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatusRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatusRequest.Merge(m, src) +} +func (m *StatusRequest) XXX_Size() int { + return m.Size() +} +func (m *StatusRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StatusRequest.DiscardUnknown(m) } -func (m *StatusRequest) Reset() { *m = StatusRequest{} } -func (*StatusRequest) ProtoMessage() {} -func (*StatusRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{11} } +var xxx_messageInfo_StatusRequest proto.InternalMessageInfo type StatusResponse struct { - Status *Status `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"` + Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatusResponse) Reset() { *m = StatusResponse{} } +func (*StatusResponse) ProtoMessage() {} +func (*StatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{12} +} +func (m *StatusResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatusResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatusResponse.Merge(m, src) +} +func (m *StatusResponse) XXX_Size() int { + return m.Size() +} +func (m *StatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatusResponse.DiscardUnknown(m) } -func (m *StatusResponse) Reset() { *m = StatusResponse{} } -func (*StatusResponse) ProtoMessage() {} -func (*StatusResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{12} } +var xxx_messageInfo_StatusResponse proto.InternalMessageInfo type ListStatusesRequest struct { - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListStatusesRequest) Reset() { *m = ListStatusesRequest{} } +func (*ListStatusesRequest) ProtoMessage() {} +func (*ListStatusesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{13} +} +func (m *ListStatusesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListStatusesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListStatusesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListStatusesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListStatusesRequest.Merge(m, src) +} +func (m *ListStatusesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListStatusesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListStatusesRequest.DiscardUnknown(m) } -func (m *ListStatusesRequest) Reset() { *m = ListStatusesRequest{} } -func (*ListStatusesRequest) ProtoMessage() {} -func (*ListStatusesRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{13} } +var xxx_messageInfo_ListStatusesRequest proto.InternalMessageInfo type ListStatusesResponse struct { - Statuses []Status `protobuf:"bytes,1,rep,name=statuses" json:"statuses"` + Statuses []Status `protobuf:"bytes,1,rep,name=statuses,proto3" json:"statuses"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListStatusesResponse) Reset() { *m = ListStatusesResponse{} } +func (*ListStatusesResponse) ProtoMessage() {} +func (*ListStatusesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{14} +} +func (m *ListStatusesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListStatusesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListStatusesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListStatusesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListStatusesResponse.Merge(m, src) +} +func (m *ListStatusesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListStatusesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListStatusesResponse.DiscardUnknown(m) } -func (m *ListStatusesResponse) Reset() { *m = ListStatusesResponse{} } -func (*ListStatusesResponse) ProtoMessage() {} -func (*ListStatusesResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{14} } +var xxx_messageInfo_ListStatusesResponse proto.InternalMessageInfo // WriteContentRequest writes data to the request ref at offset. type WriteContentRequest struct { @@ -324,12 +763,43 @@ // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,7,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,7,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WriteContentRequest) Reset() { *m = WriteContentRequest{} } +func (*WriteContentRequest) ProtoMessage() {} +func (*WriteContentRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{15} +} +func (m *WriteContentRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WriteContentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WriteContentRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WriteContentRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WriteContentRequest.Merge(m, src) +} +func (m *WriteContentRequest) XXX_Size() int { + return m.Size() +} +func (m *WriteContentRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WriteContentRequest.DiscardUnknown(m) } -func (m *WriteContentRequest) Reset() { *m = WriteContentRequest{} } -func (*WriteContentRequest) ProtoMessage() {} -func (*WriteContentRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{15} } +var xxx_messageInfo_WriteContentRequest proto.InternalMessageInfo // WriteContentResponse is returned on the culmination of a write call. type WriteContentResponse struct { @@ -340,12 +810,12 @@ // // This must be set for stat and commit write actions. All other write // actions may omit this. - StartedAt time.Time `protobuf:"bytes,2,opt,name=started_at,json=startedAt,stdtime" json:"started_at"` + StartedAt time.Time `protobuf:"bytes,2,opt,name=started_at,json=startedAt,proto3,stdtime" json:"started_at"` // UpdatedAt provides the last time of a successful write. // // This must be set for stat and commit write actions. All other write // actions may omit this. - UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` // Offset is the current committed size for the write. Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` // Total provides the current, expected total size of the write. @@ -358,23 +828,87 @@ // Digest, if present, includes the digest up to the currently committed // bytes. If action is commit, this field will be set. It is implementation // defined if this is set for other actions. - Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WriteContentResponse) Reset() { *m = WriteContentResponse{} } +func (*WriteContentResponse) ProtoMessage() {} +func (*WriteContentResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{16} +} +func (m *WriteContentResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WriteContentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WriteContentResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WriteContentResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_WriteContentResponse.Merge(m, src) +} +func (m *WriteContentResponse) XXX_Size() int { + return m.Size() +} +func (m *WriteContentResponse) XXX_DiscardUnknown() { + xxx_messageInfo_WriteContentResponse.DiscardUnknown(m) } -func (m *WriteContentResponse) Reset() { *m = WriteContentResponse{} } -func (*WriteContentResponse) ProtoMessage() {} -func (*WriteContentResponse) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{16} } +var xxx_messageInfo_WriteContentResponse proto.InternalMessageInfo type AbortRequest struct { - Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"` + Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AbortRequest) Reset() { *m = AbortRequest{} } +func (*AbortRequest) ProtoMessage() {} +func (*AbortRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_468430ba3e400391, []int{17} +} +func (m *AbortRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AbortRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AbortRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AbortRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AbortRequest.Merge(m, src) +} +func (m *AbortRequest) XXX_Size() int { + return m.Size() +} +func (m *AbortRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AbortRequest.DiscardUnknown(m) } -func (m *AbortRequest) Reset() { *m = AbortRequest{} } -func (*AbortRequest) ProtoMessage() {} -func (*AbortRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{17} } +var xxx_messageInfo_AbortRequest proto.InternalMessageInfo func init() { + proto.RegisterEnum("containerd.services.content.v1.WriteAction", WriteAction_name, WriteAction_value) proto.RegisterType((*Info)(nil), "containerd.services.content.v1.Info") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.content.v1.Info.LabelsEntry") proto.RegisterType((*InfoRequest)(nil), "containerd.services.content.v1.InfoRequest") proto.RegisterType((*InfoResponse)(nil), "containerd.services.content.v1.InfoResponse") proto.RegisterType((*UpdateRequest)(nil), "containerd.services.content.v1.UpdateRequest") @@ -390,9 +924,85 @@ proto.RegisterType((*ListStatusesRequest)(nil), "containerd.services.content.v1.ListStatusesRequest") proto.RegisterType((*ListStatusesResponse)(nil), "containerd.services.content.v1.ListStatusesResponse") proto.RegisterType((*WriteContentRequest)(nil), "containerd.services.content.v1.WriteContentRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.content.v1.WriteContentRequest.LabelsEntry") proto.RegisterType((*WriteContentResponse)(nil), "containerd.services.content.v1.WriteContentResponse") proto.RegisterType((*AbortRequest)(nil), "containerd.services.content.v1.AbortRequest") - proto.RegisterEnum("containerd.services.content.v1.WriteAction", WriteAction_name, WriteAction_value) +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/content/v1/content.proto", fileDescriptor_468430ba3e400391) +} + +var fileDescriptor_468430ba3e400391 = []byte{ + // 1081 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0x78, 0xed, 0x4d, 0xf2, 0x9c, 0x16, 0x33, 0x31, 0x95, 0xb5, 0x08, 0x67, 0xbb, 0x42, + 0xc8, 0x6a, 0xc9, 0x3a, 0x75, 0x7a, 0x00, 0x2a, 0x01, 0x8e, 0x9b, 0xaa, 0x41, 0x4d, 0x41, 0x5b, + 0x97, 0x40, 0x2f, 0x65, 0x6d, 0x8f, 0xcd, 0x2a, 0xb6, 0xd7, 0xdd, 0x19, 0x5b, 0x84, 0x13, 0x17, + 0x24, 0x14, 0xf5, 0x80, 0xb8, 0xe7, 0x02, 0xfc, 0x15, 0x1c, 0x38, 0xe7, 0xc8, 0x11, 0x71, 0x68, + 0x69, 0xfe, 0x07, 0xee, 0x68, 0x66, 0x67, 0xed, 0xf5, 0x47, 0x58, 0xdb, 0x31, 0x27, 0xbf, 0x99, + 0x7d, 0xbf, 0xf7, 0xfd, 0x31, 0x86, 0x7b, 0x4d, 0x87, 0x7d, 0xdd, 0xab, 0x9a, 0x35, 0xb7, 0x5d, + 0xa8, 0xb9, 0x1d, 0x66, 0x3b, 0x1d, 0xe2, 0xd5, 0xc3, 0xa4, 0xdd, 0x75, 0x0a, 0x94, 0x78, 0x7d, + 0xa7, 0x46, 0xa8, 0xb8, 0x27, 0x1d, 0x56, 0xe8, 0xdf, 0x0a, 0x48, 0xb3, 0xeb, 0xb9, 0xcc, 0xc5, + 0xb9, 0x21, 0xc2, 0x0c, 0xb8, 0xcd, 0x80, 0xa5, 0x7f, 0x4b, 0xcb, 0x34, 0xdd, 0xa6, 0x2b, 0x58, + 0x0b, 0x9c, 0xf2, 0x51, 0x9a, 0xde, 0x74, 0xdd, 0x66, 0x8b, 0x14, 0xc4, 0xa9, 0xda, 0x6b, 0x14, + 0x1a, 0x0e, 0x69, 0xd5, 0x9f, 0xb6, 0x6d, 0x7a, 0x24, 0x39, 0x36, 0xc7, 0x39, 0x98, 0xd3, 0x26, + 0x94, 0xd9, 0xed, 0xae, 0x64, 0x78, 0x73, 0x9c, 0x81, 0xb4, 0xbb, 0xec, 0xd8, 0xff, 0x68, 0xfc, + 0x13, 0x87, 0xc4, 0x7e, 0xa7, 0xe1, 0xe2, 0x4f, 0x40, 0xad, 0x3b, 0x4d, 0x42, 0x59, 0x16, 0xe9, + 0x28, 0xbf, 0xb6, 0x5b, 0x3c, 0x7b, 0xb1, 0x19, 0xfb, 0xeb, 0xc5, 0xe6, 0x8d, 0x90, 0xfb, 0x6e, + 0x97, 0x74, 0x06, 0x5e, 0xd0, 0x42, 0xd3, 0xdd, 0xf2, 0x21, 0xe6, 0x5d, 0xf1, 0x63, 0x49, 0x09, + 0x18, 0x43, 0x82, 0x3a, 0xdf, 0x92, 0x6c, 0x5c, 0x47, 0x79, 0xc5, 0x12, 0x34, 0x2e, 0x03, 0xd4, + 0x3c, 0x62, 0x33, 0x52, 0x7f, 0x6a, 0xb3, 0xac, 0xa2, 0xa3, 0x7c, 0xaa, 0xa8, 0x99, 0xbe, 0x69, + 0x66, 0x60, 0x9a, 0x59, 0x09, 0x6c, 0xdf, 0x5d, 0xe5, 0xfa, 0x7f, 0x7c, 0xb9, 0x89, 0xac, 0x35, + 0x89, 0x2b, 0x31, 0x2e, 0xa4, 0xd7, 0xad, 0x07, 0x42, 0x12, 0xf3, 0x08, 0x91, 0xb8, 0x12, 0xc3, + 0xf7, 0x41, 0x6d, 0xd9, 0x55, 0xd2, 0xa2, 0xd9, 0xa4, 0xae, 0xe4, 0x53, 0xc5, 0x6d, 0xf3, 0xbf, + 0x33, 0x63, 0xf2, 0xf8, 0x98, 0x0f, 0x04, 0x64, 0xaf, 0xc3, 0xbc, 0x63, 0x4b, 0xe2, 0xb5, 0xf7, + 0x21, 0x15, 0xba, 0xc6, 0x69, 0x50, 0x8e, 0xc8, 0xb1, 0x1f, 0x3f, 0x8b, 0x93, 0x38, 0x03, 0xc9, + 0xbe, 0xdd, 0xea, 0xf9, 0x91, 0x58, 0xb3, 0xfc, 0xc3, 0x07, 0xf1, 0xf7, 0x90, 0xf1, 0x25, 0xa4, + 0xb8, 0x58, 0x8b, 0x3c, 0xeb, 0xf1, 0x88, 0x2d, 0x31, 0xfa, 0xc6, 0x43, 0x58, 0xf7, 0x45, 0xd3, + 0xae, 0xdb, 0xa1, 0x04, 0x7f, 0x08, 0x09, 0xa7, 0xd3, 0x70, 0x85, 0xe4, 0x54, 0xf1, 0xed, 0x59, + 0xbc, 0xdd, 0x4d, 0x70, 0xfd, 0x96, 0xc0, 0x19, 0xcf, 0x11, 0x5c, 0x79, 0x2c, 0xa2, 0x17, 0x58, + 0x7b, 0x49, 0x89, 0xf8, 0x0e, 0xa4, 0xfc, 0x74, 0x88, 0x3a, 0x16, 0xc1, 0x99, 0x96, 0xc7, 0x7b, + 0xbc, 0xd4, 0x0f, 0x6c, 0x7a, 0x64, 0xc9, 0xac, 0x73, 0xda, 0xf8, 0x0c, 0xae, 0x06, 0xd6, 0x2c, + 0xc9, 0x41, 0x13, 0xf0, 0x03, 0x87, 0xb2, 0xb2, 0xcf, 0x12, 0x38, 0x99, 0x85, 0x95, 0x86, 0xd3, + 0x62, 0xc4, 0xa3, 0x59, 0xa4, 0x2b, 0xf9, 0x35, 0x2b, 0x38, 0x1a, 0x8f, 0x61, 0x63, 0x84, 0x7f, + 0xc2, 0x0c, 0x65, 0x21, 0x33, 0xaa, 0x90, 0xb9, 0x4b, 0x5a, 0x84, 0x91, 0x31, 0x43, 0x96, 0x59, + 0x1b, 0xcf, 0x11, 0x60, 0x8b, 0xd8, 0xf5, 0xff, 0x4f, 0x05, 0xbe, 0x06, 0xaa, 0xdb, 0x68, 0x50, + 0xc2, 0x64, 0xfb, 0xcb, 0xd3, 0x60, 0x28, 0x28, 0xc3, 0xa1, 0x60, 0x94, 0x60, 0x63, 0xc4, 0x1a, + 0x19, 0xc9, 0xa1, 0x08, 0x34, 0x2e, 0xa2, 0x6e, 0x33, 0x5b, 0x08, 0x5e, 0xb7, 0x04, 0x6d, 0xfc, + 0x1c, 0x07, 0xf5, 0x11, 0xb3, 0x59, 0x8f, 0xf2, 0xe9, 0x40, 0x99, 0xed, 0xc9, 0xe9, 0x80, 0xe6, + 0x99, 0x0e, 0x12, 0x37, 0x31, 0x62, 0xe2, 0x8b, 0x8d, 0x98, 0x34, 0x28, 0x1e, 0x69, 0x08, 0x57, + 0xd7, 0x2c, 0x4e, 0x86, 0x5c, 0x4a, 0x8c, 0xb8, 0x94, 0x81, 0x24, 0x73, 0x99, 0xdd, 0xca, 0x26, + 0xc5, 0xb5, 0x7f, 0xc0, 0x0f, 0x61, 0x95, 0x7c, 0xd3, 0x25, 0x35, 0x46, 0xea, 0x59, 0x75, 0xe1, + 0x8c, 0x0c, 0x64, 0x18, 0xd7, 0xe1, 0x8a, 0x1f, 0xa3, 0x20, 0xe1, 0xd2, 0x40, 0x34, 0x30, 0x90, + 0xb7, 0x55, 0xc0, 0x32, 0xa8, 0x67, 0x95, 0x8a, 0x1b, 0x19, 0xca, 0x77, 0xa2, 0x2a, 0x5a, 0xe2, + 0x25, 0xca, 0x28, 0xf8, 0x6d, 0xe2, 0xdf, 0x12, 0x1a, 0xdd, 0x57, 0x5f, 0x41, 0x66, 0x14, 0x20, + 0x0d, 0xb9, 0x0f, 0xab, 0x54, 0xde, 0xc9, 0xe6, 0x9a, 0xd1, 0x14, 0xd9, 0x5e, 0x03, 0xb4, 0xf1, + 0x93, 0x02, 0x1b, 0x87, 0x9e, 0x33, 0xd1, 0x62, 0x65, 0x50, 0xed, 0x1a, 0x73, 0xdc, 0x8e, 0x70, + 0xf5, 0x6a, 0xf1, 0x66, 0x94, 0x7c, 0x21, 0xa4, 0x24, 0x20, 0x96, 0x84, 0x06, 0x31, 0x8d, 0x0f, + 0x93, 0x3e, 0x48, 0xae, 0x72, 0x51, 0x72, 0x13, 0x97, 0x4f, 0x6e, 0xa8, 0xb4, 0x92, 0x53, 0xbb, + 0x45, 0x1d, 0x76, 0x0b, 0x3e, 0x1c, 0xec, 0xbe, 0x15, 0x11, 0xc8, 0x8f, 0x66, 0x72, 0x74, 0x34, + 0x5a, 0xcb, 0x5e, 0x85, 0x2f, 0xe3, 0x90, 0x19, 0x55, 0x23, 0xf3, 0xbe, 0x94, 0xac, 0x8c, 0x0e, + 0x85, 0xf8, 0x32, 0x86, 0x82, 0xb2, 0xd8, 0x50, 0x98, 0x6f, 0x04, 0x0c, 0x47, 0xb2, 0x7a, 0xe9, + 0xa9, 0xaf, 0xc3, 0x7a, 0xa9, 0xea, 0x7a, 0xec, 0xc2, 0xee, 0xbf, 0xf1, 0x3d, 0x82, 0x54, 0x28, + 0x7a, 0xf8, 0x2d, 0x48, 0x3c, 0xaa, 0x94, 0x2a, 0xe9, 0x98, 0xb6, 0x71, 0x72, 0xaa, 0xbf, 0x16, + 0xfa, 0xc4, 0x3b, 0x0b, 0x6f, 0x42, 0xf2, 0xd0, 0xda, 0xaf, 0xec, 0xa5, 0x91, 0x96, 0x39, 0x39, + 0xd5, 0xd3, 0xa1, 0xef, 0x82, 0xc4, 0xd7, 0x41, 0x2d, 0x7f, 0x7a, 0x70, 0xb0, 0x5f, 0x49, 0xc7, + 0xb5, 0x37, 0x4e, 0x4e, 0xf5, 0xd7, 0x43, 0x1c, 0x65, 0xb7, 0xdd, 0x76, 0x98, 0xb6, 0xf1, 0xc3, + 0x2f, 0xb9, 0xd8, 0x6f, 0xbf, 0xe6, 0xc2, 0x7a, 0x8b, 0xbf, 0xaf, 0xc0, 0x8a, 0x2c, 0x03, 0x6c, + 0xcb, 0x97, 0xe9, 0xcd, 0x59, 0x36, 0xa9, 0x74, 0x4d, 0x7b, 0x77, 0x36, 0x66, 0x59, 0x61, 0x4d, + 0x50, 0xfd, 0xb7, 0x04, 0xde, 0x8a, 0xc2, 0x8d, 0xbc, 0x80, 0x34, 0x73, 0x56, 0x76, 0xa9, 0xe8, + 0x19, 0x24, 0xf8, 0x68, 0xc3, 0xc5, 0x28, 0xdc, 0xe4, 0x43, 0x44, 0xdb, 0x99, 0x0b, 0xe3, 0x2b, + 0xdc, 0x46, 0xf8, 0x73, 0x50, 0xfd, 0xe7, 0x04, 0xbe, 0x1d, 0x25, 0x60, 0xda, 0xb3, 0x43, 0xbb, + 0x36, 0x51, 0xdf, 0x7b, 0xfc, 0x7f, 0x03, 0x77, 0x85, 0xef, 0xec, 0x68, 0x57, 0x26, 0xdf, 0x19, + 0xd1, 0xae, 0x4c, 0x79, 0x0d, 0x6c, 0x23, 0x9e, 0x26, 0xb9, 0xe2, 0xb7, 0x66, 0xdc, 0x41, 0xb3, + 0xa6, 0x69, 0x6c, 0xe5, 0x1d, 0xc3, 0x7a, 0x78, 0x03, 0xe1, 0x99, 0x42, 0x3f, 0xb6, 0xe0, 0xb4, + 0xdb, 0xf3, 0x81, 0xa4, 0xea, 0x3e, 0x24, 0xfd, 0xd6, 0xd9, 0x59, 0x60, 0x24, 0x47, 0xeb, 0x9c, + 0x36, 0x60, 0xf3, 0x68, 0x1b, 0xe1, 0x03, 0x48, 0x8a, 0xd9, 0x80, 0x23, 0x3b, 0x27, 0x3c, 0x42, + 0x2e, 0xaa, 0x8e, 0xdd, 0x27, 0x67, 0xaf, 0x72, 0xb1, 0x3f, 0x5f, 0xe5, 0x62, 0xdf, 0x9d, 0xe7, + 0xd0, 0xd9, 0x79, 0x0e, 0xfd, 0x71, 0x9e, 0x43, 0x7f, 0x9f, 0xe7, 0xd0, 0x93, 0x8f, 0x17, 0xfd, + 0x1f, 0x7d, 0x47, 0x92, 0x5f, 0xc4, 0xaa, 0xaa, 0xd0, 0xb6, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xc0, 0xc2, 0x35, 0xb1, 0x94, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -403,8 +1013,9 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Content service - +// ContentClient is the client API for Content service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type ContentClient interface { // Info returns information about a committed object. // @@ -425,7 +1036,7 @@ // set. List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error) // Delete will delete the referenced object. - Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*google_protobuf3.Empty, error) + Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*types.Empty, error) // Read allows one to read an object based on the offset into the content. // // The requested data may be returned in one or more messages. @@ -458,7 +1069,7 @@ Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error) // Abort cancels the ongoing write named in the request. Any resources // associated with the write will be collected. - Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*google_protobuf3.Empty, error) + Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*types.Empty, error) } type contentClient struct { @@ -471,7 +1082,7 @@ func (c *contentClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) { out := new(InfoResponse) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/Info", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Info", in, out, opts...) if err != nil { return nil, err } @@ -480,7 +1091,7 @@ func (c *contentClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error) { out := new(UpdateResponse) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/Update", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Update", in, out, opts...) if err != nil { return nil, err } @@ -488,7 +1099,7 @@ } func (c *contentClient) List(ctx context.Context, in *ListContentRequest, opts ...grpc.CallOption) (Content_ListClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Content_serviceDesc.Streams[0], c.cc, "/containerd.services.content.v1.Content/List", opts...) + stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[0], "/containerd.services.content.v1.Content/List", opts...) if err != nil { return nil, err } @@ -519,9 +1130,9 @@ return m, nil } -func (c *contentClient) Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*google_protobuf3.Empty, error) { - out := new(google_protobuf3.Empty) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/Delete", in, out, c.cc, opts...) +func (c *contentClient) Delete(ctx context.Context, in *DeleteContentRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Delete", in, out, opts...) if err != nil { return nil, err } @@ -529,7 +1140,7 @@ } func (c *contentClient) Read(ctx context.Context, in *ReadContentRequest, opts ...grpc.CallOption) (Content_ReadClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Content_serviceDesc.Streams[1], c.cc, "/containerd.services.content.v1.Content/Read", opts...) + stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[1], "/containerd.services.content.v1.Content/Read", opts...) if err != nil { return nil, err } @@ -562,7 +1173,7 @@ func (c *contentClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) { out := new(StatusResponse) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/Status", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Status", in, out, opts...) if err != nil { return nil, err } @@ -571,7 +1182,7 @@ func (c *contentClient) ListStatuses(ctx context.Context, in *ListStatusesRequest, opts ...grpc.CallOption) (*ListStatusesResponse, error) { out := new(ListStatusesResponse) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/ListStatuses", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/ListStatuses", in, out, opts...) if err != nil { return nil, err } @@ -579,7 +1190,7 @@ } func (c *contentClient) Write(ctx context.Context, opts ...grpc.CallOption) (Content_WriteClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Content_serviceDesc.Streams[2], c.cc, "/containerd.services.content.v1.Content/Write", opts...) + stream, err := c.cc.NewStream(ctx, &_Content_serviceDesc.Streams[2], "/containerd.services.content.v1.Content/Write", opts...) if err != nil { return nil, err } @@ -609,17 +1220,16 @@ return m, nil } -func (c *contentClient) Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*google_protobuf3.Empty, error) { - out := new(google_protobuf3.Empty) - err := grpc.Invoke(ctx, "/containerd.services.content.v1.Content/Abort", in, out, c.cc, opts...) +func (c *contentClient) Abort(ctx context.Context, in *AbortRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.content.v1.Content/Abort", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Content service - +// ContentServer is the server API for Content service. type ContentServer interface { // Info returns information about a committed object. // @@ -640,7 +1250,7 @@ // set. List(*ListContentRequest, Content_ListServer) error // Delete will delete the referenced object. - Delete(context.Context, *DeleteContentRequest) (*google_protobuf3.Empty, error) + Delete(context.Context, *DeleteContentRequest) (*types.Empty, error) // Read allows one to read an object based on the offset into the content. // // The requested data may be returned in one or more messages. @@ -673,7 +1283,39 @@ Write(Content_WriteServer) error // Abort cancels the ongoing write named in the request. Any resources // associated with the write will be collected. - Abort(context.Context, *AbortRequest) (*google_protobuf3.Empty, error) + Abort(context.Context, *AbortRequest) (*types.Empty, error) +} + +// UnimplementedContentServer can be embedded to have forward compatible implementations. +type UnimplementedContentServer struct { +} + +func (*UnimplementedContentServer) Info(ctx context.Context, req *InfoRequest) (*InfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Info not implemented") +} +func (*UnimplementedContentServer) Update(ctx context.Context, req *UpdateRequest) (*UpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedContentServer) List(req *ListContentRequest, srv Content_ListServer) error { + return status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedContentServer) Delete(ctx context.Context, req *DeleteContentRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") +} +func (*UnimplementedContentServer) Read(req *ReadContentRequest, srv Content_ReadServer) error { + return status.Errorf(codes.Unimplemented, "method Read not implemented") +} +func (*UnimplementedContentServer) Status(ctx context.Context, req *StatusRequest) (*StatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") +} +func (*UnimplementedContentServer) ListStatuses(ctx context.Context, req *ListStatusesRequest) (*ListStatusesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListStatuses not implemented") +} +func (*UnimplementedContentServer) Write(srv Content_WriteServer) error { + return status.Errorf(codes.Unimplemented, "method Write not implemented") +} +func (*UnimplementedContentServer) Abort(ctx context.Context, req *AbortRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Abort not implemented") } func RegisterContentServer(s *grpc.Server, srv ContentServer) { @@ -909,7 +1551,7 @@ func (m *Info) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -917,61 +1559,73 @@ } func (m *Info) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Info) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Digest) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if m.Size_ != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Size_)) - } - dAtA[i] = 0x1a - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt))) - n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - dAtA[i] = 0x22 - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n2, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x2a - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v))) - i = encodeVarintContent(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintContent(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintContent(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintContent(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a } } - return i, nil + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintContent(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x22 + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintContent(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x1a + if m.Size_ != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x10 + } + if len(m.Digest) > 0 { + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) + i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *InfoRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -979,23 +1633,33 @@ } func (m *InfoRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InfoRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Digest) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *InfoResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1003,25 +1667,36 @@ } func (m *InfoResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Info.Size())) - n3, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n3 - return i, nil + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1029,35 +1704,48 @@ } func (m *UpdateRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Info.Size())) - n4, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n4 if m.UpdateMask != nil { + { + size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.UpdateMask.Size())) - n5, err := m.UpdateMask.MarshalTo(dAtA[i:]) + } + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n5 + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) } - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1065,25 +1753,36 @@ } func (m *UpdateResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Info.Size())) - n6, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n6 - return i, nil + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ListContentRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1091,32 +1790,35 @@ } func (m *ListContentRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintContent(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *ListContentResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1124,29 +1826,40 @@ } func (m *ListContentResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Info) > 0 { - for _, msg := range m.Info { - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Info) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Info[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteContentRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1154,23 +1867,33 @@ } func (m *DeleteContentRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Digest) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ReadContentRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1178,33 +1901,43 @@ } func (m *ReadContentRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReadContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Digest) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Size_ != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x18 } if m.Offset != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x10 } - if m.Size_ != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Size_)) + if len(m.Digest) > 0 { + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) + i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ReadContentResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1212,28 +1945,38 @@ } func (m *ReadContentResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ReadContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Offset != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Data) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Data) + copy(dAtA[i:], m.Data) i = encodeVarintContent(dAtA, i, uint64(len(m.Data))) - i += copy(dAtA[i:], m.Data) + i-- + dAtA[i] = 0x12 } - return i, nil + if m.Offset != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil } func (m *Status) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1241,55 +1984,66 @@ } func (m *Status) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.StartedAt))) - n7, err := types.StdTimeMarshalTo(m.StartedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n7 - dAtA[i] = 0x12 - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n8, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.Expected) > 0 { + i -= len(m.Expected) + copy(dAtA[i:], m.Expected) + i = encodeVarintContent(dAtA, i, uint64(len(m.Expected))) + i-- + dAtA[i] = 0x32 } - i += n8 - if len(m.Ref) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) - i += copy(dAtA[i:], m.Ref) + if m.Total != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Total)) + i-- + dAtA[i] = 0x28 } if m.Offset != 0 { - dAtA[i] = 0x20 - i++ i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x20 } - if m.Total != 0 { - dAtA[i] = 0x28 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Total)) - } - if len(m.Expected) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Expected))) - i += copy(dAtA[i:], m.Expected) + if len(m.Ref) > 0 { + i -= len(m.Ref) + copy(dAtA[i:], m.Ref) + i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) + i-- + dAtA[i] = 0x1a } - return i, nil + n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err7 != nil { + return 0, err7 + } + i -= n7 + i = encodeVarintContent(dAtA, i, uint64(n7)) + i-- + dAtA[i] = 0x12 + n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt):]) + if err8 != nil { + return 0, err8 + } + i -= n8 + i = encodeVarintContent(dAtA, i, uint64(n8)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *StatusRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1297,23 +2051,33 @@ } func (m *StatusRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatusRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Ref) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Ref) + copy(dAtA[i:], m.Ref) i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) - i += copy(dAtA[i:], m.Ref) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StatusResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1321,27 +2085,38 @@ } func (m *StatusResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatusResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Status != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Status.Size())) - n9, err := m.Status.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Status.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) } - i += n9 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListStatusesRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1349,32 +2124,35 @@ } func (m *ListStatusesRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListStatusesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintContent(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *ListStatusesResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1382,29 +2160,40 @@ } func (m *ListStatusesResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListStatusesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Statuses) > 0 { - for _, msg := range m.Statuses { - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Statuses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Statuses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintContent(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *WriteContentRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1412,67 +2201,81 @@ } func (m *WriteContentRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WriteContentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Action != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Action)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Ref) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) - i += copy(dAtA[i:], m.Ref) + if len(m.Labels) > 0 { + for k := range m.Labels { + v := m.Labels[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintContent(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintContent(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintContent(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x3a + } } - if m.Total != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Total)) + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintContent(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x32 + } + if m.Offset != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x28 } if len(m.Expected) > 0 { - dAtA[i] = 0x22 - i++ + i -= len(m.Expected) + copy(dAtA[i:], m.Expected) i = encodeVarintContent(dAtA, i, uint64(len(m.Expected))) - i += copy(dAtA[i:], m.Expected) + i-- + dAtA[i] = 0x22 } - if m.Offset != 0 { - dAtA[i] = 0x28 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + if m.Total != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Total)) + i-- + dAtA[i] = 0x18 } - if len(m.Data) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Data))) - i += copy(dAtA[i:], m.Data) + if len(m.Ref) > 0 { + i -= len(m.Ref) + copy(dAtA[i:], m.Ref) + i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) + i-- + dAtA[i] = 0x12 } - if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x3a - i++ - v := m.Labels[k] - mapSize := 1 + len(k) + sovContent(uint64(len(k))) + 1 + len(v) + sovContent(uint64(len(v))) - i = encodeVarintContent(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintContent(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ - i = encodeVarintContent(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) - } + if m.Action != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Action)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *WriteContentResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1480,54 +2283,64 @@ } func (m *WriteContentResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WriteContentResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Action != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Action)) - } - dAtA[i] = 0x12 - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.StartedAt))) - n10, err := types.StdTimeMarshalTo(m.StartedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n10 - dAtA[i] = 0x1a - i++ - i = encodeVarintContent(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n11, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n11 - if m.Offset != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + if len(m.Digest) > 0 { + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) + i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) + i-- + dAtA[i] = 0x32 } if m.Total != 0 { - dAtA[i] = 0x28 - i++ i = encodeVarintContent(dAtA, i, uint64(m.Total)) + i-- + dAtA[i] = 0x28 } - if len(m.Digest) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintContent(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + if m.Offset != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x20 + } + n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err10 != nil { + return 0, err10 + } + i -= n10 + i = encodeVarintContent(dAtA, i, uint64(n10)) + i-- + dAtA[i] = 0x1a + n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt):]) + if err11 != nil { + return 0, err11 + } + i -= n11 + i = encodeVarintContent(dAtA, i, uint64(n11)) + i-- + dAtA[i] = 0x12 + if m.Action != 0 { + i = encodeVarintContent(dAtA, i, uint64(m.Action)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *AbortRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1535,29 +2348,44 @@ } func (m *AbortRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AbortRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Ref) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Ref) + copy(dAtA[i:], m.Ref) i = encodeVarintContent(dAtA, i, uint64(len(m.Ref))) - i += copy(dAtA[i:], m.Ref) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintContent(dAtA []byte, offset int, v uint64) int { + offset -= sovContent(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Info) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Digest) @@ -1567,9 +2395,9 @@ if m.Size_ != 0 { n += 1 + sovContent(uint64(m.Size_)) } - l = types.SizeOfStdTime(m.CreatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovContent(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovContent(uint64(l)) if len(m.Labels) > 0 { for k, v := range m.Labels { @@ -1579,28 +2407,46 @@ n += mapEntrySize + 1 + sovContent(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *InfoRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Digest) if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *InfoResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Info.Size() n += 1 + l + sovContent(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Info.Size() @@ -1609,18 +2455,30 @@ l = m.UpdateMask.Size() n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Info.Size() n += 1 + l + sovContent(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListContentRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -1629,10 +2487,16 @@ n += 1 + l + sovContent(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListContentResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Info) > 0 { @@ -1641,20 +2505,32 @@ n += 1 + l + sovContent(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteContentRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Digest) if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ReadContentRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Digest) @@ -1667,10 +2543,16 @@ if m.Size_ != 0 { n += 1 + sovContent(uint64(m.Size_)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ReadContentResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Offset != 0 { @@ -1680,15 +2562,21 @@ if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *Status) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l - l = types.SizeOfStdTime(m.StartedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt) n += 1 + l + sovContent(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovContent(uint64(l)) l = len(m.Ref) if l > 0 { @@ -1704,30 +2592,48 @@ if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatusRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Ref) if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatusResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Status != nil { l = m.Status.Size() n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListStatusesRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -1736,10 +2642,16 @@ n += 1 + l + sovContent(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListStatusesResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Statuses) > 0 { @@ -1748,10 +2660,16 @@ n += 1 + l + sovContent(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WriteContentRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Action != 0 { @@ -1783,18 +2701,24 @@ n += mapEntrySize + 1 + sovContent(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WriteContentResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Action != 0 { n += 1 + sovContent(uint64(m.Action)) } - l = types.SizeOfStdTime(m.StartedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt) n += 1 + l + sovContent(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovContent(uint64(l)) if m.Offset != 0 { n += 1 + sovContent(uint64(m.Offset)) @@ -1806,28 +2730,30 @@ if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *AbortRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Ref) if l > 0 { n += 1 + l + sovContent(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovContent(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozContent(x uint64) (n int) { return sovContent(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1840,7 +2766,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1849,9 +2775,10 @@ s := strings.Join([]string{`&Info{`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, - `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1862,6 +2789,7 @@ } s := strings.Join([]string{`&InfoRequest{`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1872,6 +2800,7 @@ } s := strings.Join([]string{`&InfoResponse{`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1882,7 +2811,8 @@ } s := strings.Join([]string{`&UpdateRequest{`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, - `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf1.FieldMask", 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types.FieldMask", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1893,6 +2823,7 @@ } s := strings.Join([]string{`&UpdateResponse{`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1903,6 +2834,7 @@ } s := strings.Join([]string{`&ListContentRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1911,8 +2843,14 @@ if this == nil { return "nil" } + repeatedStringForInfo := "[]Info{" + for _, f := range this.Info { + repeatedStringForInfo += strings.Replace(strings.Replace(f.String(), "Info", "Info", 1), `&`, ``, 1) + "," + } + repeatedStringForInfo += "}" s := strings.Join([]string{`&ListContentResponse{`, - `Info:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Info), "Info", "Info", 1), `&`, ``, 1) + `,`, + `Info:` + repeatedStringForInfo + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1923,6 +2861,7 @@ } s := strings.Join([]string{`&DeleteContentRequest{`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1935,6 +2874,7 @@ `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1946,6 +2886,7 @@ s := strings.Join([]string{`&ReadContentResponse{`, `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Data:` + fmt.Sprintf("%v", this.Data) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1955,12 +2896,13 @@ return "nil" } s := strings.Join([]string{`&Status{`, - `StartedAt:` + strings.Replace(strings.Replace(this.StartedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `StartedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StartedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Total:` + fmt.Sprintf("%v", this.Total) + `,`, `Expected:` + fmt.Sprintf("%v", this.Expected) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1971,6 +2913,7 @@ } s := strings.Join([]string{`&StatusRequest{`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1980,7 +2923,8 @@ return "nil" } s := strings.Join([]string{`&StatusResponse{`, - `Status:` + strings.Replace(fmt.Sprintf("%v", this.Status), "Status", "Status", 1) + `,`, + `Status:` + strings.Replace(this.Status.String(), "Status", "Status", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1991,6 +2935,7 @@ } s := strings.Join([]string{`&ListStatusesRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1999,8 +2944,14 @@ if this == nil { return "nil" } + repeatedStringForStatuses := "[]Status{" + for _, f := range this.Statuses { + repeatedStringForStatuses += strings.Replace(strings.Replace(f.String(), "Status", "Status", 1), `&`, ``, 1) + "," + } + repeatedStringForStatuses += "}" s := strings.Join([]string{`&ListStatusesResponse{`, - `Statuses:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Statuses), "Status", "Status", 1), `&`, ``, 1) + `,`, + `Statuses:` + repeatedStringForStatuses + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2013,7 +2964,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -2027,6 +2978,7 @@ `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Data:` + fmt.Sprintf("%v", this.Data) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2037,11 +2989,12 @@ } s := strings.Join([]string{`&WriteContentResponse{`, `Action:` + fmt.Sprintf("%v", this.Action) + `,`, - `StartedAt:` + strings.Replace(strings.Replace(this.StartedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `StartedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StartedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Offset:` + fmt.Sprintf("%v", this.Offset) + `,`, `Total:` + fmt.Sprintf("%v", this.Total) + `,`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2052,6 +3005,7 @@ } s := strings.Join([]string{`&AbortRequest{`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2079,7 +3033,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2107,7 +3061,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2117,6 +3071,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2136,7 +3093,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift + m.Size_ |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -2155,7 +3112,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2164,10 +3121,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2185,7 +3145,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2194,10 +3154,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2215,7 +3178,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2224,6 +3187,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2244,7 +3210,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2261,7 +3227,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2271,6 +3237,9 @@ return ErrInvalidLengthContent } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthContent + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -2287,7 +3256,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2297,6 +3266,9 @@ return ErrInvalidLengthContent } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthContent + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -2308,7 +3280,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > postIndex { @@ -2325,12 +3297,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2355,7 +3328,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2383,7 +3356,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2393,6 +3366,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2404,12 +3380,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2434,7 +3411,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2462,7 +3439,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2471,6 +3448,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2484,12 +3464,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2514,7 +3495,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2542,7 +3523,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2551,6 +3532,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2572,7 +3556,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2581,11 +3565,14 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } if m.UpdateMask == nil { - m.UpdateMask = &google_protobuf1.FieldMask{} + m.UpdateMask = &types.FieldMask{} } if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2597,12 +3584,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2627,7 +3615,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2655,7 +3643,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2664,6 +3652,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2677,12 +3668,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2707,7 +3699,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2735,7 +3727,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2745,6 +3737,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2756,12 +3751,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2786,7 +3782,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2814,7 +3810,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2823,6 +3819,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2837,12 +3836,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2867,7 +3867,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2895,7 +3895,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2905,6 +3905,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2916,12 +3919,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2946,7 +3950,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2974,7 +3978,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2984,6 +3988,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3003,7 +4010,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Offset |= (int64(b) & 0x7F) << shift + m.Offset |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3022,7 +4029,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift + m.Size_ |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3033,12 +4040,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3063,7 +4071,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3091,7 +4099,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Offset |= (int64(b) & 0x7F) << shift + m.Offset |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3110,7 +4118,7 @@ } b := dAtA[iNdEx] iNdEx++ - byteLen |= (int(b) & 0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3119,6 +4127,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3133,12 +4144,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3163,7 +4175,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3191,7 +4203,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3200,10 +4212,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3221,7 +4236,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3230,10 +4245,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3251,7 +4269,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3261,6 +4279,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3280,7 +4301,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Offset |= (int64(b) & 0x7F) << shift + m.Offset |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3299,7 +4320,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Total |= (int64(b) & 0x7F) << shift + m.Total |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3318,7 +4339,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3328,6 +4349,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3339,12 +4363,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3369,7 +4394,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3397,7 +4422,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3407,6 +4432,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3418,12 +4446,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3448,7 +4477,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3476,7 +4505,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3485,6 +4514,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3501,12 +4533,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3531,7 +4564,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3559,7 +4592,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3569,6 +4602,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3580,12 +4616,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3610,7 +4647,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3638,7 +4675,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3647,6 +4684,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3661,12 +4701,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3691,7 +4732,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3719,7 +4760,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Action |= (WriteAction(b) & 0x7F) << shift + m.Action |= WriteAction(b&0x7F) << shift if b < 0x80 { break } @@ -3738,7 +4779,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3748,6 +4789,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3767,7 +4811,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Total |= (int64(b) & 0x7F) << shift + m.Total |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3786,7 +4830,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3796,6 +4840,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3815,7 +4862,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Offset |= (int64(b) & 0x7F) << shift + m.Offset |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -3834,7 +4881,7 @@ } b := dAtA[iNdEx] iNdEx++ - byteLen |= (int(b) & 0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3843,6 +4890,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3865,7 +4915,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3874,6 +4924,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3894,7 +4947,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3911,7 +4964,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3921,6 +4974,9 @@ return ErrInvalidLengthContent } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthContent + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -3937,7 +4993,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3947,6 +5003,9 @@ return ErrInvalidLengthContent } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthContent + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -3958,7 +5017,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > postIndex { @@ -3975,12 +5034,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4005,7 +5065,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4033,7 +5093,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Action |= (WriteAction(b) & 0x7F) << shift + m.Action |= WriteAction(b&0x7F) << shift if b < 0x80 { break } @@ -4052,7 +5112,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4061,10 +5121,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4082,7 +5145,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4091,10 +5154,13 @@ return ErrInvalidLengthContent } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4112,7 +5178,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Offset |= (int64(b) & 0x7F) << shift + m.Offset |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -4131,7 +5197,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Total |= (int64(b) & 0x7F) << shift + m.Total |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -4150,7 +5216,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4160,6 +5226,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4171,12 +5240,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4201,7 +5271,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4229,7 +5299,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4239,6 +5309,9 @@ return ErrInvalidLengthContent } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthContent + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4250,12 +5323,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthContent } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4268,6 +5342,7 @@ func skipContent(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -4299,10 +5374,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -4319,129 +5392,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthContent } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowContent - } - 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 := skipContent(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupContent + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthContent + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthContent = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowContent = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthContent = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowContent = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupContent = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/content/v1/content.proto", fileDescriptorContent) -} - -var fileDescriptorContent = []byte{ - // 1081 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6f, 0x1b, 0x45, - 0x14, 0xf7, 0x78, 0xed, 0x4d, 0xf2, 0x9c, 0x16, 0x33, 0x31, 0x95, 0xb5, 0x08, 0x67, 0xbb, 0x42, - 0xc8, 0x6a, 0xc9, 0x3a, 0x75, 0x7a, 0x00, 0x2a, 0x01, 0x8e, 0x9b, 0xaa, 0x41, 0x4d, 0x41, 0x5b, - 0x97, 0x40, 0x2f, 0x65, 0x6d, 0x8f, 0xcd, 0x2a, 0xb6, 0xd7, 0xdd, 0x19, 0x5b, 0x84, 0x13, 0x17, - 0x24, 0x14, 0xf5, 0x80, 0xb8, 0xe7, 0x02, 0xfc, 0x15, 0x1c, 0x38, 0xe7, 0xc8, 0x11, 0x71, 0x68, - 0x69, 0xfe, 0x07, 0xee, 0x68, 0x66, 0x67, 0xed, 0xf5, 0x47, 0x58, 0xdb, 0x31, 0x27, 0xbf, 0x99, - 0x7d, 0xbf, 0xf7, 0xfd, 0x31, 0x86, 0x7b, 0x4d, 0x87, 0x7d, 0xdd, 0xab, 0x9a, 0x35, 0xb7, 0x5d, - 0xa8, 0xb9, 0x1d, 0x66, 0x3b, 0x1d, 0xe2, 0xd5, 0xc3, 0xa4, 0xdd, 0x75, 0x0a, 0x94, 0x78, 0x7d, - 0xa7, 0x46, 0xa8, 0xb8, 0x27, 0x1d, 0x56, 0xe8, 0xdf, 0x0a, 0x48, 0xb3, 0xeb, 0xb9, 0xcc, 0xc5, - 0xb9, 0x21, 0xc2, 0x0c, 0xb8, 0xcd, 0x80, 0xa5, 0x7f, 0x4b, 0xcb, 0x34, 0xdd, 0xa6, 0x2b, 0x58, - 0x0b, 0x9c, 0xf2, 0x51, 0x9a, 0xde, 0x74, 0xdd, 0x66, 0x8b, 0x14, 0xc4, 0xa9, 0xda, 0x6b, 0x14, - 0x1a, 0x0e, 0x69, 0xd5, 0x9f, 0xb6, 0x6d, 0x7a, 0x24, 0x39, 0x36, 0xc7, 0x39, 0x98, 0xd3, 0x26, - 0x94, 0xd9, 0xed, 0xae, 0x64, 0x78, 0x73, 0x9c, 0x81, 0xb4, 0xbb, 0xec, 0xd8, 0xff, 0x68, 0xfc, - 0x13, 0x87, 0xc4, 0x7e, 0xa7, 0xe1, 0xe2, 0x4f, 0x40, 0xad, 0x3b, 0x4d, 0x42, 0x59, 0x16, 0xe9, - 0x28, 0xbf, 0xb6, 0x5b, 0x3c, 0x7b, 0xb1, 0x19, 0xfb, 0xeb, 0xc5, 0xe6, 0x8d, 0x90, 0xfb, 0x6e, - 0x97, 0x74, 0x06, 0x5e, 0xd0, 0x42, 0xd3, 0xdd, 0xf2, 0x21, 0xe6, 0x5d, 0xf1, 0x63, 0x49, 0x09, - 0x18, 0x43, 0x82, 0x3a, 0xdf, 0x92, 0x6c, 0x5c, 0x47, 0x79, 0xc5, 0x12, 0x34, 0x2e, 0x03, 0xd4, - 0x3c, 0x62, 0x33, 0x52, 0x7f, 0x6a, 0xb3, 0xac, 0xa2, 0xa3, 0x7c, 0xaa, 0xa8, 0x99, 0xbe, 0x69, - 0x66, 0x60, 0x9a, 0x59, 0x09, 0x6c, 0xdf, 0x5d, 0xe5, 0xfa, 0x7f, 0x7c, 0xb9, 0x89, 0xac, 0x35, - 0x89, 0x2b, 0x31, 0x2e, 0xa4, 0xd7, 0xad, 0x07, 0x42, 0x12, 0xf3, 0x08, 0x91, 0xb8, 0x12, 0xc3, - 0xf7, 0x41, 0x6d, 0xd9, 0x55, 0xd2, 0xa2, 0xd9, 0xa4, 0xae, 0xe4, 0x53, 0xc5, 0x6d, 0xf3, 0xbf, - 0x33, 0x63, 0xf2, 0xf8, 0x98, 0x0f, 0x04, 0x64, 0xaf, 0xc3, 0xbc, 0x63, 0x4b, 0xe2, 0xb5, 0xf7, - 0x21, 0x15, 0xba, 0xc6, 0x69, 0x50, 0x8e, 0xc8, 0xb1, 0x1f, 0x3f, 0x8b, 0x93, 0x38, 0x03, 0xc9, - 0xbe, 0xdd, 0xea, 0xf9, 0x91, 0x58, 0xb3, 0xfc, 0xc3, 0x07, 0xf1, 0xf7, 0x90, 0xf1, 0x25, 0xa4, - 0xb8, 0x58, 0x8b, 0x3c, 0xeb, 0xf1, 0x88, 0x2d, 0x31, 0xfa, 0xc6, 0x43, 0x58, 0xf7, 0x45, 0xd3, - 0xae, 0xdb, 0xa1, 0x04, 0x7f, 0x08, 0x09, 0xa7, 0xd3, 0x70, 0x85, 0xe4, 0x54, 0xf1, 0xed, 0x59, - 0xbc, 0xdd, 0x4d, 0x70, 0xfd, 0x96, 0xc0, 0x19, 0xcf, 0x11, 0x5c, 0x79, 0x2c, 0xa2, 0x17, 0x58, - 0x7b, 0x49, 0x89, 0xf8, 0x0e, 0xa4, 0xfc, 0x74, 0x88, 0x3a, 0x16, 0xc1, 0x99, 0x96, 0xc7, 0x7b, - 0xbc, 0xd4, 0x0f, 0x6c, 0x7a, 0x64, 0xc9, 0xac, 0x73, 0xda, 0xf8, 0x0c, 0xae, 0x06, 0xd6, 0x2c, - 0xc9, 0x41, 0x13, 0xf0, 0x03, 0x87, 0xb2, 0xb2, 0xcf, 0x12, 0x38, 0x99, 0x85, 0x95, 0x86, 0xd3, - 0x62, 0xc4, 0xa3, 0x59, 0xa4, 0x2b, 0xf9, 0x35, 0x2b, 0x38, 0x1a, 0x8f, 0x61, 0x63, 0x84, 0x7f, - 0xc2, 0x0c, 0x65, 0x21, 0x33, 0xaa, 0x90, 0xb9, 0x4b, 0x5a, 0x84, 0x91, 0x31, 0x43, 0x96, 0x59, - 0x1b, 0xcf, 0x11, 0x60, 0x8b, 0xd8, 0xf5, 0xff, 0x4f, 0x05, 0xbe, 0x06, 0xaa, 0xdb, 0x68, 0x50, - 0xc2, 0x64, 0xfb, 0xcb, 0xd3, 0x60, 0x28, 0x28, 0xc3, 0xa1, 0x60, 0x94, 0x60, 0x63, 0xc4, 0x1a, - 0x19, 0xc9, 0xa1, 0x08, 0x34, 0x2e, 0xa2, 0x6e, 0x33, 0x5b, 0x08, 0x5e, 0xb7, 0x04, 0x6d, 0xfc, - 0x1c, 0x07, 0xf5, 0x11, 0xb3, 0x59, 0x8f, 0xf2, 0xe9, 0x40, 0x99, 0xed, 0xc9, 0xe9, 0x80, 0xe6, - 0x99, 0x0e, 0x12, 0x37, 0x31, 0x62, 0xe2, 0x8b, 0x8d, 0x98, 0x34, 0x28, 0x1e, 0x69, 0x08, 0x57, - 0xd7, 0x2c, 0x4e, 0x86, 0x5c, 0x4a, 0x8c, 0xb8, 0x94, 0x81, 0x24, 0x73, 0x99, 0xdd, 0xca, 0x26, - 0xc5, 0xb5, 0x7f, 0xc0, 0x0f, 0x61, 0x95, 0x7c, 0xd3, 0x25, 0x35, 0x46, 0xea, 0x59, 0x75, 0xe1, - 0x8c, 0x0c, 0x64, 0x18, 0xd7, 0xe1, 0x8a, 0x1f, 0xa3, 0x20, 0xe1, 0xd2, 0x40, 0x34, 0x30, 0x90, - 0xb7, 0x55, 0xc0, 0x32, 0xa8, 0x67, 0x95, 0x8a, 0x1b, 0x19, 0xca, 0x77, 0xa2, 0x2a, 0x5a, 0xe2, - 0x25, 0xca, 0x28, 0xf8, 0x6d, 0xe2, 0xdf, 0x12, 0x1a, 0xdd, 0x57, 0x5f, 0x41, 0x66, 0x14, 0x20, - 0x0d, 0xb9, 0x0f, 0xab, 0x54, 0xde, 0xc9, 0xe6, 0x9a, 0xd1, 0x14, 0xd9, 0x5e, 0x03, 0xb4, 0xf1, - 0x93, 0x02, 0x1b, 0x87, 0x9e, 0x33, 0xd1, 0x62, 0x65, 0x50, 0xed, 0x1a, 0x73, 0xdc, 0x8e, 0x70, - 0xf5, 0x6a, 0xf1, 0x66, 0x94, 0x7c, 0x21, 0xa4, 0x24, 0x20, 0x96, 0x84, 0x06, 0x31, 0x8d, 0x0f, - 0x93, 0x3e, 0x48, 0xae, 0x72, 0x51, 0x72, 0x13, 0x97, 0x4f, 0x6e, 0xa8, 0xb4, 0x92, 0x53, 0xbb, - 0x45, 0x1d, 0x76, 0x0b, 0x3e, 0x1c, 0xec, 0xbe, 0x15, 0x11, 0xc8, 0x8f, 0x66, 0x72, 0x74, 0x34, - 0x5a, 0xcb, 0x5e, 0x85, 0x2f, 0xe3, 0x90, 0x19, 0x55, 0x23, 0xf3, 0xbe, 0x94, 0xac, 0x8c, 0x0e, - 0x85, 0xf8, 0x32, 0x86, 0x82, 0xb2, 0xd8, 0x50, 0x98, 0x6f, 0x04, 0x0c, 0x47, 0xb2, 0x7a, 0xe9, - 0xa9, 0xaf, 0xc3, 0x7a, 0xa9, 0xea, 0x7a, 0xec, 0xc2, 0xee, 0xbf, 0xf1, 0x3d, 0x82, 0x54, 0x28, - 0x7a, 0xf8, 0x2d, 0x48, 0x3c, 0xaa, 0x94, 0x2a, 0xe9, 0x98, 0xb6, 0x71, 0x72, 0xaa, 0xbf, 0x16, - 0xfa, 0xc4, 0x3b, 0x0b, 0x6f, 0x42, 0xf2, 0xd0, 0xda, 0xaf, 0xec, 0xa5, 0x91, 0x96, 0x39, 0x39, - 0xd5, 0xd3, 0xa1, 0xef, 0x82, 0xc4, 0xd7, 0x41, 0x2d, 0x7f, 0x7a, 0x70, 0xb0, 0x5f, 0x49, 0xc7, - 0xb5, 0x37, 0x4e, 0x4e, 0xf5, 0xd7, 0x43, 0x1c, 0x65, 0xb7, 0xdd, 0x76, 0x98, 0xb6, 0xf1, 0xc3, - 0x2f, 0xb9, 0xd8, 0x6f, 0xbf, 0xe6, 0xc2, 0x7a, 0x8b, 0xbf, 0xaf, 0xc0, 0x8a, 0x2c, 0x03, 0x6c, - 0xcb, 0x97, 0xe9, 0xcd, 0x59, 0x36, 0xa9, 0x74, 0x4d, 0x7b, 0x77, 0x36, 0x66, 0x59, 0x61, 0x4d, - 0x50, 0xfd, 0xb7, 0x04, 0xde, 0x8a, 0xc2, 0x8d, 0xbc, 0x80, 0x34, 0x73, 0x56, 0x76, 0xa9, 0xe8, - 0x19, 0x24, 0xf8, 0x68, 0xc3, 0xc5, 0x28, 0xdc, 0xe4, 0x43, 0x44, 0xdb, 0x99, 0x0b, 0xe3, 0x2b, - 0xdc, 0x46, 0xf8, 0x73, 0x50, 0xfd, 0xe7, 0x04, 0xbe, 0x1d, 0x25, 0x60, 0xda, 0xb3, 0x43, 0xbb, - 0x36, 0x51, 0xdf, 0x7b, 0xfc, 0x7f, 0x03, 0x77, 0x85, 0xef, 0xec, 0x68, 0x57, 0x26, 0xdf, 0x19, - 0xd1, 0xae, 0x4c, 0x79, 0x0d, 0x6c, 0x23, 0x9e, 0x26, 0xb9, 0xe2, 0xb7, 0x66, 0xdc, 0x41, 0xb3, - 0xa6, 0x69, 0x6c, 0xe5, 0x1d, 0xc3, 0x7a, 0x78, 0x03, 0xe1, 0x99, 0x42, 0x3f, 0xb6, 0xe0, 0xb4, - 0xdb, 0xf3, 0x81, 0xa4, 0xea, 0x3e, 0x24, 0xfd, 0xd6, 0xd9, 0x59, 0x60, 0x24, 0x47, 0xeb, 0x9c, - 0x36, 0x60, 0xf3, 0x68, 0x1b, 0xe1, 0x03, 0x48, 0x8a, 0xd9, 0x80, 0x23, 0x3b, 0x27, 0x3c, 0x42, - 0x2e, 0xaa, 0x8e, 0xdd, 0x27, 0x67, 0xaf, 0x72, 0xb1, 0x3f, 0x5f, 0xe5, 0x62, 0xdf, 0x9d, 0xe7, - 0xd0, 0xd9, 0x79, 0x0e, 0xfd, 0x71, 0x9e, 0x43, 0x7f, 0x9f, 0xe7, 0xd0, 0x93, 0x8f, 0x17, 0xfd, - 0x1f, 0x7d, 0x47, 0x92, 0x5f, 0xc4, 0xaa, 0xaa, 0xd0, 0xb6, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xc0, 0xc2, 0x35, 0xb1, 0x94, 0x0f, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/content/v1/content.proto containerd-1.5.9/api/services/content/v1/content.proto --- containerd-1.2.6/api/services/content/v1/content.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/content/v1/content.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.content.v1; diff -Nru containerd-1.2.6/api/services/diff/v1/diff.pb.go containerd-1.5.9/api/services/diff/v1/diff.pb.go --- containerd-1.2.6/api/services/diff/v1/diff.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/diff/v1/diff.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,36 +1,24 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/diff/v1/diff.proto -/* - Package diff is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/diff/v1/diff.proto - - It has these top-level messages: - ApplyRequest - ApplyResponse - DiffRequest - DiffResponse -*/ package diff -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import containerd_types "github.com/containerd/containerd/api/types" -import containerd_types1 "github.com/containerd/containerd/api/types" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + types1 "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -41,36 +29,99 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type ApplyRequest struct { // Diff is the descriptor of the diff to be extracted - Diff *containerd_types1.Descriptor `protobuf:"bytes,1,opt,name=diff" json:"diff,omitempty"` - Mounts []*containerd_types.Mount `protobuf:"bytes,2,rep,name=mounts" json:"mounts,omitempty"` + Diff *types.Descriptor `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"` + Mounts []*types.Mount `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"` + Payloads map[string]*types1.Any `protobuf:"bytes,3,rep,name=payloads,proto3" json:"payloads,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ApplyRequest) Reset() { *m = ApplyRequest{} } +func (*ApplyRequest) ProtoMessage() {} +func (*ApplyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_3b36a99e6faaa935, []int{0} +} +func (m *ApplyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ApplyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ApplyRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ApplyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplyRequest.Merge(m, src) +} +func (m *ApplyRequest) XXX_Size() int { + return m.Size() +} +func (m *ApplyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ApplyRequest.DiscardUnknown(m) } -func (m *ApplyRequest) Reset() { *m = ApplyRequest{} } -func (*ApplyRequest) ProtoMessage() {} -func (*ApplyRequest) Descriptor() ([]byte, []int) { return fileDescriptorDiff, []int{0} } +var xxx_messageInfo_ApplyRequest proto.InternalMessageInfo type ApplyResponse struct { // Applied is the descriptor for the object which was applied. // If the input was a compressed blob then the result will be // the descriptor for the uncompressed blob. - Applied *containerd_types1.Descriptor `protobuf:"bytes,1,opt,name=applied" json:"applied,omitempty"` + Applied *types.Descriptor `protobuf:"bytes,1,opt,name=applied,proto3" json:"applied,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ApplyResponse) Reset() { *m = ApplyResponse{} } +func (*ApplyResponse) ProtoMessage() {} +func (*ApplyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_3b36a99e6faaa935, []int{1} +} +func (m *ApplyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ApplyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ApplyResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ApplyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplyResponse.Merge(m, src) +} +func (m *ApplyResponse) XXX_Size() int { + return m.Size() +} +func (m *ApplyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ApplyResponse.DiscardUnknown(m) } -func (m *ApplyResponse) Reset() { *m = ApplyResponse{} } -func (*ApplyResponse) ProtoMessage() {} -func (*ApplyResponse) Descriptor() ([]byte, []int) { return fileDescriptorDiff, []int{1} } +var xxx_messageInfo_ApplyResponse proto.InternalMessageInfo type DiffRequest struct { // Left are the mounts which represent the older copy // in which is the base of the computed changes. - Left []*containerd_types.Mount `protobuf:"bytes,1,rep,name=left" json:"left,omitempty"` + Left []*types.Mount `protobuf:"bytes,1,rep,name=left,proto3" json:"left,omitempty"` // Right are the mounts which represents the newer copy // in which changes from the left were made into. - Right []*containerd_types.Mount `protobuf:"bytes,2,rep,name=right" json:"right,omitempty"` + Right []*types.Mount `protobuf:"bytes,2,rep,name=right,proto3" json:"right,omitempty"` // MediaType is the media type descriptor for the created diff // object MediaType string `protobuf:"bytes,3,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"` @@ -79,29 +130,134 @@ Ref string `protobuf:"bytes,4,opt,name=ref,proto3" json:"ref,omitempty"` // Labels are the labels to apply to the generated content // on content store commit. - Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiffRequest) Reset() { *m = DiffRequest{} } +func (*DiffRequest) ProtoMessage() {} +func (*DiffRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_3b36a99e6faaa935, []int{2} +} +func (m *DiffRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DiffRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DiffRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DiffRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiffRequest.Merge(m, src) +} +func (m *DiffRequest) XXX_Size() int { + return m.Size() +} +func (m *DiffRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DiffRequest.DiscardUnknown(m) } -func (m *DiffRequest) Reset() { *m = DiffRequest{} } -func (*DiffRequest) ProtoMessage() {} -func (*DiffRequest) Descriptor() ([]byte, []int) { return fileDescriptorDiff, []int{2} } +var xxx_messageInfo_DiffRequest proto.InternalMessageInfo type DiffResponse struct { // Diff is the descriptor of the diff which can be applied - Diff *containerd_types1.Descriptor `protobuf:"bytes,3,opt,name=diff" json:"diff,omitempty"` + Diff *types.Descriptor `protobuf:"bytes,3,opt,name=diff,proto3" json:"diff,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DiffResponse) Reset() { *m = DiffResponse{} } +func (*DiffResponse) ProtoMessage() {} +func (*DiffResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_3b36a99e6faaa935, []int{3} +} +func (m *DiffResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DiffResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DiffResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DiffResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DiffResponse.Merge(m, src) +} +func (m *DiffResponse) XXX_Size() int { + return m.Size() +} +func (m *DiffResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DiffResponse.DiscardUnknown(m) } -func (m *DiffResponse) Reset() { *m = DiffResponse{} } -func (*DiffResponse) ProtoMessage() {} -func (*DiffResponse) Descriptor() ([]byte, []int) { return fileDescriptorDiff, []int{3} } +var xxx_messageInfo_DiffResponse proto.InternalMessageInfo func init() { proto.RegisterType((*ApplyRequest)(nil), "containerd.services.diff.v1.ApplyRequest") + proto.RegisterMapType((map[string]*types1.Any)(nil), "containerd.services.diff.v1.ApplyRequest.PayloadsEntry") proto.RegisterType((*ApplyResponse)(nil), "containerd.services.diff.v1.ApplyResponse") proto.RegisterType((*DiffRequest)(nil), "containerd.services.diff.v1.DiffRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.diff.v1.DiffRequest.LabelsEntry") proto.RegisterType((*DiffResponse)(nil), "containerd.services.diff.v1.DiffResponse") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/diff/v1/diff.proto", fileDescriptor_3b36a99e6faaa935) +} + +var fileDescriptor_3b36a99e6faaa935 = []byte{ + // 526 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x4c, + 0x10, 0x8d, 0xed, 0x24, 0xdf, 0x97, 0x49, 0x2b, 0xa1, 0x55, 0x24, 0x8c, 0x01, 0xab, 0xca, 0x29, + 0x2d, 0x62, 0x4d, 0x03, 0x2a, 0xd0, 0x5e, 0x5a, 0x54, 0xc4, 0xa5, 0x48, 0x60, 0x7a, 0x40, 0x20, + 0x81, 0x9c, 0x78, 0xed, 0xae, 0x70, 0xbc, 0x8b, 0x77, 0x1d, 0xc9, 0x37, 0xfe, 0x06, 0x67, 0x7e, + 0x0a, 0x97, 0x1e, 0x39, 0x72, 0xa4, 0xf9, 0x25, 0xc8, 0xeb, 0x75, 0x31, 0x02, 0x05, 0xc3, 0xc9, + 0x9b, 0x9d, 0xf7, 0xde, 0xce, 0xbc, 0x37, 0x0a, 0x1c, 0xc6, 0x54, 0x9e, 0xe5, 0x33, 0x3c, 0x67, + 0x0b, 0x6f, 0xce, 0x52, 0x19, 0xd0, 0x94, 0x64, 0x61, 0xf3, 0x18, 0x70, 0xea, 0x09, 0x92, 0x2d, + 0xe9, 0x9c, 0x08, 0x2f, 0xa4, 0x51, 0xe4, 0x2d, 0x77, 0xd5, 0x17, 0xf3, 0x8c, 0x49, 0x86, 0xae, + 0xff, 0xc0, 0xe2, 0x1a, 0x87, 0x55, 0x7d, 0xb9, 0xeb, 0x8c, 0x62, 0x16, 0x33, 0x85, 0xf3, 0xca, + 0x53, 0x45, 0x71, 0xae, 0xc5, 0x8c, 0xc5, 0x09, 0xf1, 0xd4, 0xaf, 0x59, 0x1e, 0x79, 0x41, 0x5a, + 0xe8, 0xd2, 0x5e, 0xab, 0x7e, 0x64, 0xc1, 0x89, 0xf0, 0x16, 0x2c, 0x4f, 0xa5, 0xe6, 0x1d, 0xfc, + 0x05, 0x2f, 0x24, 0x62, 0x9e, 0x51, 0x2e, 0x59, 0x56, 0x91, 0xc7, 0x1f, 0x4d, 0xd8, 0x38, 0xe2, + 0x3c, 0x29, 0x7c, 0xf2, 0x3e, 0x27, 0x42, 0xa2, 0x3b, 0xd0, 0x2d, 0x27, 0xb0, 0x8d, 0x2d, 0x63, + 0x32, 0x9c, 0xde, 0xc0, 0x8d, 0x11, 0x95, 0x04, 0x3e, 0xbe, 0x94, 0xf0, 0x15, 0x12, 0x79, 0xd0, + 0x57, 0xed, 0x08, 0xdb, 0xdc, 0xb2, 0x26, 0xc3, 0xe9, 0xd5, 0x5f, 0x39, 0x4f, 0xcb, 0xba, 0xaf, + 0x61, 0xe8, 0x05, 0xfc, 0xcf, 0x83, 0x22, 0x61, 0x41, 0x28, 0x6c, 0x4b, 0x51, 0xee, 0xe3, 0x35, + 0x4e, 0xe2, 0x66, 0x7f, 0xf8, 0x99, 0x66, 0x3e, 0x4e, 0x65, 0x56, 0xf8, 0x97, 0x42, 0xce, 0x73, + 0xd8, 0xfc, 0xa9, 0x84, 0xae, 0x80, 0xf5, 0x8e, 0x14, 0x6a, 0x8e, 0x81, 0x5f, 0x1e, 0xd1, 0x0e, + 0xf4, 0x96, 0x41, 0x92, 0x13, 0xdb, 0x54, 0xb3, 0x8d, 0x70, 0x95, 0x05, 0xae, 0xb3, 0xc0, 0x47, + 0x69, 0xe1, 0x57, 0x90, 0x7d, 0xf3, 0x81, 0x31, 0x7e, 0x02, 0x9b, 0xfa, 0x69, 0xc1, 0x59, 0x2a, + 0x08, 0xda, 0x83, 0xff, 0x02, 0xce, 0x13, 0x4a, 0xc2, 0x56, 0xf6, 0xd4, 0xe0, 0xf1, 0x27, 0x13, + 0x86, 0xc7, 0x34, 0x8a, 0x6a, 0x8f, 0x6f, 0x41, 0x37, 0x21, 0x91, 0xb4, 0x8d, 0xf5, 0x7e, 0x29, + 0x10, 0xba, 0x0d, 0xbd, 0x8c, 0xc6, 0x67, 0xf2, 0x4f, 0xee, 0x56, 0x28, 0x74, 0x13, 0x60, 0x41, + 0x42, 0x1a, 0xbc, 0x2d, 0x6b, 0xb6, 0xa5, 0xa6, 0x1f, 0xa8, 0x9b, 0xd3, 0x82, 0x93, 0xd2, 0x95, + 0x8c, 0x44, 0x76, 0xb7, 0x72, 0x25, 0x23, 0x11, 0x3a, 0x81, 0x7e, 0x12, 0xcc, 0x48, 0x22, 0xec, + 0x9e, 0x7a, 0xe0, 0xde, 0xda, 0x2c, 0x1a, 0x63, 0xe0, 0x13, 0x45, 0xab, 0x82, 0xd0, 0x1a, 0xce, + 0x43, 0x18, 0x36, 0xae, 0x7f, 0x13, 0xc2, 0xa8, 0x19, 0xc2, 0xa0, 0x69, 0xf7, 0x21, 0x6c, 0x54, + 0xea, 0xda, 0xed, 0x7a, 0x13, 0xad, 0xb6, 0x9b, 0x38, 0xfd, 0x6c, 0x40, 0xb7, 0x94, 0x40, 0x6f, + 0xa0, 0xa7, 0x92, 0x43, 0xdb, 0xad, 0x17, 0xcb, 0xd9, 0x69, 0x03, 0xd5, 0xad, 0xbd, 0xd6, 0xef, + 0x4c, 0xda, 0x7a, 0xe5, 0x6c, 0xb7, 0x40, 0x56, 0xe2, 0x8f, 0x4e, 0xcf, 0x2f, 0xdc, 0xce, 0xd7, + 0x0b, 0xb7, 0xf3, 0x61, 0xe5, 0x1a, 0xe7, 0x2b, 0xd7, 0xf8, 0xb2, 0x72, 0x8d, 0x6f, 0x2b, 0xd7, + 0x78, 0xb5, 0xff, 0x4f, 0xff, 0x58, 0x07, 0xe5, 0xf7, 0x65, 0x67, 0xd6, 0x57, 0x7b, 0x7e, 0xf7, + 0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x85, 0x25, 0xb8, 0xf8, 0x04, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -110,8 +266,9 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Diff service - +// DiffClient is the client API for Diff service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type DiffClient interface { // Apply applies the content associated with the provided digests onto // the provided mounts. Archive content will be extracted and @@ -132,7 +289,7 @@ func (c *diffClient) Apply(ctx context.Context, in *ApplyRequest, opts ...grpc.CallOption) (*ApplyResponse, error) { out := new(ApplyResponse) - err := grpc.Invoke(ctx, "/containerd.services.diff.v1.Diff/Apply", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.diff.v1.Diff/Apply", in, out, opts...) if err != nil { return nil, err } @@ -141,15 +298,14 @@ func (c *diffClient) Diff(ctx context.Context, in *DiffRequest, opts ...grpc.CallOption) (*DiffResponse, error) { out := new(DiffResponse) - err := grpc.Invoke(ctx, "/containerd.services.diff.v1.Diff/Diff", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.diff.v1.Diff/Diff", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Diff service - +// DiffServer is the server API for Diff service. type DiffServer interface { // Apply applies the content associated with the provided digests onto // the provided mounts. Archive content will be extracted and @@ -160,6 +316,17 @@ Diff(context.Context, *DiffRequest) (*DiffResponse, error) } +// UnimplementedDiffServer can be embedded to have forward compatible implementations. +type UnimplementedDiffServer struct { +} + +func (*UnimplementedDiffServer) Apply(ctx context.Context, req *ApplyRequest) (*ApplyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Apply not implemented") +} +func (*UnimplementedDiffServer) Diff(ctx context.Context, req *DiffRequest) (*DiffResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Diff not implemented") +} + func RegisterDiffServer(s *grpc.Server, srv DiffServer) { s.RegisterService(&_Diff_serviceDesc, srv) } @@ -220,7 +387,7 @@ func (m *ApplyRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -228,39 +395,78 @@ } func (m *ApplyRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ApplyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Diff != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintDiff(dAtA, i, uint64(m.Diff.Size())) - n1, err := m.Diff.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Payloads) > 0 { + for k := range m.Payloads { + v := m.Payloads[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintDiff(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintDiff(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a } - i += n1 } if len(m.Mounts) > 0 { - for _, msg := range m.Mounts { + for iNdEx := len(m.Mounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Mounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintDiff(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + } + } + if m.Diff != nil { + { + size, err := m.Diff.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ApplyResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -268,27 +474,38 @@ } func (m *ApplyResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ApplyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Applied != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintDiff(dAtA, i, uint64(m.Applied.Size())) - n2, err := m.Applied.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Applied.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *DiffRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -296,70 +513,87 @@ } func (m *DiffRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DiffRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Left) > 0 { - for _, msg := range m.Left { - dAtA[i] = 0xa - i++ - i = encodeVarintDiff(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Right) > 0 { - for _, msg := range m.Right { + if len(m.Labels) > 0 { + for k := range m.Labels { + v := m.Labels[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintDiff(dAtA, i, uint64(len(v))) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintDiff(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintDiff(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintDiff(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a } } + if len(m.Ref) > 0 { + i -= len(m.Ref) + copy(dAtA[i:], m.Ref) + i = encodeVarintDiff(dAtA, i, uint64(len(m.Ref))) + i-- + dAtA[i] = 0x22 + } if len(m.MediaType) > 0 { - dAtA[i] = 0x1a - i++ + i -= len(m.MediaType) + copy(dAtA[i:], m.MediaType) i = encodeVarintDiff(dAtA, i, uint64(len(m.MediaType))) - i += copy(dAtA[i:], m.MediaType) + i-- + dAtA[i] = 0x1a } - if len(m.Ref) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintDiff(dAtA, i, uint64(len(m.Ref))) - i += copy(dAtA[i:], m.Ref) + if len(m.Right) > 0 { + for iNdEx := len(m.Right) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Right[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } } - if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x2a - i++ - v := m.Labels[k] - mapSize := 1 + len(k) + sovDiff(uint64(len(k))) + 1 + len(v) + sovDiff(uint64(len(v))) - i = encodeVarintDiff(dAtA, i, uint64(mapSize)) + if len(m.Left) > 0 { + for iNdEx := len(m.Left) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Left[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0xa - i++ - i = encodeVarintDiff(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ - i = encodeVarintDiff(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + return len(dAtA) - i, nil } func (m *DiffResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -367,33 +601,49 @@ } func (m *DiffResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DiffResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Diff != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintDiff(dAtA, i, uint64(m.Diff.Size())) - n3, err := m.Diff.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Diff.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDiff(dAtA, i, uint64(size)) } - i += n3 + i-- + dAtA[i] = 0x1a } - return i, nil + return len(dAtA) - i, nil } func encodeVarintDiff(dAtA []byte, offset int, v uint64) int { + offset -= sovDiff(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *ApplyRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Diff != nil { @@ -406,20 +656,45 @@ n += 1 + l + sovDiff(uint64(l)) } } + if len(m.Payloads) > 0 { + for k, v := range m.Payloads { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovDiff(uint64(l)) + } + mapEntrySize := 1 + len(k) + sovDiff(uint64(len(k))) + l + n += mapEntrySize + 1 + sovDiff(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ApplyResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Applied != nil { l = m.Applied.Size() n += 1 + l + sovDiff(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DiffRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Left) > 0 { @@ -450,28 +725,30 @@ n += mapEntrySize + 1 + sovDiff(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DiffResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Diff != nil { l = m.Diff.Size() n += 1 + l + sovDiff(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovDiff(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozDiff(x uint64) (n int) { return sovDiff(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -480,9 +757,26 @@ if this == nil { return "nil" } + repeatedStringForMounts := "[]*Mount{" + for _, f := range this.Mounts { + repeatedStringForMounts += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForMounts += "}" + keysForPayloads := make([]string, 0, len(this.Payloads)) + for k, _ := range this.Payloads { + keysForPayloads = append(keysForPayloads, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForPayloads) + mapStringForPayloads := "map[string]*types1.Any{" + for _, k := range keysForPayloads { + mapStringForPayloads += fmt.Sprintf("%v: %v,", k, this.Payloads[k]) + } + mapStringForPayloads += "}" s := strings.Join([]string{`&ApplyRequest{`, - `Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "containerd_types1.Descriptor", 1) + `,`, - `Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "containerd_types.Mount", 1) + `,`, + `Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "types.Descriptor", 1) + `,`, + `Mounts:` + repeatedStringForMounts + `,`, + `Payloads:` + mapStringForPayloads + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -492,7 +786,8 @@ return "nil" } s := strings.Join([]string{`&ApplyResponse{`, - `Applied:` + strings.Replace(fmt.Sprintf("%v", this.Applied), "Descriptor", "containerd_types1.Descriptor", 1) + `,`, + `Applied:` + strings.Replace(fmt.Sprintf("%v", this.Applied), "Descriptor", "types.Descriptor", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -501,22 +796,33 @@ if this == nil { return "nil" } + repeatedStringForLeft := "[]*Mount{" + for _, f := range this.Left { + repeatedStringForLeft += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForLeft += "}" + repeatedStringForRight := "[]*Mount{" + for _, f := range this.Right { + repeatedStringForRight += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForRight += "}" keysForLabels := make([]string, 0, len(this.Labels)) for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) } mapStringForLabels += "}" s := strings.Join([]string{`&DiffRequest{`, - `Left:` + strings.Replace(fmt.Sprintf("%v", this.Left), "Mount", "containerd_types.Mount", 1) + `,`, - `Right:` + strings.Replace(fmt.Sprintf("%v", this.Right), "Mount", "containerd_types.Mount", 1) + `,`, + `Left:` + repeatedStringForLeft + `,`, + `Right:` + repeatedStringForRight + `,`, `MediaType:` + fmt.Sprintf("%v", this.MediaType) + `,`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -526,7 +832,8 @@ return "nil" } s := strings.Join([]string{`&DiffResponse{`, - `Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "containerd_types1.Descriptor", 1) + `,`, + `Diff:` + strings.Replace(fmt.Sprintf("%v", this.Diff), "Descriptor", "types.Descriptor", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -554,7 +861,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -582,7 +889,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -591,11 +898,14 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Diff == nil { - m.Diff = &containerd_types1.Descriptor{} + m.Diff = &types.Descriptor{} } if err := m.Diff.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -615,7 +925,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -624,26 +934,159 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Mounts = append(m.Mounts, &containerd_types.Mount{}) + m.Mounts = append(m.Mounts, &types.Mount{}) if err := m.Mounts[len(m.Mounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payloads", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDiff + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDiff + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Payloads == nil { + m.Payloads = make(map[string]*types1.Any) + } + var mapkey string + var mapvalue *types1.Any + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDiff + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDiff + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthDiff + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthDiff + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDiff + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthDiff + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthDiff + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &types1.Any{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipDiff(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDiff + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Payloads[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipDiff(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDiff } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -668,7 +1111,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -696,7 +1139,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -705,11 +1148,14 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Applied == nil { - m.Applied = &containerd_types1.Descriptor{} + m.Applied = &types.Descriptor{} } if err := m.Applied.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -721,12 +1167,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDiff } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -751,7 +1198,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -779,7 +1226,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -788,10 +1235,13 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Left = append(m.Left, &containerd_types.Mount{}) + m.Left = append(m.Left, &types.Mount{}) if err := m.Left[len(m.Left)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -810,7 +1260,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -819,10 +1269,13 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Right = append(m.Right, &containerd_types.Mount{}) + m.Right = append(m.Right, &types.Mount{}) if err := m.Right[len(m.Right)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -841,7 +1294,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -851,6 +1304,9 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -870,7 +1326,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -880,6 +1336,9 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -899,7 +1358,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -908,6 +1367,9 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -928,7 +1390,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -945,7 +1407,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -955,6 +1417,9 @@ return ErrInvalidLengthDiff } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthDiff + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -971,7 +1436,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -981,6 +1446,9 @@ return ErrInvalidLengthDiff } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthDiff + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -992,7 +1460,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDiff } if (iNdEx + skippy) > postIndex { @@ -1009,12 +1477,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDiff } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1039,7 +1508,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1067,7 +1536,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1076,11 +1545,14 @@ return ErrInvalidLengthDiff } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDiff + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Diff == nil { - m.Diff = &containerd_types1.Descriptor{} + m.Diff = &types.Descriptor{} } if err := m.Diff.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1092,12 +1564,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDiff } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1110,6 +1583,7 @@ func skipDiff(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1141,10 +1615,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1161,90 +1633,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthDiff } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowDiff - } - 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 := skipDiff(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDiff + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthDiff + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthDiff = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowDiff = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthDiff = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDiff = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDiff = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/diff/v1/diff.proto", fileDescriptorDiff) -} - -var fileDescriptorDiff = []byte{ - // 457 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4f, 0x6f, 0xd3, 0x30, - 0x14, 0xaf, 0xfb, 0x0f, 0xf5, 0x75, 0x48, 0xc8, 0x9a, 0x44, 0x14, 0x20, 0xaa, 0x7a, 0xea, 0x40, - 0x38, 0xac, 0xa0, 0x09, 0xb6, 0xcb, 0x40, 0x43, 0x5c, 0xc6, 0x25, 0xda, 0x01, 0x81, 0x04, 0x4a, - 0x9b, 0x97, 0xce, 0x22, 0x8d, 0xbd, 0xd8, 0xad, 0x94, 0x1b, 0xdf, 0x85, 0x8f, 0xc2, 0x65, 0x47, - 0x8e, 0x1c, 0x69, 0x3f, 0x09, 0xb2, 0x93, 0x40, 0x24, 0xa4, 0x12, 0x76, 0xca, 0xcb, 0xf3, 0xef, - 0x9f, 0xfd, 0x6c, 0x38, 0x5d, 0x70, 0x7d, 0xb9, 0x9a, 0xb1, 0xb9, 0x58, 0xfa, 0x73, 0x91, 0xea, - 0x90, 0xa7, 0x98, 0x45, 0xf5, 0x32, 0x94, 0xdc, 0x57, 0x98, 0xad, 0xf9, 0x1c, 0x95, 0x1f, 0xf1, - 0x38, 0xf6, 0xd7, 0x87, 0xf6, 0xcb, 0x64, 0x26, 0xb4, 0xa0, 0xf7, 0xfe, 0x60, 0x59, 0x85, 0x63, - 0x76, 0x7d, 0x7d, 0xe8, 0xee, 0x2f, 0xc4, 0x42, 0x58, 0x9c, 0x6f, 0xaa, 0x82, 0xe2, 0x1e, 0x35, - 0x32, 0xd5, 0xb9, 0x44, 0xe5, 0x2f, 0xc5, 0x2a, 0xd5, 0x25, 0xef, 0xe4, 0x3f, 0x78, 0x11, 0xaa, - 0x79, 0xc6, 0xa5, 0x16, 0x59, 0x41, 0x1e, 0x5f, 0xc1, 0xde, 0x4b, 0x29, 0x93, 0x3c, 0xc0, 0xab, - 0x15, 0x2a, 0x4d, 0x9f, 0x40, 0xd7, 0xa4, 0x74, 0xc8, 0x88, 0x4c, 0x86, 0xd3, 0xfb, 0xac, 0xb6, - 0x0d, 0xab, 0xc0, 0xce, 0x7e, 0x2b, 0x04, 0x16, 0x49, 0x7d, 0xe8, 0xdb, 0x34, 0xca, 0x69, 0x8f, - 0x3a, 0x93, 0xe1, 0xf4, 0xee, 0xdf, 0x9c, 0xb7, 0x66, 0x3d, 0x28, 0x61, 0xe3, 0x37, 0x70, 0xbb, - 0xb4, 0x54, 0x52, 0xa4, 0x0a, 0xe9, 0x11, 0xdc, 0x0a, 0xa5, 0x4c, 0x38, 0x46, 0x8d, 0x6c, 0x2b, - 0xf0, 0xf8, 0x6b, 0x1b, 0x86, 0x67, 0x3c, 0x8e, 0xab, 0xec, 0x8f, 0xa0, 0x9b, 0x60, 0xac, 0x1d, - 0xb2, 0x3b, 0x87, 0x05, 0xd1, 0xc7, 0xd0, 0xcb, 0xf8, 0xe2, 0x52, 0xff, 0x2b, 0x75, 0x81, 0xa2, - 0x0f, 0x00, 0x96, 0x18, 0xf1, 0xf0, 0x93, 0x59, 0x73, 0x3a, 0x23, 0x32, 0x19, 0x04, 0x03, 0xdb, - 0xb9, 0xc8, 0x25, 0xd2, 0x3b, 0xd0, 0xc9, 0x30, 0x76, 0xba, 0xb6, 0x6f, 0x4a, 0x7a, 0x0e, 0xfd, - 0x24, 0x9c, 0x61, 0xa2, 0x9c, 0x9e, 0x35, 0x78, 0xc6, 0x76, 0xdc, 0x08, 0x56, 0xdb, 0x06, 0x3b, - 0xb7, 0xb4, 0xd7, 0xa9, 0xce, 0xf2, 0xa0, 0xd4, 0x70, 0x5f, 0xc0, 0xb0, 0xd6, 0x36, 0x76, 0x9f, - 0x31, 0xb7, 0xa7, 0x35, 0x08, 0x4c, 0x49, 0xf7, 0xa1, 0xb7, 0x0e, 0x93, 0x15, 0x3a, 0x6d, 0xdb, - 0x2b, 0x7e, 0x8e, 0xdb, 0xcf, 0xc9, 0xf8, 0x14, 0xf6, 0x0a, 0xf5, 0xf2, 0xb4, 0xab, 0x09, 0x77, - 0x9a, 0x4e, 0x78, 0xfa, 0x8d, 0x40, 0xd7, 0x48, 0xd0, 0x8f, 0xd0, 0xb3, 0x93, 0xa3, 0x07, 0x3b, - 0x37, 0x53, 0xbf, 0x50, 0xee, 0xc3, 0x26, 0xd0, 0x32, 0xda, 0x87, 0xd2, 0x67, 0xd2, 0xf4, 0xac, - 0xdc, 0x83, 0x06, 0xc8, 0x42, 0xfc, 0xd5, 0xc5, 0xf5, 0xc6, 0x6b, 0xfd, 0xd8, 0x78, 0xad, 0x2f, - 0x5b, 0x8f, 0x5c, 0x6f, 0x3d, 0xf2, 0x7d, 0xeb, 0x91, 0x9f, 0x5b, 0x8f, 0xbc, 0x3f, 0xbe, 0xd1, - 0x6b, 0x3f, 0x31, 0xdf, 0x77, 0xad, 0x59, 0xdf, 0x3e, 0xa4, 0xa7, 0xbf, 0x02, 0x00, 0x00, 0xff, - 0xff, 0x61, 0xd1, 0x6e, 0x9e, 0x34, 0x04, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/diff/v1/diff.proto containerd-1.5.9/api/services/diff/v1/diff.proto --- containerd-1.2.6/api/services/diff/v1/diff.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/diff/v1/diff.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,8 +1,25 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.diff.v1; import weak "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; import "github.com/containerd/containerd/api/types/mount.proto"; import "github.com/containerd/containerd/api/types/descriptor.proto"; @@ -25,6 +42,8 @@ containerd.types.Descriptor diff = 1; repeated containerd.types.Mount mounts = 2; + + map payloads = 3; } message ApplyResponse { diff -Nru containerd-1.2.6/api/services/events/v1/events.pb.go containerd-1.5.9/api/services/events/v1/events.pb.go --- containerd-1.2.6/api/services/events/v1/events.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/events/v1/events.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,43 +1,25 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/events/v1/events.proto -/* - Package events is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/events/v1/events.proto - - It has these top-level messages: - PublishRequest - ForwardRequest - SubscribeRequest - Envelope -*/ package events -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import containerd_plugin "github.com/containerd/containerd/protobuf/plugin" -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" - -import time "time" - -import typeurl "github.com/containerd/typeurl" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + context "context" + fmt "fmt" + github_com_containerd_typeurl "github.com/containerd/typeurl" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -49,43 +31,167 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type PublishRequest struct { - Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` - Event *google_protobuf1.Any `protobuf:"bytes,2,opt,name=event" json:"event,omitempty"` + Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` + Event *types.Any `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PublishRequest) Reset() { *m = PublishRequest{} } +func (*PublishRequest) ProtoMessage() {} +func (*PublishRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_43fcd20dc1642376, []int{0} +} +func (m *PublishRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PublishRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PublishRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PublishRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PublishRequest.Merge(m, src) +} +func (m *PublishRequest) XXX_Size() int { + return m.Size() +} +func (m *PublishRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PublishRequest.DiscardUnknown(m) } -func (m *PublishRequest) Reset() { *m = PublishRequest{} } -func (*PublishRequest) ProtoMessage() {} -func (*PublishRequest) Descriptor() ([]byte, []int) { return fileDescriptorEvents, []int{0} } +var xxx_messageInfo_PublishRequest proto.InternalMessageInfo type ForwardRequest struct { - Envelope *Envelope `protobuf:"bytes,1,opt,name=envelope" json:"envelope,omitempty"` + Envelope *Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ForwardRequest) Reset() { *m = ForwardRequest{} } +func (*ForwardRequest) ProtoMessage() {} +func (*ForwardRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_43fcd20dc1642376, []int{1} +} +func (m *ForwardRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForwardRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForwardRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ForwardRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardRequest.Merge(m, src) +} +func (m *ForwardRequest) XXX_Size() int { + return m.Size() +} +func (m *ForwardRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardRequest.DiscardUnknown(m) } -func (m *ForwardRequest) Reset() { *m = ForwardRequest{} } -func (*ForwardRequest) ProtoMessage() {} -func (*ForwardRequest) Descriptor() ([]byte, []int) { return fileDescriptorEvents, []int{1} } +var xxx_messageInfo_ForwardRequest proto.InternalMessageInfo type SubscribeRequest struct { - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SubscribeRequest) Reset() { *m = SubscribeRequest{} } +func (*SubscribeRequest) ProtoMessage() {} +func (*SubscribeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_43fcd20dc1642376, []int{2} +} +func (m *SubscribeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SubscribeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SubscribeRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SubscribeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SubscribeRequest.Merge(m, src) +} +func (m *SubscribeRequest) XXX_Size() int { + return m.Size() +} +func (m *SubscribeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SubscribeRequest.DiscardUnknown(m) } -func (m *SubscribeRequest) Reset() { *m = SubscribeRequest{} } -func (*SubscribeRequest) ProtoMessage() {} -func (*SubscribeRequest) Descriptor() ([]byte, []int) { return fileDescriptorEvents, []int{2} } +var xxx_messageInfo_SubscribeRequest proto.InternalMessageInfo type Envelope struct { - Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,stdtime" json:"timestamp"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` - Event *google_protobuf1.Any `protobuf:"bytes,4,opt,name=event" json:"event,omitempty"` + Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` + Event *types.Any `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Envelope) Reset() { *m = Envelope{} } +func (*Envelope) ProtoMessage() {} +func (*Envelope) Descriptor() ([]byte, []int) { + return fileDescriptor_43fcd20dc1642376, []int{3} +} +func (m *Envelope) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Envelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Envelope.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Envelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_Envelope.Merge(m, src) +} +func (m *Envelope) XXX_Size() int { + return m.Size() +} +func (m *Envelope) XXX_DiscardUnknown() { + xxx_messageInfo_Envelope.DiscardUnknown(m) } -func (m *Envelope) Reset() { *m = Envelope{} } -func (*Envelope) ProtoMessage() {} -func (*Envelope) Descriptor() ([]byte, []int) { return fileDescriptorEvents, []int{3} } +var xxx_messageInfo_Envelope proto.InternalMessageInfo func init() { proto.RegisterType((*PublishRequest)(nil), "containerd.services.events.v1.PublishRequest") @@ -94,6 +200,44 @@ proto.RegisterType((*Envelope)(nil), "containerd.services.events.v1.Envelope") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/events/v1/events.proto", fileDescriptor_43fcd20dc1642376) +} + +var fileDescriptor_43fcd20dc1642376 = []byte{ + // 466 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcd, 0x8e, 0xd3, 0x30, + 0x14, 0x85, 0xeb, 0xf9, 0x6d, 0x3c, 0xd2, 0x08, 0x45, 0x15, 0x2a, 0x01, 0xd2, 0xaa, 0x1b, 0x2a, + 0x04, 0x0e, 0x53, 0x76, 0x20, 0x21, 0x28, 0x94, 0xf5, 0x28, 0x80, 0x54, 0xb1, 0x4b, 0xd2, 0xdb, + 0xd4, 0x52, 0x62, 0x9b, 0xd8, 0x09, 0x9a, 0xdd, 0x3c, 0x02, 0x1b, 0xde, 0x84, 0x0d, 0x6f, 0xd0, + 0x25, 0x4b, 0x56, 0xc0, 0xf4, 0x49, 0x50, 0x13, 0xbb, 0x61, 0x3a, 0x40, 0x10, 0xbb, 0x6b, 0xdf, + 0xe3, 0xcf, 0xb9, 0xe7, 0x38, 0xf8, 0x45, 0x4c, 0xd5, 0x22, 0x0f, 0x49, 0xc4, 0x53, 0x2f, 0xe2, + 0x4c, 0x05, 0x94, 0x41, 0x36, 0xfb, 0xb5, 0x0c, 0x04, 0xf5, 0x24, 0x64, 0x05, 0x8d, 0x40, 0x7a, + 0x50, 0x00, 0x53, 0xd2, 0x2b, 0x4e, 0x74, 0x45, 0x44, 0xc6, 0x15, 0xb7, 0x6f, 0xd7, 0x7a, 0x62, + 0xb4, 0x44, 0x2b, 0x8a, 0x13, 0xe7, 0x69, 0xe3, 0x25, 0x25, 0x26, 0xcc, 0xe7, 0x9e, 0x48, 0xf2, + 0x98, 0x32, 0x6f, 0x4e, 0x21, 0x99, 0x89, 0x40, 0x2d, 0xaa, 0x0b, 0x9c, 0x4e, 0xcc, 0x63, 0x5e, + 0x96, 0xde, 0xba, 0xd2, 0xbb, 0x37, 0x62, 0xce, 0xe3, 0x04, 0xea, 0xd3, 0x01, 0x3b, 0xd3, 0xad, + 0x9b, 0xdb, 0x2d, 0x48, 0x85, 0x32, 0xcd, 0xde, 0x76, 0x53, 0xd1, 0x14, 0xa4, 0x0a, 0x52, 0x51, + 0x09, 0x06, 0x3e, 0x3e, 0x3e, 0xcd, 0xc3, 0x84, 0xca, 0x85, 0x0f, 0xef, 0x72, 0x90, 0xca, 0xee, + 0xe0, 0x7d, 0xc5, 0x05, 0x8d, 0xba, 0xa8, 0x8f, 0x86, 0x96, 0x5f, 0x2d, 0xec, 0xbb, 0x78, 0xbf, + 0x9c, 0xb2, 0xbb, 0xd3, 0x47, 0xc3, 0xa3, 0x51, 0x87, 0x54, 0x60, 0x62, 0xc0, 0xe4, 0x19, 0x3b, + 0xf3, 0x2b, 0xc9, 0xe0, 0x0d, 0x3e, 0x7e, 0xc9, 0xb3, 0xf7, 0x41, 0x36, 0x33, 0xcc, 0xe7, 0xb8, + 0x0d, 0xac, 0x80, 0x84, 0x0b, 0x28, 0xb1, 0x47, 0xa3, 0x3b, 0xe4, 0xaf, 0x46, 0x92, 0x89, 0x96, + 0xfb, 0x9b, 0x83, 0x83, 0x7b, 0xf8, 0xda, 0xab, 0x3c, 0x94, 0x51, 0x46, 0x43, 0x30, 0xe0, 0x2e, + 0x3e, 0x9c, 0xd3, 0x44, 0x41, 0x26, 0xbb, 0xa8, 0xbf, 0x3b, 0xb4, 0x7c, 0xb3, 0x1c, 0x7c, 0x42, + 0xb8, 0x6d, 0x20, 0xf6, 0x18, 0x5b, 0x9b, 0xc1, 0xf5, 0x07, 0x38, 0x57, 0x26, 0x78, 0x6d, 0x14, + 0xe3, 0xf6, 0xf2, 0x5b, 0xaf, 0xf5, 0xe1, 0x7b, 0x0f, 0xf9, 0xf5, 0x31, 0xfb, 0x16, 0xb6, 0x58, + 0x90, 0x82, 0x14, 0x41, 0x04, 0xa5, 0x0b, 0x96, 0x5f, 0x6f, 0xd4, 0xae, 0xed, 0xfe, 0xd6, 0xb5, + 0xbd, 0x46, 0xd7, 0x1e, 0xed, 0x9d, 0x7f, 0xee, 0xa1, 0xd1, 0xc7, 0x1d, 0x7c, 0x30, 0x29, 0x5d, + 0xb0, 0x4f, 0xf1, 0xa1, 0x8e, 0xc6, 0xbe, 0xdf, 0xe0, 0xd6, 0xe5, 0x08, 0x9d, 0xeb, 0x57, 0xee, + 0x99, 0xac, 0xdf, 0xc4, 0x9a, 0xa8, 0x83, 0x69, 0x24, 0x5e, 0x0e, 0xf0, 0x8f, 0xc4, 0x18, 0x5b, + 0x9b, 0x4c, 0x6c, 0xaf, 0x81, 0xb9, 0x9d, 0x9e, 0xf3, 0xaf, 0x8f, 0xe0, 0x01, 0x1a, 0x4f, 0x97, + 0x17, 0x6e, 0xeb, 0xeb, 0x85, 0xdb, 0x3a, 0x5f, 0xb9, 0x68, 0xb9, 0x72, 0xd1, 0x97, 0x95, 0x8b, + 0x7e, 0xac, 0x5c, 0xf4, 0xf6, 0xc9, 0x7f, 0xfe, 0xd7, 0x8f, 0xab, 0x6a, 0xda, 0x9a, 0xa2, 0xf0, + 0xa0, 0x1c, 0xeb, 0xe1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe6, 0xbf, 0x19, 0xa6, 0x24, 0x04, + 0x00, 0x00, +} + // Field returns the value for the given fieldpath as a string, if defined. // If the value is not defined, the second value will be false. func (m *Envelope) Field(fieldpath []string) (string, bool) { @@ -108,7 +252,7 @@ case "topic": return string(m.Topic), len(m.Topic) > 0 case "event": - decoded, err := typeurl.UnmarshalAny(m.Event) + decoded, err := github_com_containerd_typeurl.UnmarshalAny(m.Event) if err != nil { return "", false } @@ -130,20 +274,21 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Events service - +// EventsClient is the client API for Events service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type EventsClient interface { // Publish an event to a topic. // // The event will be packed into a timestamp envelope with the namespace // introspected from the context. The envelope will then be dispatched. - Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) + Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*types.Empty, error) // Forward sends an event that has already been packaged into an envelope // with a timestamp and namespace. // // This is useful if earlier timestamping is required or when forwarding on // behalf of another component, namespace or publisher. - Forward(ctx context.Context, in *ForwardRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) + Forward(ctx context.Context, in *ForwardRequest, opts ...grpc.CallOption) (*types.Empty, error) // Subscribe to a stream of events, possibly returning only that match any // of the provided filters. // @@ -162,18 +307,18 @@ return &eventsClient{cc} } -func (c *eventsClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) { - out := new(google_protobuf2.Empty) - err := grpc.Invoke(ctx, "/containerd.services.events.v1.Events/Publish", in, out, c.cc, opts...) +func (c *eventsClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.events.v1.Events/Publish", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *eventsClient) Forward(ctx context.Context, in *ForwardRequest, opts ...grpc.CallOption) (*google_protobuf2.Empty, error) { - out := new(google_protobuf2.Empty) - err := grpc.Invoke(ctx, "/containerd.services.events.v1.Events/Forward", in, out, c.cc, opts...) +func (c *eventsClient) Forward(ctx context.Context, in *ForwardRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.events.v1.Events/Forward", in, out, opts...) if err != nil { return nil, err } @@ -181,7 +326,7 @@ } func (c *eventsClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (Events_SubscribeClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Events_serviceDesc.Streams[0], c.cc, "/containerd.services.events.v1.Events/Subscribe", opts...) + stream, err := c.cc.NewStream(ctx, &_Events_serviceDesc.Streams[0], "/containerd.services.events.v1.Events/Subscribe", opts...) if err != nil { return nil, err } @@ -212,20 +357,19 @@ return m, nil } -// Server API for Events service - +// EventsServer is the server API for Events service. type EventsServer interface { // Publish an event to a topic. // // The event will be packed into a timestamp envelope with the namespace // introspected from the context. The envelope will then be dispatched. - Publish(context.Context, *PublishRequest) (*google_protobuf2.Empty, error) + Publish(context.Context, *PublishRequest) (*types.Empty, error) // Forward sends an event that has already been packaged into an envelope // with a timestamp and namespace. // // This is useful if earlier timestamping is required or when forwarding on // behalf of another component, namespace or publisher. - Forward(context.Context, *ForwardRequest) (*google_protobuf2.Empty, error) + Forward(context.Context, *ForwardRequest) (*types.Empty, error) // Subscribe to a stream of events, possibly returning only that match any // of the provided filters. // @@ -236,6 +380,20 @@ Subscribe(*SubscribeRequest, Events_SubscribeServer) error } +// UnimplementedEventsServer can be embedded to have forward compatible implementations. +type UnimplementedEventsServer struct { +} + +func (*UnimplementedEventsServer) Publish(ctx context.Context, req *PublishRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Publish not implemented") +} +func (*UnimplementedEventsServer) Forward(ctx context.Context, req *ForwardRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Forward not implemented") +} +func (*UnimplementedEventsServer) Subscribe(req *SubscribeRequest, srv Events_SubscribeServer) error { + return status.Errorf(codes.Unimplemented, "method Subscribe not implemented") +} + func RegisterEventsServer(s *grpc.Server, srv EventsServer) { s.RegisterService(&_Events_serviceDesc, srv) } @@ -323,7 +481,7 @@ func (m *PublishRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -331,33 +489,45 @@ } func (m *PublishRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PublishRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Topic) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintEvents(dAtA, i, uint64(len(m.Topic))) - i += copy(dAtA[i:], m.Topic) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Event != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintEvents(dAtA, i, uint64(m.Event.Size())) - n1, err := m.Event.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Event.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) } - i += n1 + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Topic) > 0 { + i -= len(m.Topic) + copy(dAtA[i:], m.Topic) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Topic))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ForwardRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -365,27 +535,38 @@ } func (m *ForwardRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForwardRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Envelope != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintEvents(dAtA, i, uint64(m.Envelope.Size())) - n2, err := m.Envelope.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Envelope.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *SubscribeRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -393,32 +574,35 @@ } func (m *SubscribeRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SubscribeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *Envelope) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -426,53 +610,71 @@ } func (m *Envelope) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Envelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintEvents(dAtA, i, uint64(types.SizeOfStdTime(m.Timestamp))) - n3, err := types.StdTimeMarshalTo(m.Timestamp, dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n3 - if len(m.Namespace) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintEvents(dAtA, i, uint64(len(m.Namespace))) - i += copy(dAtA[i:], m.Namespace) + if m.Event != nil { + { + size, err := m.Event.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } if len(m.Topic) > 0 { - dAtA[i] = 0x1a - i++ + i -= len(m.Topic) + copy(dAtA[i:], m.Topic) i = encodeVarintEvents(dAtA, i, uint64(len(m.Topic))) - i += copy(dAtA[i:], m.Topic) + i-- + dAtA[i] = 0x1a } - if m.Event != nil { - dAtA[i] = 0x22 - i++ - i = encodeVarintEvents(dAtA, i, uint64(m.Event.Size())) - n4, err := m.Event.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n4 + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x12 } - return i, nil + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintEvents(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *PublishRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Topic) @@ -483,20 +685,32 @@ l = m.Event.Size() n += 1 + l + sovEvents(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ForwardRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Envelope != nil { l = m.Envelope.Size() n += 1 + l + sovEvents(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *SubscribeRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -505,13 +719,19 @@ n += 1 + l + sovEvents(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *Envelope) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l - l = types.SizeOfStdTime(m.Timestamp) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) n += 1 + l + sovEvents(uint64(l)) l = len(m.Namespace) if l > 0 { @@ -525,18 +745,14 @@ l = m.Event.Size() n += 1 + l + sovEvents(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovEvents(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozEvents(x uint64) (n int) { return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -547,7 +763,8 @@ } s := strings.Join([]string{`&PublishRequest{`, `Topic:` + fmt.Sprintf("%v", this.Topic) + `,`, - `Event:` + strings.Replace(fmt.Sprintf("%v", this.Event), "Any", "google_protobuf1.Any", 1) + `,`, + `Event:` + strings.Replace(fmt.Sprintf("%v", this.Event), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -557,7 +774,8 @@ return "nil" } s := strings.Join([]string{`&ForwardRequest{`, - `Envelope:` + strings.Replace(fmt.Sprintf("%v", this.Envelope), "Envelope", "Envelope", 1) + `,`, + `Envelope:` + strings.Replace(this.Envelope.String(), "Envelope", "Envelope", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -568,6 +786,7 @@ } s := strings.Join([]string{`&SubscribeRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -577,10 +796,11 @@ return "nil" } s := strings.Join([]string{`&Envelope{`, - `Timestamp:` + strings.Replace(strings.Replace(this.Timestamp.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `Timestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Timestamp), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, `Topic:` + fmt.Sprintf("%v", this.Topic) + `,`, - `Event:` + strings.Replace(fmt.Sprintf("%v", this.Event), "Any", "google_protobuf1.Any", 1) + `,`, + `Event:` + strings.Replace(fmt.Sprintf("%v", this.Event), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -608,7 +828,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -636,7 +856,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -646,6 +866,9 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -665,7 +888,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -674,11 +897,14 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Event == nil { - m.Event = &google_protobuf1.Any{} + m.Event = &types.Any{} } if err := m.Event.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -690,12 +916,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthEvents } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -720,7 +947,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -748,7 +975,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -757,6 +984,9 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -773,12 +1003,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthEvents } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -803,7 +1034,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -831,7 +1062,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -841,6 +1072,9 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -852,12 +1086,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthEvents } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -882,7 +1117,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -910,7 +1145,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -919,10 +1154,13 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -940,7 +1178,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -950,6 +1188,9 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -969,7 +1210,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -979,6 +1220,9 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -998,7 +1242,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1007,11 +1251,14 @@ return ErrInvalidLengthEvents } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Event == nil { - m.Event = &google_protobuf1.Any{} + m.Event = &types.Any{} } if err := m.Event.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1023,12 +1270,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthEvents } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1041,6 +1289,7 @@ func skipEvents(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1072,10 +1321,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1092,91 +1339,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthEvents } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowEvents - } - 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 := skipEvents(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/events/v1/events.proto", fileDescriptorEvents) -} - -var fileDescriptorEvents = []byte{ - // 466 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcd, 0x8e, 0xd3, 0x30, - 0x14, 0x85, 0xeb, 0xf9, 0x6d, 0x3c, 0xd2, 0x08, 0x45, 0x15, 0x2a, 0x01, 0xd2, 0xaa, 0x1b, 0x2a, - 0x04, 0x0e, 0x53, 0x76, 0x20, 0x21, 0x28, 0x94, 0xf5, 0x28, 0x80, 0x54, 0xb1, 0x4b, 0xd2, 0xdb, - 0xd4, 0x52, 0x62, 0x9b, 0xd8, 0x09, 0x9a, 0xdd, 0x3c, 0x02, 0x1b, 0xde, 0x84, 0x0d, 0x6f, 0xd0, - 0x25, 0x4b, 0x56, 0xc0, 0xf4, 0x49, 0x50, 0x13, 0xbb, 0x61, 0x3a, 0x40, 0x10, 0xbb, 0x6b, 0xdf, - 0xe3, 0xcf, 0xb9, 0xe7, 0x38, 0xf8, 0x45, 0x4c, 0xd5, 0x22, 0x0f, 0x49, 0xc4, 0x53, 0x2f, 0xe2, - 0x4c, 0x05, 0x94, 0x41, 0x36, 0xfb, 0xb5, 0x0c, 0x04, 0xf5, 0x24, 0x64, 0x05, 0x8d, 0x40, 0x7a, - 0x50, 0x00, 0x53, 0xd2, 0x2b, 0x4e, 0x74, 0x45, 0x44, 0xc6, 0x15, 0xb7, 0x6f, 0xd7, 0x7a, 0x62, - 0xb4, 0x44, 0x2b, 0x8a, 0x13, 0xe7, 0x69, 0xe3, 0x25, 0x25, 0x26, 0xcc, 0xe7, 0x9e, 0x48, 0xf2, - 0x98, 0x32, 0x6f, 0x4e, 0x21, 0x99, 0x89, 0x40, 0x2d, 0xaa, 0x0b, 0x9c, 0x4e, 0xcc, 0x63, 0x5e, - 0x96, 0xde, 0xba, 0xd2, 0xbb, 0x37, 0x62, 0xce, 0xe3, 0x04, 0xea, 0xd3, 0x01, 0x3b, 0xd3, 0xad, - 0x9b, 0xdb, 0x2d, 0x48, 0x85, 0x32, 0xcd, 0xde, 0x76, 0x53, 0xd1, 0x14, 0xa4, 0x0a, 0x52, 0x51, - 0x09, 0x06, 0x3e, 0x3e, 0x3e, 0xcd, 0xc3, 0x84, 0xca, 0x85, 0x0f, 0xef, 0x72, 0x90, 0xca, 0xee, - 0xe0, 0x7d, 0xc5, 0x05, 0x8d, 0xba, 0xa8, 0x8f, 0x86, 0x96, 0x5f, 0x2d, 0xec, 0xbb, 0x78, 0xbf, - 0x9c, 0xb2, 0xbb, 0xd3, 0x47, 0xc3, 0xa3, 0x51, 0x87, 0x54, 0x60, 0x62, 0xc0, 0xe4, 0x19, 0x3b, - 0xf3, 0x2b, 0xc9, 0xe0, 0x0d, 0x3e, 0x7e, 0xc9, 0xb3, 0xf7, 0x41, 0x36, 0x33, 0xcc, 0xe7, 0xb8, - 0x0d, 0xac, 0x80, 0x84, 0x0b, 0x28, 0xb1, 0x47, 0xa3, 0x3b, 0xe4, 0xaf, 0x46, 0x92, 0x89, 0x96, - 0xfb, 0x9b, 0x83, 0x83, 0x7b, 0xf8, 0xda, 0xab, 0x3c, 0x94, 0x51, 0x46, 0x43, 0x30, 0xe0, 0x2e, - 0x3e, 0x9c, 0xd3, 0x44, 0x41, 0x26, 0xbb, 0xa8, 0xbf, 0x3b, 0xb4, 0x7c, 0xb3, 0x1c, 0x7c, 0x42, - 0xb8, 0x6d, 0x20, 0xf6, 0x18, 0x5b, 0x9b, 0xc1, 0xf5, 0x07, 0x38, 0x57, 0x26, 0x78, 0x6d, 0x14, - 0xe3, 0xf6, 0xf2, 0x5b, 0xaf, 0xf5, 0xe1, 0x7b, 0x0f, 0xf9, 0xf5, 0x31, 0xfb, 0x16, 0xb6, 0x58, - 0x90, 0x82, 0x14, 0x41, 0x04, 0xa5, 0x0b, 0x96, 0x5f, 0x6f, 0xd4, 0xae, 0xed, 0xfe, 0xd6, 0xb5, - 0xbd, 0x46, 0xd7, 0x1e, 0xed, 0x9d, 0x7f, 0xee, 0xa1, 0xd1, 0xc7, 0x1d, 0x7c, 0x30, 0x29, 0x5d, - 0xb0, 0x4f, 0xf1, 0xa1, 0x8e, 0xc6, 0xbe, 0xdf, 0xe0, 0xd6, 0xe5, 0x08, 0x9d, 0xeb, 0x57, 0xee, - 0x99, 0xac, 0xdf, 0xc4, 0x9a, 0xa8, 0x83, 0x69, 0x24, 0x5e, 0x0e, 0xf0, 0x8f, 0xc4, 0x18, 0x5b, - 0x9b, 0x4c, 0x6c, 0xaf, 0x81, 0xb9, 0x9d, 0x9e, 0xf3, 0xaf, 0x8f, 0xe0, 0x01, 0x1a, 0x4f, 0x97, - 0x17, 0x6e, 0xeb, 0xeb, 0x85, 0xdb, 0x3a, 0x5f, 0xb9, 0x68, 0xb9, 0x72, 0xd1, 0x97, 0x95, 0x8b, - 0x7e, 0xac, 0x5c, 0xf4, 0xf6, 0xc9, 0x7f, 0xfe, 0xd7, 0x8f, 0xab, 0x6a, 0xda, 0x9a, 0xa2, 0xf0, - 0xa0, 0x1c, 0xeb, 0xe1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe6, 0xbf, 0x19, 0xa6, 0x24, 0x04, - 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/events/v1/events.proto containerd-1.5.9/api/services/events/v1/events.proto --- containerd-1.2.6/api/services/events/v1/events.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/events/v1/events.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.events.v1; diff -Nru containerd-1.2.6/api/services/images/v1/images.pb.go containerd-1.5.9/api/services/images/v1/images.pb.go --- containerd-1.2.6/api/services/images/v1/images.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/images/v1/images.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,48 +1,26 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/images/v1/images.proto -/* - Package images is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/images/v1/images.proto - - It has these top-level messages: - Image - GetImageRequest - GetImageResponse - CreateImageRequest - CreateImageResponse - UpdateImageRequest - UpdateImageResponse - ListImagesRequest - ListImagesResponse - DeleteImageRequest -*/ package images -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" -import containerd_types "github.com/containerd/containerd/api/types" - -import time "time" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types1 "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -54,7 +32,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Image struct { // Name provides a unique name for the image. @@ -66,72 +44,289 @@ // // Labels may be updated using the field mask. // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Target describes the content entry point of the image. - Target containerd_types.Descriptor `protobuf:"bytes,3,opt,name=target" json:"target"` + Target types.Descriptor `protobuf:"bytes,3,opt,name=target,proto3" json:"target"` // CreatedAt is the time the image was first created. - CreatedAt time.Time `protobuf:"bytes,7,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + CreatedAt time.Time `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` // UpdatedAt is the last time the image was mutated. - UpdatedAt time.Time `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + UpdatedAt time.Time `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Image) Reset() { *m = Image{} } +func (*Image) ProtoMessage() {} +func (*Image) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{0} +} +func (m *Image) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Image) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Image.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Image) XXX_Merge(src proto.Message) { + xxx_messageInfo_Image.Merge(m, src) +} +func (m *Image) XXX_Size() int { + return m.Size() +} +func (m *Image) XXX_DiscardUnknown() { + xxx_messageInfo_Image.DiscardUnknown(m) } -func (m *Image) Reset() { *m = Image{} } -func (*Image) ProtoMessage() {} -func (*Image) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{0} } +var xxx_messageInfo_Image proto.InternalMessageInfo type GetImageRequest struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetImageRequest) Reset() { *m = GetImageRequest{} } +func (*GetImageRequest) ProtoMessage() {} +func (*GetImageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{1} +} +func (m *GetImageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetImageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetImageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetImageRequest.Merge(m, src) +} +func (m *GetImageRequest) XXX_Size() int { + return m.Size() +} +func (m *GetImageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetImageRequest.DiscardUnknown(m) } -func (m *GetImageRequest) Reset() { *m = GetImageRequest{} } -func (*GetImageRequest) ProtoMessage() {} -func (*GetImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{1} } +var xxx_messageInfo_GetImageRequest proto.InternalMessageInfo type GetImageResponse struct { - Image *Image `protobuf:"bytes,1,opt,name=image" json:"image,omitempty"` + Image *Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetImageResponse) Reset() { *m = GetImageResponse{} } +func (*GetImageResponse) ProtoMessage() {} +func (*GetImageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{2} +} +func (m *GetImageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetImageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetImageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetImageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetImageResponse.Merge(m, src) +} +func (m *GetImageResponse) XXX_Size() int { + return m.Size() +} +func (m *GetImageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetImageResponse.DiscardUnknown(m) } -func (m *GetImageResponse) Reset() { *m = GetImageResponse{} } -func (*GetImageResponse) ProtoMessage() {} -func (*GetImageResponse) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{2} } +var xxx_messageInfo_GetImageResponse proto.InternalMessageInfo type CreateImageRequest struct { - Image Image `protobuf:"bytes,1,opt,name=image" json:"image"` + Image Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateImageRequest) Reset() { *m = CreateImageRequest{} } +func (*CreateImageRequest) ProtoMessage() {} +func (*CreateImageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{3} +} +func (m *CreateImageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateImageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateImageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateImageRequest.Merge(m, src) +} +func (m *CreateImageRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateImageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateImageRequest.DiscardUnknown(m) } -func (m *CreateImageRequest) Reset() { *m = CreateImageRequest{} } -func (*CreateImageRequest) ProtoMessage() {} -func (*CreateImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{3} } +var xxx_messageInfo_CreateImageRequest proto.InternalMessageInfo type CreateImageResponse struct { - Image Image `protobuf:"bytes,1,opt,name=image" json:"image"` + Image Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateImageResponse) Reset() { *m = CreateImageResponse{} } +func (*CreateImageResponse) ProtoMessage() {} +func (*CreateImageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{4} +} +func (m *CreateImageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateImageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateImageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateImageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateImageResponse.Merge(m, src) +} +func (m *CreateImageResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateImageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateImageResponse.DiscardUnknown(m) } -func (m *CreateImageResponse) Reset() { *m = CreateImageResponse{} } -func (*CreateImageResponse) ProtoMessage() {} -func (*CreateImageResponse) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{4} } +var xxx_messageInfo_CreateImageResponse proto.InternalMessageInfo type UpdateImageRequest struct { // Image provides a full or partial image for update. // // The name field must be set or an error will be returned. - Image Image `protobuf:"bytes,1,opt,name=image" json:"image"` + Image Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image"` // UpdateMask specifies which fields to perform the update on. If empty, // the operation applies to all fields. - UpdateMask *google_protobuf2.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` + UpdateMask *types1.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateImageRequest) Reset() { *m = UpdateImageRequest{} } +func (*UpdateImageRequest) ProtoMessage() {} +func (*UpdateImageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{5} +} +func (m *UpdateImageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateImageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateImageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateImageRequest.Merge(m, src) +} +func (m *UpdateImageRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateImageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateImageRequest.DiscardUnknown(m) } -func (m *UpdateImageRequest) Reset() { *m = UpdateImageRequest{} } -func (*UpdateImageRequest) ProtoMessage() {} -func (*UpdateImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{5} } +var xxx_messageInfo_UpdateImageRequest proto.InternalMessageInfo type UpdateImageResponse struct { - Image Image `protobuf:"bytes,1,opt,name=image" json:"image"` + Image Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateImageResponse) Reset() { *m = UpdateImageResponse{} } +func (*UpdateImageResponse) ProtoMessage() {} +func (*UpdateImageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{6} +} +func (m *UpdateImageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateImageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateImageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateImageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateImageResponse.Merge(m, src) +} +func (m *UpdateImageResponse) XXX_Size() int { + return m.Size() +} +func (m *UpdateImageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateImageResponse.DiscardUnknown(m) } -func (m *UpdateImageResponse) Reset() { *m = UpdateImageResponse{} } -func (*UpdateImageResponse) ProtoMessage() {} -func (*UpdateImageResponse) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{6} } +var xxx_messageInfo_UpdateImageResponse proto.InternalMessageInfo type ListImagesRequest struct { // Filters contains one or more filters using the syntax defined in the @@ -144,20 +339,82 @@ // filters[0] or filters[1] or ... or filters[n-1] or filters[n] // // If filters is zero-length or nil, all items will be returned. - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListImagesRequest) Reset() { *m = ListImagesRequest{} } +func (*ListImagesRequest) ProtoMessage() {} +func (*ListImagesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{7} +} +func (m *ListImagesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListImagesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListImagesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListImagesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListImagesRequest.Merge(m, src) +} +func (m *ListImagesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListImagesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListImagesRequest.DiscardUnknown(m) } -func (m *ListImagesRequest) Reset() { *m = ListImagesRequest{} } -func (*ListImagesRequest) ProtoMessage() {} -func (*ListImagesRequest) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{7} } +var xxx_messageInfo_ListImagesRequest proto.InternalMessageInfo type ListImagesResponse struct { - Images []Image `protobuf:"bytes,1,rep,name=images" json:"images"` + Images []Image `protobuf:"bytes,1,rep,name=images,proto3" json:"images"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListImagesResponse) Reset() { *m = ListImagesResponse{} } +func (*ListImagesResponse) ProtoMessage() {} +func (*ListImagesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{8} +} +func (m *ListImagesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListImagesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListImagesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListImagesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListImagesResponse.Merge(m, src) +} +func (m *ListImagesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListImagesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListImagesResponse.DiscardUnknown(m) } -func (m *ListImagesResponse) Reset() { *m = ListImagesResponse{} } -func (*ListImagesResponse) ProtoMessage() {} -func (*ListImagesResponse) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{8} } +var xxx_messageInfo_ListImagesResponse proto.InternalMessageInfo type DeleteImageRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -165,15 +422,47 @@ // synchronously before returning to the caller // // Default is false - Sync bool `protobuf:"varint,2,opt,name=sync,proto3" json:"sync,omitempty"` + Sync bool `protobuf:"varint,2,opt,name=sync,proto3" json:"sync,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteImageRequest) Reset() { *m = DeleteImageRequest{} } +func (*DeleteImageRequest) ProtoMessage() {} +func (*DeleteImageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8666fa071128ae5f, []int{9} +} +func (m *DeleteImageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteImageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteImageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteImageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteImageRequest.Merge(m, src) +} +func (m *DeleteImageRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteImageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteImageRequest.DiscardUnknown(m) } -func (m *DeleteImageRequest) Reset() { *m = DeleteImageRequest{} } -func (*DeleteImageRequest) ProtoMessage() {} -func (*DeleteImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorImages, []int{9} } +var xxx_messageInfo_DeleteImageRequest proto.InternalMessageInfo func init() { proto.RegisterType((*Image)(nil), "containerd.services.images.v1.Image") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.images.v1.Image.LabelsEntry") proto.RegisterType((*GetImageRequest)(nil), "containerd.services.images.v1.GetImageRequest") proto.RegisterType((*GetImageResponse)(nil), "containerd.services.images.v1.GetImageResponse") proto.RegisterType((*CreateImageRequest)(nil), "containerd.services.images.v1.CreateImageRequest") @@ -185,6 +474,56 @@ proto.RegisterType((*DeleteImageRequest)(nil), "containerd.services.images.v1.DeleteImageRequest") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/images/v1/images.proto", fileDescriptor_8666fa071128ae5f) +} + +var fileDescriptor_8666fa071128ae5f = []byte{ + // 659 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0x8e, 0x93, 0xd4, 0x6d, 0x27, 0x07, 0xca, 0x52, 0x21, 0xcb, 0x40, 0x1a, 0x45, 0x20, 0xe5, + 0xc2, 0x9a, 0x86, 0x0b, 0xb4, 0x08, 0xd1, 0xb4, 0xa5, 0x20, 0x15, 0x0e, 0xe6, 0xaf, 0xe2, 0x52, + 0x6d, 0x92, 0x89, 0xb1, 0x62, 0xc7, 0xc6, 0xbb, 0x89, 0x94, 0x1b, 0x8f, 0x80, 0x04, 0x0f, 0xd5, + 0x23, 0x47, 0x4e, 0x40, 0x73, 0xe0, 0x39, 0x90, 0x77, 0x37, 0x34, 0x4d, 0x22, 0x92, 0x94, 0xde, + 0x66, 0xed, 0xef, 0x9b, 0x9f, 0x6f, 0x66, 0x76, 0x61, 0xcf, 0xf3, 0xc5, 0x87, 0x6e, 0x9d, 0x36, + 0xa2, 0xd0, 0x69, 0x44, 0x1d, 0xc1, 0xfc, 0x0e, 0x26, 0xcd, 0x51, 0x93, 0xc5, 0xbe, 0xc3, 0x31, + 0xe9, 0xf9, 0x0d, 0xe4, 0x8e, 0x1f, 0x32, 0x0f, 0xb9, 0xd3, 0xdb, 0xd4, 0x16, 0x8d, 0x93, 0x48, + 0x44, 0xe4, 0xd6, 0x19, 0x9e, 0x0e, 0xb1, 0x54, 0x23, 0x7a, 0x9b, 0xf6, 0xba, 0x17, 0x79, 0x91, + 0x44, 0x3a, 0xa9, 0xa5, 0x48, 0xf6, 0x0d, 0x2f, 0x8a, 0xbc, 0x00, 0x1d, 0x79, 0xaa, 0x77, 0x5b, + 0x0e, 0x86, 0xb1, 0xe8, 0xeb, 0x9f, 0xa5, 0xf1, 0x9f, 0x2d, 0x1f, 0x83, 0xe6, 0x71, 0xc8, 0x78, + 0x5b, 0x23, 0x36, 0xc6, 0x11, 0xc2, 0x0f, 0x91, 0x0b, 0x16, 0xc6, 0x1a, 0xb0, 0x3d, 0x57, 0x69, + 0xa2, 0x1f, 0x23, 0x77, 0x9a, 0xc8, 0x1b, 0x89, 0x1f, 0x8b, 0x28, 0x51, 0xe4, 0xf2, 0xef, 0x2c, + 0x2c, 0x3d, 0x4f, 0x0b, 0x20, 0x04, 0xf2, 0x1d, 0x16, 0xa2, 0x65, 0x94, 0x8c, 0xca, 0xaa, 0x2b, + 0x6d, 0xf2, 0x0c, 0xcc, 0x80, 0xd5, 0x31, 0xe0, 0x56, 0xb6, 0x94, 0xab, 0x14, 0xaa, 0xf7, 0xe8, + 0x3f, 0x05, 0xa0, 0xd2, 0x13, 0x3d, 0x94, 0x94, 0xfd, 0x8e, 0x48, 0xfa, 0xae, 0xe6, 0x93, 0x2d, + 0x30, 0x05, 0x4b, 0x3c, 0x14, 0x56, 0xae, 0x64, 0x54, 0x0a, 0xd5, 0x9b, 0xa3, 0x9e, 0x64, 0x6e, + 0x74, 0xef, 0x6f, 0x6e, 0xb5, 0xfc, 0xc9, 0x8f, 0x8d, 0x8c, 0xab, 0x19, 0x64, 0x17, 0xa0, 0x91, + 0x20, 0x13, 0xd8, 0x3c, 0x66, 0xc2, 0x5a, 0x96, 0x7c, 0x9b, 0x2a, 0x59, 0xe8, 0x50, 0x16, 0xfa, + 0x7a, 0x28, 0x4b, 0x6d, 0x25, 0x65, 0x7f, 0xfe, 0xb9, 0x61, 0xb8, 0xab, 0x9a, 0xb7, 0x23, 0x9d, + 0x74, 0xe3, 0xe6, 0xd0, 0xc9, 0xca, 0x22, 0x4e, 0x34, 0x6f, 0x47, 0xd8, 0x0f, 0xa1, 0x30, 0x52, + 0x1c, 0x59, 0x83, 0x5c, 0x1b, 0xfb, 0x5a, 0xb1, 0xd4, 0x24, 0xeb, 0xb0, 0xd4, 0x63, 0x41, 0x17, + 0xad, 0xac, 0xfc, 0xa6, 0x0e, 0x5b, 0xd9, 0x07, 0x46, 0xf9, 0x0e, 0x5c, 0x39, 0x40, 0x21, 0x05, + 0x72, 0xf1, 0x63, 0x17, 0xb9, 0x98, 0xa6, 0x78, 0xf9, 0x25, 0xac, 0x9d, 0xc1, 0x78, 0x1c, 0x75, + 0x38, 0x92, 0x2d, 0x58, 0x92, 0x12, 0x4b, 0x60, 0xa1, 0x7a, 0x7b, 0x9e, 0x26, 0xb8, 0x8a, 0x52, + 0x7e, 0x0b, 0x64, 0x57, 0x6a, 0x70, 0x2e, 0xf2, 0x93, 0x0b, 0x78, 0xd4, 0x4d, 0xd1, 0x7e, 0xdf, + 0xc1, 0xb5, 0x73, 0x7e, 0x75, 0xaa, 0xff, 0xef, 0xf8, 0x8b, 0x01, 0xe4, 0x8d, 0x14, 0xfc, 0x72, + 0x33, 0x26, 0xdb, 0x50, 0x50, 0x8d, 0x94, 0xcb, 0x25, 0x1b, 0x34, 0x6d, 0x02, 0x9e, 0xa6, 0xfb, + 0xf7, 0x82, 0xf1, 0xb6, 0xab, 0xe7, 0x25, 0xb5, 0xd3, 0x72, 0xcf, 0x25, 0x75, 0x69, 0xe5, 0xde, + 0x85, 0xab, 0x87, 0x3e, 0x57, 0x0d, 0xe7, 0xc3, 0x62, 0x2d, 0x58, 0x6e, 0xf9, 0x81, 0xc0, 0x84, + 0x5b, 0x46, 0x29, 0x57, 0x59, 0x75, 0x87, 0xc7, 0xf2, 0x11, 0x90, 0x51, 0xb8, 0x4e, 0xa3, 0x06, + 0xa6, 0x0a, 0x22, 0xe1, 0x8b, 0xe5, 0xa1, 0x99, 0xe5, 0x47, 0x40, 0xf6, 0x30, 0xc0, 0x31, 0xd9, + 0xa7, 0x5d, 0x0a, 0x04, 0xf2, 0xbc, 0xdf, 0x69, 0x48, 0x05, 0x57, 0x5c, 0x69, 0x57, 0xbf, 0xe6, + 0xc1, 0x54, 0x49, 0x91, 0x16, 0xe4, 0x0e, 0x50, 0x10, 0x3a, 0x23, 0x87, 0xb1, 0x65, 0xb0, 0x9d, + 0xb9, 0xf1, 0xba, 0xe8, 0x36, 0xe4, 0x53, 0x29, 0xc8, 0xac, 0x3b, 0x69, 0x42, 0x5e, 0x7b, 0x73, + 0x01, 0x86, 0x0e, 0x16, 0x81, 0xa9, 0xc6, 0x9d, 0xcc, 0x22, 0x4f, 0x6e, 0x9b, 0x5d, 0x5d, 0x84, + 0x72, 0x16, 0x50, 0x0d, 0xdc, 0xcc, 0x80, 0x93, 0xcb, 0x32, 0x33, 0xe0, 0xb4, 0x51, 0x7e, 0x05, + 0xa6, 0xea, 0xff, 0xcc, 0x80, 0x93, 0x63, 0x62, 0x5f, 0x9f, 0x58, 0xa3, 0xfd, 0xf4, 0x8d, 0xab, + 0x1d, 0x9d, 0x9c, 0x16, 0x33, 0xdf, 0x4f, 0x8b, 0x99, 0x4f, 0x83, 0xa2, 0x71, 0x32, 0x28, 0x1a, + 0xdf, 0x06, 0x45, 0xe3, 0xd7, 0xa0, 0x68, 0xbc, 0x7f, 0x7c, 0xc1, 0xf7, 0x78, 0x5b, 0x59, 0x47, + 0x99, 0xba, 0x29, 0x63, 0xdd, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x24, 0x4e, 0xca, 0x64, 0xda, + 0x07, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -193,8 +532,9 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Images service - +// ImagesClient is the client API for Images service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type ImagesClient interface { // Get returns an image by name. Get(ctx context.Context, in *GetImageRequest, opts ...grpc.CallOption) (*GetImageResponse, error) @@ -208,7 +548,7 @@ // image. Update(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) // Delete deletes the image by name. - Delete(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) + Delete(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*types1.Empty, error) } type imagesClient struct { @@ -221,7 +561,7 @@ func (c *imagesClient) Get(ctx context.Context, in *GetImageRequest, opts ...grpc.CallOption) (*GetImageResponse, error) { out := new(GetImageResponse) - err := grpc.Invoke(ctx, "/containerd.services.images.v1.Images/Get", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/Get", in, out, opts...) if err != nil { return nil, err } @@ -230,7 +570,7 @@ func (c *imagesClient) List(ctx context.Context, in *ListImagesRequest, opts ...grpc.CallOption) (*ListImagesResponse, error) { out := new(ListImagesResponse) - err := grpc.Invoke(ctx, "/containerd.services.images.v1.Images/List", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/List", in, out, opts...) if err != nil { return nil, err } @@ -239,7 +579,7 @@ func (c *imagesClient) Create(ctx context.Context, in *CreateImageRequest, opts ...grpc.CallOption) (*CreateImageResponse, error) { out := new(CreateImageResponse) - err := grpc.Invoke(ctx, "/containerd.services.images.v1.Images/Create", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/Create", in, out, opts...) if err != nil { return nil, err } @@ -248,24 +588,23 @@ func (c *imagesClient) Update(ctx context.Context, in *UpdateImageRequest, opts ...grpc.CallOption) (*UpdateImageResponse, error) { out := new(UpdateImageResponse) - err := grpc.Invoke(ctx, "/containerd.services.images.v1.Images/Update", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/Update", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *imagesClient) Delete(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) { - out := new(google_protobuf1.Empty) - err := grpc.Invoke(ctx, "/containerd.services.images.v1.Images/Delete", in, out, c.cc, opts...) +func (c *imagesClient) Delete(ctx context.Context, in *DeleteImageRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/Delete", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Images service - +// ImagesServer is the server API for Images service. type ImagesServer interface { // Get returns an image by name. Get(context.Context, *GetImageRequest) (*GetImageResponse, error) @@ -279,7 +618,27 @@ // image. Update(context.Context, *UpdateImageRequest) (*UpdateImageResponse, error) // Delete deletes the image by name. - Delete(context.Context, *DeleteImageRequest) (*google_protobuf1.Empty, error) + Delete(context.Context, *DeleteImageRequest) (*types1.Empty, error) +} + +// UnimplementedImagesServer can be embedded to have forward compatible implementations. +type UnimplementedImagesServer struct { +} + +func (*UnimplementedImagesServer) Get(ctx context.Context, req *GetImageRequest) (*GetImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") +} +func (*UnimplementedImagesServer) List(ctx context.Context, req *ListImagesRequest) (*ListImagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedImagesServer) Create(ctx context.Context, req *CreateImageRequest) (*CreateImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (*UnimplementedImagesServer) Update(ctx context.Context, req *UpdateImageRequest) (*UpdateImageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedImagesServer) Delete(ctx context.Context, req *DeleteImageRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func RegisterImagesServer(s *grpc.Server, srv ImagesServer) { @@ -408,7 +767,7 @@ func (m *Image) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -416,64 +775,78 @@ } func (m *Image) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Image) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintImages(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x42 + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintImages(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x3a + { + size, err := m.Target.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x1a if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovImages(uint64(len(k))) + 1 + len(v) + sovImages(uint64(len(v))) - i = encodeVarintImages(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintImages(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintImages(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintImages(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintImages(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - dAtA[i] = 0x1a - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Target.Size())) - n1, err := m.Target.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - dAtA[i] = 0x3a - i++ - i = encodeVarintImages(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt))) - n2, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 - dAtA[i] = 0x42 - i++ - i = encodeVarintImages(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n3, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintImages(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa } - i += n3 - return i, nil + return len(dAtA) - i, nil } func (m *GetImageRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -481,23 +854,33 @@ } func (m *GetImageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetImageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintImages(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetImageResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -505,27 +888,38 @@ } func (m *GetImageResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetImageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Image != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Image.Size())) - n4, err := m.Image.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } - i += n4 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CreateImageRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -533,25 +927,36 @@ } func (m *CreateImageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateImageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Image.Size())) - n5, err := m.Image.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } - i += n5 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CreateImageResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -559,25 +964,36 @@ } func (m *CreateImageResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateImageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Image.Size())) - n6, err := m.Image.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n6 - return i, nil + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateImageRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -585,35 +1001,48 @@ } func (m *UpdateImageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateImageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Image.Size())) - n7, err := m.Image.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n7 if m.UpdateMask != nil { + { + size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintImages(dAtA, i, uint64(m.UpdateMask.Size())) - n8, err := m.UpdateMask.MarshalTo(dAtA[i:]) + } + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n8 + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateImageResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -621,25 +1050,36 @@ } func (m *UpdateImageResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateImageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(m.Image.Size())) - n9, err := m.Image.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Image.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } - i += n9 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ListImagesRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -647,32 +1087,35 @@ } func (m *ListImagesRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListImagesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintImages(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *ListImagesResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -680,29 +1123,40 @@ } func (m *ListImagesResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListImagesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Images) > 0 { - for _, msg := range m.Images { - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Images) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Images[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintImages(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteImageRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -710,39 +1164,54 @@ } func (m *DeleteImageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteImageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintImages(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Sync { - dAtA[i] = 0x10 - i++ + i-- if m.Sync { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintImages(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintImages(dAtA []byte, offset int, v uint64) int { + offset -= sovImages(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Image) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -759,50 +1228,80 @@ } l = m.Target.Size() n += 1 + l + sovImages(uint64(l)) - l = types.SizeOfStdTime(m.CreatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovImages(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovImages(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetImageRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovImages(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetImageResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Image != nil { l = m.Image.Size() n += 1 + l + sovImages(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateImageRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Image.Size() n += 1 + l + sovImages(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateImageResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Image.Size() n += 1 + l + sovImages(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateImageRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Image.Size() @@ -811,18 +1310,30 @@ l = m.UpdateMask.Size() n += 1 + l + sovImages(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateImageResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Image.Size() n += 1 + l + sovImages(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListImagesRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -831,10 +1342,16 @@ n += 1 + l + sovImages(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListImagesResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Images) > 0 { @@ -843,10 +1360,16 @@ n += 1 + l + sovImages(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteImageRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -856,18 +1379,14 @@ if m.Sync { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovImages(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozImages(x uint64) (n int) { return sovImages(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -880,7 +1399,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -889,9 +1408,10 @@ s := strings.Join([]string{`&Image{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, - `Target:` + strings.Replace(strings.Replace(this.Target.String(), "Descriptor", "containerd_types.Descriptor", 1), `&`, ``, 1) + `,`, - `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `Target:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Target), "Descriptor", "types.Descriptor", 1), `&`, ``, 1) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -902,6 +1422,7 @@ } s := strings.Join([]string{`&GetImageRequest{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -911,7 +1432,8 @@ return "nil" } s := strings.Join([]string{`&GetImageResponse{`, - `Image:` + strings.Replace(fmt.Sprintf("%v", this.Image), "Image", "Image", 1) + `,`, + `Image:` + strings.Replace(this.Image.String(), "Image", "Image", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -922,6 +1444,7 @@ } s := strings.Join([]string{`&CreateImageRequest{`, `Image:` + strings.Replace(strings.Replace(this.Image.String(), "Image", "Image", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -932,6 +1455,7 @@ } s := strings.Join([]string{`&CreateImageResponse{`, `Image:` + strings.Replace(strings.Replace(this.Image.String(), "Image", "Image", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -942,7 +1466,8 @@ } s := strings.Join([]string{`&UpdateImageRequest{`, `Image:` + strings.Replace(strings.Replace(this.Image.String(), "Image", "Image", 1), `&`, ``, 1) + `,`, - `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf2.FieldMask", 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types1.FieldMask", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -953,6 +1478,7 @@ } s := strings.Join([]string{`&UpdateImageResponse{`, `Image:` + strings.Replace(strings.Replace(this.Image.String(), "Image", "Image", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -963,6 +1489,7 @@ } s := strings.Join([]string{`&ListImagesRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -971,8 +1498,14 @@ if this == nil { return "nil" } + repeatedStringForImages := "[]Image{" + for _, f := range this.Images { + repeatedStringForImages += strings.Replace(strings.Replace(f.String(), "Image", "Image", 1), `&`, ``, 1) + "," + } + repeatedStringForImages += "}" s := strings.Join([]string{`&ListImagesResponse{`, - `Images:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Images), "Image", "Image", 1), `&`, ``, 1) + `,`, + `Images:` + repeatedStringForImages + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -984,6 +1517,7 @@ s := strings.Join([]string{`&DeleteImageRequest{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Sync:` + fmt.Sprintf("%v", this.Sync) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1011,7 +1545,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1039,7 +1573,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1049,6 +1583,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1068,7 +1605,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1077,6 +1614,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1097,7 +1637,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1114,7 +1654,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1124,6 +1664,9 @@ return ErrInvalidLengthImages } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthImages + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1140,7 +1683,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1150,6 +1693,9 @@ return ErrInvalidLengthImages } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthImages + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1161,7 +1707,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > postIndex { @@ -1186,7 +1732,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1195,6 +1741,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1216,7 +1765,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1225,10 +1774,13 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1246,7 +1798,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1255,10 +1807,13 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1268,12 +1823,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1298,7 +1854,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1326,7 +1882,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1336,6 +1892,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1347,12 +1906,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1377,7 +1937,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1405,7 +1965,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1414,6 +1974,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1430,12 +1993,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1460,7 +2024,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1488,7 +2052,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1497,6 +2061,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1510,12 +2077,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1540,7 +2108,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1568,7 +2136,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1577,6 +2145,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1590,12 +2161,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1620,7 +2192,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1648,7 +2220,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1657,6 +2229,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1678,7 +2253,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1687,11 +2262,14 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } if m.UpdateMask == nil { - m.UpdateMask = &google_protobuf2.FieldMask{} + m.UpdateMask = &types1.FieldMask{} } if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1703,12 +2281,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1733,7 +2312,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1761,7 +2340,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1770,6 +2349,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1783,12 +2365,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1813,7 +2396,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1841,7 +2424,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1851,6 +2434,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1862,12 +2448,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1892,7 +2479,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1920,7 +2507,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1929,6 +2516,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1943,12 +2533,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1973,7 +2564,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2001,7 +2592,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2011,6 +2602,9 @@ return ErrInvalidLengthImages } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthImages + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2030,7 +2624,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2042,12 +2636,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthImages } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2060,6 +2655,7 @@ func skipImages(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -2091,10 +2687,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -2111,103 +2705,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthImages } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowImages - } - 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 := skipImages(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupImages + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthImages + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthImages = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowImages = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthImages = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowImages = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupImages = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/images/v1/images.proto", fileDescriptorImages) -} - -var fileDescriptorImages = []byte{ - // 659 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0x8e, 0x93, 0xd4, 0x6d, 0x27, 0x07, 0xca, 0x52, 0x21, 0xcb, 0x40, 0x1a, 0x45, 0x20, 0xe5, - 0xc2, 0x9a, 0x86, 0x0b, 0xb4, 0x08, 0xd1, 0xb4, 0xa5, 0x20, 0x15, 0x0e, 0xe6, 0xaf, 0xe2, 0x52, - 0x6d, 0x92, 0x89, 0xb1, 0x62, 0xc7, 0xc6, 0xbb, 0x89, 0x94, 0x1b, 0x8f, 0x80, 0x04, 0x0f, 0xd5, - 0x23, 0x47, 0x4e, 0x40, 0x73, 0xe0, 0x39, 0x90, 0x77, 0x37, 0x34, 0x4d, 0x22, 0x92, 0x94, 0xde, - 0x66, 0xed, 0xef, 0x9b, 0x9f, 0x6f, 0x66, 0x76, 0x61, 0xcf, 0xf3, 0xc5, 0x87, 0x6e, 0x9d, 0x36, - 0xa2, 0xd0, 0x69, 0x44, 0x1d, 0xc1, 0xfc, 0x0e, 0x26, 0xcd, 0x51, 0x93, 0xc5, 0xbe, 0xc3, 0x31, - 0xe9, 0xf9, 0x0d, 0xe4, 0x8e, 0x1f, 0x32, 0x0f, 0xb9, 0xd3, 0xdb, 0xd4, 0x16, 0x8d, 0x93, 0x48, - 0x44, 0xe4, 0xd6, 0x19, 0x9e, 0x0e, 0xb1, 0x54, 0x23, 0x7a, 0x9b, 0xf6, 0xba, 0x17, 0x79, 0x91, - 0x44, 0x3a, 0xa9, 0xa5, 0x48, 0xf6, 0x0d, 0x2f, 0x8a, 0xbc, 0x00, 0x1d, 0x79, 0xaa, 0x77, 0x5b, - 0x0e, 0x86, 0xb1, 0xe8, 0xeb, 0x9f, 0xa5, 0xf1, 0x9f, 0x2d, 0x1f, 0x83, 0xe6, 0x71, 0xc8, 0x78, - 0x5b, 0x23, 0x36, 0xc6, 0x11, 0xc2, 0x0f, 0x91, 0x0b, 0x16, 0xc6, 0x1a, 0xb0, 0x3d, 0x57, 0x69, - 0xa2, 0x1f, 0x23, 0x77, 0x9a, 0xc8, 0x1b, 0x89, 0x1f, 0x8b, 0x28, 0x51, 0xe4, 0xf2, 0xef, 0x2c, - 0x2c, 0x3d, 0x4f, 0x0b, 0x20, 0x04, 0xf2, 0x1d, 0x16, 0xa2, 0x65, 0x94, 0x8c, 0xca, 0xaa, 0x2b, - 0x6d, 0xf2, 0x0c, 0xcc, 0x80, 0xd5, 0x31, 0xe0, 0x56, 0xb6, 0x94, 0xab, 0x14, 0xaa, 0xf7, 0xe8, - 0x3f, 0x05, 0xa0, 0xd2, 0x13, 0x3d, 0x94, 0x94, 0xfd, 0x8e, 0x48, 0xfa, 0xae, 0xe6, 0x93, 0x2d, - 0x30, 0x05, 0x4b, 0x3c, 0x14, 0x56, 0xae, 0x64, 0x54, 0x0a, 0xd5, 0x9b, 0xa3, 0x9e, 0x64, 0x6e, - 0x74, 0xef, 0x6f, 0x6e, 0xb5, 0xfc, 0xc9, 0x8f, 0x8d, 0x8c, 0xab, 0x19, 0x64, 0x17, 0xa0, 0x91, - 0x20, 0x13, 0xd8, 0x3c, 0x66, 0xc2, 0x5a, 0x96, 0x7c, 0x9b, 0x2a, 0x59, 0xe8, 0x50, 0x16, 0xfa, - 0x7a, 0x28, 0x4b, 0x6d, 0x25, 0x65, 0x7f, 0xfe, 0xb9, 0x61, 0xb8, 0xab, 0x9a, 0xb7, 0x23, 0x9d, - 0x74, 0xe3, 0xe6, 0xd0, 0xc9, 0xca, 0x22, 0x4e, 0x34, 0x6f, 0x47, 0xd8, 0x0f, 0xa1, 0x30, 0x52, - 0x1c, 0x59, 0x83, 0x5c, 0x1b, 0xfb, 0x5a, 0xb1, 0xd4, 0x24, 0xeb, 0xb0, 0xd4, 0x63, 0x41, 0x17, - 0xad, 0xac, 0xfc, 0xa6, 0x0e, 0x5b, 0xd9, 0x07, 0x46, 0xf9, 0x0e, 0x5c, 0x39, 0x40, 0x21, 0x05, - 0x72, 0xf1, 0x63, 0x17, 0xb9, 0x98, 0xa6, 0x78, 0xf9, 0x25, 0xac, 0x9d, 0xc1, 0x78, 0x1c, 0x75, - 0x38, 0x92, 0x2d, 0x58, 0x92, 0x12, 0x4b, 0x60, 0xa1, 0x7a, 0x7b, 0x9e, 0x26, 0xb8, 0x8a, 0x52, - 0x7e, 0x0b, 0x64, 0x57, 0x6a, 0x70, 0x2e, 0xf2, 0x93, 0x0b, 0x78, 0xd4, 0x4d, 0xd1, 0x7e, 0xdf, - 0xc1, 0xb5, 0x73, 0x7e, 0x75, 0xaa, 0xff, 0xef, 0xf8, 0x8b, 0x01, 0xe4, 0x8d, 0x14, 0xfc, 0x72, - 0x33, 0x26, 0xdb, 0x50, 0x50, 0x8d, 0x94, 0xcb, 0x25, 0x1b, 0x34, 0x6d, 0x02, 0x9e, 0xa6, 0xfb, - 0xf7, 0x82, 0xf1, 0xb6, 0xab, 0xe7, 0x25, 0xb5, 0xd3, 0x72, 0xcf, 0x25, 0x75, 0x69, 0xe5, 0xde, - 0x85, 0xab, 0x87, 0x3e, 0x57, 0x0d, 0xe7, 0xc3, 0x62, 0x2d, 0x58, 0x6e, 0xf9, 0x81, 0xc0, 0x84, - 0x5b, 0x46, 0x29, 0x57, 0x59, 0x75, 0x87, 0xc7, 0xf2, 0x11, 0x90, 0x51, 0xb8, 0x4e, 0xa3, 0x06, - 0xa6, 0x0a, 0x22, 0xe1, 0x8b, 0xe5, 0xa1, 0x99, 0xe5, 0x47, 0x40, 0xf6, 0x30, 0xc0, 0x31, 0xd9, - 0xa7, 0x5d, 0x0a, 0x04, 0xf2, 0xbc, 0xdf, 0x69, 0x48, 0x05, 0x57, 0x5c, 0x69, 0x57, 0xbf, 0xe6, - 0xc1, 0x54, 0x49, 0x91, 0x16, 0xe4, 0x0e, 0x50, 0x10, 0x3a, 0x23, 0x87, 0xb1, 0x65, 0xb0, 0x9d, - 0xb9, 0xf1, 0xba, 0xe8, 0x36, 0xe4, 0x53, 0x29, 0xc8, 0xac, 0x3b, 0x69, 0x42, 0x5e, 0x7b, 0x73, - 0x01, 0x86, 0x0e, 0x16, 0x81, 0xa9, 0xc6, 0x9d, 0xcc, 0x22, 0x4f, 0x6e, 0x9b, 0x5d, 0x5d, 0x84, - 0x72, 0x16, 0x50, 0x0d, 0xdc, 0xcc, 0x80, 0x93, 0xcb, 0x32, 0x33, 0xe0, 0xb4, 0x51, 0x7e, 0x05, - 0xa6, 0xea, 0xff, 0xcc, 0x80, 0x93, 0x63, 0x62, 0x5f, 0x9f, 0x58, 0xa3, 0xfd, 0xf4, 0x8d, 0xab, - 0x1d, 0x9d, 0x9c, 0x16, 0x33, 0xdf, 0x4f, 0x8b, 0x99, 0x4f, 0x83, 0xa2, 0x71, 0x32, 0x28, 0x1a, - 0xdf, 0x06, 0x45, 0xe3, 0xd7, 0xa0, 0x68, 0xbc, 0x7f, 0x7c, 0xc1, 0xf7, 0x78, 0x5b, 0x59, 0x47, - 0x99, 0xba, 0x29, 0x63, 0xdd, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x24, 0x4e, 0xca, 0x64, 0xda, - 0x07, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/images/v1/images.proto containerd-1.5.9/api/services/images/v1/images.proto --- containerd-1.2.6/api/services/images/v1/images.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/images/v1/images.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.images.v1; diff -Nru containerd-1.2.6/api/services/introspection/v1/introspection.pb.go containerd-1.5.9/api/services/introspection/v1/introspection.pb.go --- containerd-1.2.6/api/services/introspection/v1/introspection.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/introspection/v1/introspection.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,35 +1,25 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/introspection/v1/introspection.proto -/* - Package introspection is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/introspection/v1/introspection.proto - - It has these top-level messages: - Plugin - PluginsRequest - PluginsResponse -*/ package introspection -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import containerd_types "github.com/containerd/containerd/api/types" -import google_rpc "github.com/gogo/googleapis/google/rpc" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + rpc "github.com/gogo/googleapis/google/rpc" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + types1 "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -40,7 +30,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Plugin struct { // Type defines the type of plugin. @@ -51,7 +41,7 @@ // ID identifies the plugin uniquely in the system. ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` // Requires lists the plugin types required by this plugin. - Requires []string `protobuf:"bytes,3,rep,name=requires" json:"requires,omitempty"` + Requires []string `protobuf:"bytes,3,rep,name=requires,proto3" json:"requires,omitempty"` // Platforms enumerates the platforms this plugin will support. // // If values are provided here, the plugin will only be operable under the @@ -61,30 +51,61 @@ // // If the plugin prefers certain platforms over others, they should be // listed from most to least preferred. - Platforms []containerd_types.Platform `protobuf:"bytes,4,rep,name=platforms" json:"platforms"` + Platforms []types.Platform `protobuf:"bytes,4,rep,name=platforms,proto3" json:"platforms"` // Exports allows plugins to provide values about state or configuration to // interested parties. // // One example is exposing the configured path of a snapshotter plugin. - Exports map[string]string `protobuf:"bytes,5,rep,name=exports" json:"exports,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Exports map[string]string `protobuf:"bytes,5,rep,name=exports,proto3" json:"exports,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Capabilities allows plugins to communicate feature switches to allow // clients to detect features that may not be on be default or may be // different from version to version. // // Use this sparingly. - Capabilities []string `protobuf:"bytes,6,rep,name=capabilities" json:"capabilities,omitempty"` + Capabilities []string `protobuf:"bytes,6,rep,name=capabilities,proto3" json:"capabilities,omitempty"` // InitErr will be set if the plugin fails initialization. // // This means the plugin may have been registered but a non-terminal error // was encountered during initialization. // // Plugins that have this value set cannot be used. - InitErr *google_rpc.Status `protobuf:"bytes,7,opt,name=init_err,json=initErr" json:"init_err,omitempty"` + InitErr *rpc.Status `protobuf:"bytes,7,opt,name=init_err,json=initErr,proto3" json:"init_err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Plugin) Reset() { *m = Plugin{} } +func (*Plugin) ProtoMessage() {} +func (*Plugin) Descriptor() ([]byte, []int) { + return fileDescriptor_1a14fda866f10715, []int{0} +} +func (m *Plugin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Plugin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Plugin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Plugin) XXX_Merge(src proto.Message) { + xxx_messageInfo_Plugin.Merge(m, src) +} +func (m *Plugin) XXX_Size() int { + return m.Size() +} +func (m *Plugin) XXX_DiscardUnknown() { + xxx_messageInfo_Plugin.DiscardUnknown(m) } -func (m *Plugin) Reset() { *m = Plugin{} } -func (*Plugin) ProtoMessage() {} -func (*Plugin) Descriptor() ([]byte, []int) { return fileDescriptorIntrospection, []int{0} } +var xxx_messageInfo_Plugin proto.InternalMessageInfo type PluginsRequest struct { // Filters contains one or more filters using the syntax defined in the @@ -97,25 +118,171 @@ // filters[0] or filters[1] or ... or filters[n-1] or filters[n] // // If filters is zero-length or nil, all items will be returned. - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PluginsRequest) Reset() { *m = PluginsRequest{} } +func (*PluginsRequest) ProtoMessage() {} +func (*PluginsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_1a14fda866f10715, []int{1} +} +func (m *PluginsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PluginsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PluginsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginsRequest.Merge(m, src) +} +func (m *PluginsRequest) XXX_Size() int { + return m.Size() +} +func (m *PluginsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PluginsRequest.DiscardUnknown(m) } -func (m *PluginsRequest) Reset() { *m = PluginsRequest{} } -func (*PluginsRequest) ProtoMessage() {} -func (*PluginsRequest) Descriptor() ([]byte, []int) { return fileDescriptorIntrospection, []int{1} } +var xxx_messageInfo_PluginsRequest proto.InternalMessageInfo type PluginsResponse struct { - Plugins []Plugin `protobuf:"bytes,1,rep,name=plugins" json:"plugins"` + Plugins []Plugin `protobuf:"bytes,1,rep,name=plugins,proto3" json:"plugins"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PluginsResponse) Reset() { *m = PluginsResponse{} } +func (*PluginsResponse) ProtoMessage() {} +func (*PluginsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1a14fda866f10715, []int{2} +} +func (m *PluginsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PluginsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PluginsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginsResponse.Merge(m, src) +} +func (m *PluginsResponse) XXX_Size() int { + return m.Size() +} +func (m *PluginsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PluginsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginsResponse proto.InternalMessageInfo + +type ServerResponse struct { + UUID string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ServerResponse) Reset() { *m = ServerResponse{} } +func (*ServerResponse) ProtoMessage() {} +func (*ServerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_1a14fda866f10715, []int{3} +} +func (m *ServerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ServerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ServerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ServerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServerResponse.Merge(m, src) +} +func (m *ServerResponse) XXX_Size() int { + return m.Size() +} +func (m *ServerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ServerResponse.DiscardUnknown(m) } -func (m *PluginsResponse) Reset() { *m = PluginsResponse{} } -func (*PluginsResponse) ProtoMessage() {} -func (*PluginsResponse) Descriptor() ([]byte, []int) { return fileDescriptorIntrospection, []int{2} } +var xxx_messageInfo_ServerResponse proto.InternalMessageInfo func init() { proto.RegisterType((*Plugin)(nil), "containerd.services.introspection.v1.Plugin") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.introspection.v1.Plugin.ExportsEntry") proto.RegisterType((*PluginsRequest)(nil), "containerd.services.introspection.v1.PluginsRequest") proto.RegisterType((*PluginsResponse)(nil), "containerd.services.introspection.v1.PluginsResponse") + proto.RegisterType((*ServerResponse)(nil), "containerd.services.introspection.v1.ServerResponse") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/introspection/v1/introspection.proto", fileDescriptor_1a14fda866f10715) +} + +var fileDescriptor_1a14fda866f10715 = []byte{ + // 549 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0xad, 0x9d, 0x34, 0x6e, 0x37, 0xa5, 0xa0, 0x55, 0x55, 0x2c, 0x83, 0x9c, 0x28, 0xe2, 0x10, + 0x21, 0x58, 0xab, 0x01, 0x24, 0x5a, 0x24, 0x0e, 0x51, 0x73, 0x88, 0xd4, 0x43, 0xe5, 0xa8, 0x08, + 0x71, 0xa9, 0x1c, 0x67, 0x63, 0x56, 0x38, 0xde, 0xed, 0xee, 0xda, 0x22, 0x37, 0x3e, 0x2f, 0x47, + 0x8e, 0x9c, 0x02, 0xf5, 0x37, 0xf0, 0x01, 0xc8, 0xbb, 0x76, 0x9a, 0xdc, 0x12, 0x71, 0x9b, 0x79, + 0x33, 0x6f, 0xe6, 0xcd, 0xf3, 0xca, 0xc0, 0x8f, 0x88, 0xfc, 0x9a, 0x8e, 0x51, 0x48, 0x67, 0x5e, + 0x48, 0x13, 0x19, 0x90, 0x04, 0xf3, 0xc9, 0x7a, 0x18, 0x30, 0xe2, 0x09, 0xcc, 0x33, 0x12, 0x62, + 0xe1, 0x91, 0x44, 0x72, 0x2a, 0x18, 0x0e, 0x25, 0xa1, 0x89, 0x97, 0x9d, 0x6d, 0x02, 0x88, 0x71, + 0x2a, 0x29, 0x7c, 0xf1, 0xc0, 0x46, 0x15, 0x13, 0x6d, 0x36, 0x66, 0x67, 0xce, 0xf9, 0x56, 0x9b, + 0xe5, 0x9c, 0x61, 0xe1, 0xb1, 0x38, 0x90, 0x53, 0xca, 0x67, 0x7a, 0x81, 0xf3, 0x34, 0xa2, 0x34, + 0x8a, 0xb1, 0xc7, 0x59, 0xe8, 0x09, 0x19, 0xc8, 0x54, 0x94, 0x85, 0x67, 0x65, 0x41, 0x65, 0xe3, + 0x74, 0xea, 0xe1, 0x19, 0x93, 0xf3, 0xb2, 0x78, 0x12, 0xd1, 0x88, 0xaa, 0xd0, 0x2b, 0x22, 0x8d, + 0x76, 0xfe, 0x9a, 0xa0, 0x71, 0x1d, 0xa7, 0x11, 0x49, 0x20, 0x04, 0xf5, 0x62, 0x9d, 0x6d, 0xb4, + 0x8d, 0xee, 0xa1, 0xaf, 0x62, 0x78, 0x0a, 0x4c, 0x32, 0xb1, 0xcd, 0x02, 0xe9, 0x37, 0xf2, 0x65, + 0xcb, 0x1c, 0x5e, 0xfa, 0x26, 0x99, 0x40, 0x07, 0x1c, 0x70, 0x7c, 0x97, 0x12, 0x8e, 0x85, 0x5d, + 0x6b, 0xd7, 0xba, 0x87, 0xfe, 0x2a, 0x87, 0x1f, 0xc1, 0x61, 0x25, 0x58, 0xd8, 0xf5, 0x76, 0xad, + 0xdb, 0xec, 0x39, 0x68, 0xcd, 0x13, 0x75, 0x13, 0xba, 0x2e, 0x5b, 0xfa, 0xf5, 0xc5, 0xb2, 0xb5, + 0xe7, 0x3f, 0x50, 0xe0, 0x08, 0x58, 0xf8, 0x3b, 0xa3, 0x5c, 0x0a, 0x7b, 0x5f, 0xb1, 0xcf, 0xd1, + 0x36, 0x8e, 0x22, 0x7d, 0x06, 0x1a, 0x68, 0xee, 0x20, 0x91, 0x7c, 0xee, 0x57, 0x93, 0x60, 0x07, + 0x1c, 0x85, 0x01, 0x0b, 0xc6, 0x24, 0x26, 0x92, 0x60, 0x61, 0x37, 0x94, 0xe8, 0x0d, 0x0c, 0xbe, + 0x06, 0x07, 0x24, 0x21, 0xf2, 0x16, 0x73, 0x6e, 0x5b, 0x6d, 0xa3, 0xdb, 0xec, 0x41, 0xa4, 0x1d, + 0x45, 0x9c, 0x85, 0x68, 0xa4, 0xac, 0xf6, 0xad, 0xa2, 0x67, 0xc0, 0xb9, 0x73, 0x01, 0x8e, 0xd6, + 0x77, 0xc1, 0x27, 0xa0, 0xf6, 0x0d, 0xcf, 0x4b, 0xfb, 0x8a, 0x10, 0x9e, 0x80, 0xfd, 0x2c, 0x88, + 0x53, 0xac, 0x0d, 0xf4, 0x75, 0x72, 0x61, 0xbe, 0x37, 0x3a, 0x2f, 0xc1, 0xb1, 0x96, 0x2b, 0x7c, + 0x7c, 0x97, 0x62, 0x21, 0xa1, 0x0d, 0xac, 0x29, 0x89, 0x25, 0xe6, 0xc2, 0x36, 0x94, 0xb6, 0x2a, + 0xed, 0xdc, 0x82, 0xc7, 0xab, 0x5e, 0xc1, 0x68, 0x22, 0x30, 0xbc, 0x02, 0x16, 0xd3, 0x90, 0x6a, + 0x6e, 0xf6, 0x5e, 0xed, 0x62, 0x51, 0x69, 0x79, 0x35, 0xa2, 0x83, 0xc0, 0xf1, 0x08, 0xf3, 0x0c, + 0xf3, 0xd5, 0xfc, 0xe7, 0xa0, 0x9e, 0xa6, 0x64, 0xa2, 0x6f, 0xe9, 0x1f, 0xe4, 0xcb, 0x56, 0xfd, + 0xe6, 0x66, 0x78, 0xe9, 0x2b, 0xb4, 0xf7, 0xdb, 0x00, 0x8f, 0x86, 0xeb, 0xa3, 0x61, 0x06, 0xac, + 0x52, 0x22, 0x7c, 0xbb, 0x8b, 0x92, 0xea, 0x7a, 0xe7, 0xdd, 0x8e, 0xac, 0x52, 0xe7, 0x27, 0xd0, + 0xd0, 0xca, 0xe1, 0x69, 0xf5, 0xa5, 0xaa, 0xb7, 0x8f, 0x06, 0xc5, 0xdb, 0x77, 0xb6, 0x94, 0xb3, + 0x79, 0x7f, 0x7f, 0xba, 0xb8, 0x77, 0xf7, 0x7e, 0xdd, 0xbb, 0x7b, 0x3f, 0x72, 0xd7, 0x58, 0xe4, + 0xae, 0xf1, 0x33, 0x77, 0x8d, 0x3f, 0xb9, 0x6b, 0x7c, 0xb9, 0xfa, 0xbf, 0x1f, 0xc6, 0x87, 0x0d, + 0xe0, 0x73, 0x6d, 0xdc, 0x50, 0x7a, 0xdf, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xb3, 0x50, + 0xdc, 0x89, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -126,14 +293,17 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Introspection service - +// IntrospectionClient is the client API for Introspection service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type IntrospectionClient interface { // Plugins returns a list of plugins in containerd. // // Clients can use this to detect features and capabilities when using // containerd. Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error) + // Server returns information about the containerd server + Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error) } type introspectionClient struct { @@ -146,21 +316,42 @@ func (c *introspectionClient) Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error) { out := new(PluginsResponse) - err := grpc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/Plugins", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/Plugins", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Introspection service +func (c *introspectionClient) Server(ctx context.Context, in *types1.Empty, opts ...grpc.CallOption) (*ServerResponse, error) { + out := new(ServerResponse) + err := c.cc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/Server", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} +// IntrospectionServer is the server API for Introspection service. type IntrospectionServer interface { // Plugins returns a list of plugins in containerd. // // Clients can use this to detect features and capabilities when using // containerd. Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error) + // Server returns information about the containerd server + Server(context.Context, *types1.Empty) (*ServerResponse, error) +} + +// UnimplementedIntrospectionServer can be embedded to have forward compatible implementations. +type UnimplementedIntrospectionServer struct { +} + +func (*UnimplementedIntrospectionServer) Plugins(ctx context.Context, req *PluginsRequest) (*PluginsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Plugins not implemented") +} +func (*UnimplementedIntrospectionServer) Server(ctx context.Context, req *types1.Empty) (*ServerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Server not implemented") } func RegisterIntrospectionServer(s *grpc.Server, srv IntrospectionServer) { @@ -185,6 +376,24 @@ return interceptor(ctx, in, info, handler) } +func _Introspection_Server_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(types1.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntrospectionServer).Server(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.introspection.v1.Introspection/Server", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntrospectionServer).Server(ctx, req.(*types1.Empty)) + } + return interceptor(ctx, in, info, handler) +} + var _Introspection_serviceDesc = grpc.ServiceDesc{ ServiceName: "containerd.services.introspection.v1.Introspection", HandlerType: (*IntrospectionServer)(nil), @@ -193,6 +402,10 @@ MethodName: "Plugins", Handler: _Introspection_Plugins_Handler, }, + { + MethodName: "Server", + Handler: _Introspection_Server_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto", @@ -201,7 +414,7 @@ func (m *Plugin) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -209,98 +422,103 @@ } func (m *Plugin) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Plugin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Type) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(len(m.Type))) - i += copy(dAtA[i:], m.Type) - } - if len(m.ID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if len(m.Requires) > 0 { - for _, s := range m.Requires { - dAtA[i] = 0x1a - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Platforms) > 0 { - for _, msg := range m.Platforms { - dAtA[i] = 0x22 - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + if m.InitErr != nil { + { + size, err := m.InitErr.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintIntrospection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.Capabilities) > 0 { + for iNdEx := len(m.Capabilities) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Capabilities[iNdEx]) + copy(dAtA[i:], m.Capabilities[iNdEx]) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.Capabilities[iNdEx]))) + i-- + dAtA[i] = 0x32 } } if len(m.Exports) > 0 { - for k, _ := range m.Exports { - dAtA[i] = 0x2a - i++ + for k := range m.Exports { v := m.Exports[k] - mapSize := 1 + len(k) + sovIntrospection(uint64(len(k))) + 1 + len(v) + sovIntrospection(uint64(len(v))) - i = encodeVarintIntrospection(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintIntrospection(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintIntrospection(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintIntrospection(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a } } - if len(m.Capabilities) > 0 { - for _, s := range m.Capabilities { - dAtA[i] = 0x32 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) + if len(m.Platforms) > 0 { + for iNdEx := len(m.Platforms) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Platforms[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIntrospection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } } - if m.InitErr != nil { - dAtA[i] = 0x3a - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(m.InitErr.Size())) - n1, err := m.InitErr.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if len(m.Requires) > 0 { + for iNdEx := len(m.Requires) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Requires[iNdEx]) + copy(dAtA[i:], m.Requires[iNdEx]) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.Requires[iNdEx]))) + i-- + dAtA[i] = 0x1a } - i += n1 } - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0x12 + } + if len(m.Type) > 0 { + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *PluginsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -308,32 +526,35 @@ } func (m *PluginsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *PluginsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -341,35 +562,85 @@ } func (m *PluginsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Plugins) > 0 { - for _, msg := range m.Plugins { - dAtA[i] = 0xa - i++ - i = encodeVarintIntrospection(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Plugins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Plugins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintIntrospection(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil +} + +func (m *ServerResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ServerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ServerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.UUID) > 0 { + i -= len(m.UUID) + copy(dAtA[i:], m.UUID) + i = encodeVarintIntrospection(dAtA, i, uint64(len(m.UUID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func encodeVarintIntrospection(dAtA []byte, offset int, v uint64) int { + offset -= sovIntrospection(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Plugin) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Type) @@ -410,10 +681,16 @@ l = m.InitErr.Size() n += 1 + l + sovIntrospection(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PluginsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -422,10 +699,16 @@ n += 1 + l + sovIntrospection(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PluginsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Plugins) > 0 { @@ -434,19 +717,31 @@ n += 1 + l + sovIntrospection(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } -func sovIntrospection(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } +func (m *ServerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UUID) + if l > 0 { + n += 1 + l + sovIntrospection(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) } return n } + +func sovIntrospection(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} func sozIntrospection(x uint64) (n int) { return sovIntrospection(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } @@ -454,11 +749,16 @@ if this == nil { return "nil" } + repeatedStringForPlatforms := "[]Platform{" + for _, f := range this.Platforms { + repeatedStringForPlatforms += fmt.Sprintf("%v", f) + "," + } + repeatedStringForPlatforms += "}" keysForExports := make([]string, 0, len(this.Exports)) for k, _ := range this.Exports { keysForExports = append(keysForExports, k) } - sortkeys.Strings(keysForExports) + github_com_gogo_protobuf_sortkeys.Strings(keysForExports) mapStringForExports := "map[string]string{" for _, k := range keysForExports { mapStringForExports += fmt.Sprintf("%v: %v,", k, this.Exports[k]) @@ -468,10 +768,11 @@ `Type:` + fmt.Sprintf("%v", this.Type) + `,`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Requires:` + fmt.Sprintf("%v", this.Requires) + `,`, - `Platforms:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Platforms), "Platform", "containerd_types.Platform", 1), `&`, ``, 1) + `,`, + `Platforms:` + repeatedStringForPlatforms + `,`, `Exports:` + mapStringForExports + `,`, `Capabilities:` + fmt.Sprintf("%v", this.Capabilities) + `,`, - `InitErr:` + strings.Replace(fmt.Sprintf("%v", this.InitErr), "Status", "google_rpc.Status", 1) + `,`, + `InitErr:` + strings.Replace(fmt.Sprintf("%v", this.InitErr), "Status", "rpc.Status", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -482,6 +783,7 @@ } s := strings.Join([]string{`&PluginsRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -490,8 +792,25 @@ if this == nil { return "nil" } + repeatedStringForPlugins := "[]Plugin{" + for _, f := range this.Plugins { + repeatedStringForPlugins += strings.Replace(strings.Replace(f.String(), "Plugin", "Plugin", 1), `&`, ``, 1) + "," + } + repeatedStringForPlugins += "}" s := strings.Join([]string{`&PluginsResponse{`, - `Plugins:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Plugins), "Plugin", "Plugin", 1), `&`, ``, 1) + `,`, + `Plugins:` + repeatedStringForPlugins + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *ServerResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ServerResponse{`, + `UUID:` + fmt.Sprintf("%v", this.UUID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -519,7 +838,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -547,7 +866,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -557,6 +876,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -576,7 +898,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -586,6 +908,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -605,7 +930,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -615,6 +940,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -634,7 +962,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -643,10 +971,13 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Platforms = append(m.Platforms, containerd_types.Platform{}) + m.Platforms = append(m.Platforms, types.Platform{}) if err := m.Platforms[len(m.Platforms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -665,7 +996,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -674,6 +1005,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -694,7 +1028,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -711,7 +1045,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -721,6 +1055,9 @@ return ErrInvalidLengthIntrospection } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthIntrospection + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -737,7 +1074,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -747,6 +1084,9 @@ return ErrInvalidLengthIntrospection } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthIntrospection + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -758,7 +1098,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthIntrospection } if (iNdEx + skippy) > postIndex { @@ -783,7 +1123,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -793,6 +1133,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -812,7 +1155,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -821,11 +1164,14 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } if m.InitErr == nil { - m.InitErr = &google_rpc.Status{} + m.InitErr = &rpc.Status{} } if err := m.InitErr.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -837,12 +1183,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthIntrospection } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -867,7 +1214,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -895,7 +1242,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -905,6 +1252,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -916,12 +1266,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthIntrospection } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -946,7 +1297,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -974,7 +1325,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -983,6 +1334,9 @@ return ErrInvalidLengthIntrospection } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -997,12 +1351,96 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthIntrospection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ServerResponse) 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 ErrIntOverflowIntrospection + } + 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: ServerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ServerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UUID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIntrospection + } + 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 ErrInvalidLengthIntrospection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIntrospection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UUID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIntrospection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthIntrospection } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1015,6 +1453,7 @@ func skipIntrospection(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1046,10 +1485,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1066,92 +1503,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthIntrospection } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowIntrospection - } - 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 := skipIntrospection(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupIntrospection + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthIntrospection + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthIntrospection = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowIntrospection = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthIntrospection = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowIntrospection = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupIntrospection = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/introspection/v1/introspection.proto", fileDescriptorIntrospection) -} - -var fileDescriptorIntrospection = []byte{ - // 487 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0xcd, 0x3a, 0x69, 0xdc, 0x4c, 0xca, 0x87, 0x56, 0x15, 0x58, 0x3e, 0xb8, 0x51, 0xc4, 0x21, - 0x42, 0xb0, 0x56, 0x03, 0x48, 0xb4, 0x48, 0x1c, 0x22, 0x72, 0xa8, 0xd4, 0x43, 0xe5, 0x5e, 0x10, - 0x97, 0xca, 0x71, 0x36, 0x66, 0x85, 0xeb, 0xdd, 0xee, 0xae, 0x2d, 0x72, 0xe3, 0xc6, 0x5f, 0xcb, - 0x91, 0x23, 0xa7, 0x8a, 0xfa, 0x37, 0xf0, 0x03, 0x90, 0xbd, 0x76, 0x9b, 0xdc, 0x12, 0x71, 0x9b, - 0x79, 0x7e, 0x6f, 0xe6, 0xcd, 0x93, 0x17, 0x82, 0x98, 0xe9, 0xaf, 0xd9, 0x8c, 0x44, 0xfc, 0xda, - 0x8f, 0x78, 0xaa, 0x43, 0x96, 0x52, 0x39, 0x5f, 0x2f, 0x43, 0xc1, 0x7c, 0x45, 0x65, 0xce, 0x22, - 0xaa, 0x7c, 0x96, 0x6a, 0xc9, 0x95, 0xa0, 0x91, 0x66, 0x3c, 0xf5, 0xf3, 0xe3, 0x4d, 0x80, 0x08, - 0xc9, 0x35, 0xc7, 0x2f, 0x1e, 0xd4, 0xa4, 0x51, 0x92, 0x4d, 0x62, 0x7e, 0xec, 0x9e, 0x6c, 0xb5, - 0x59, 0x2f, 0x05, 0x55, 0xbe, 0x48, 0x42, 0xbd, 0xe0, 0xf2, 0xda, 0x2c, 0x70, 0x9f, 0xc7, 0x9c, - 0xc7, 0x09, 0xf5, 0xa5, 0x88, 0x7c, 0xa5, 0x43, 0x9d, 0xa9, 0xfa, 0xc3, 0x61, 0xcc, 0x63, 0x5e, - 0x95, 0x7e, 0x59, 0x19, 0x74, 0xf8, 0xd7, 0x82, 0xee, 0x45, 0x92, 0xc5, 0x2c, 0xc5, 0x18, 0x3a, - 0xe5, 0x44, 0x07, 0x0d, 0xd0, 0xa8, 0x17, 0x54, 0x35, 0x7e, 0x06, 0x16, 0x9b, 0x3b, 0x56, 0x89, - 0x4c, 0xba, 0xc5, 0xed, 0x91, 0x75, 0xf6, 0x29, 0xb0, 0xd8, 0x1c, 0xbb, 0xb0, 0x2f, 0xe9, 0x4d, - 0xc6, 0x24, 0x55, 0x4e, 0x7b, 0xd0, 0x1e, 0xf5, 0x82, 0xfb, 0x1e, 0x7f, 0x84, 0x5e, 0xe3, 0x49, - 0x39, 0x9d, 0x41, 0x7b, 0xd4, 0x1f, 0xbb, 0x64, 0xed, 0xec, 0xca, 0x36, 0xb9, 0xa8, 0x29, 0x93, - 0xce, 0xea, 0xf6, 0xa8, 0x15, 0x3c, 0x48, 0xf0, 0x25, 0xd8, 0xf4, 0xbb, 0xe0, 0x52, 0x2b, 0x67, - 0xaf, 0x52, 0x9f, 0x90, 0x6d, 0x42, 0x23, 0xe6, 0x0c, 0x32, 0x35, 0xda, 0x69, 0xaa, 0xe5, 0x32, - 0x68, 0x26, 0xe1, 0x21, 0x1c, 0x44, 0xa1, 0x08, 0x67, 0x2c, 0x61, 0x9a, 0x51, 0xe5, 0x74, 0x2b, - 0xd3, 0x1b, 0x18, 0x7e, 0x0d, 0xfb, 0x2c, 0x65, 0xfa, 0x8a, 0x4a, 0xe9, 0xd8, 0x03, 0x34, 0xea, - 0x8f, 0x31, 0x31, 0x69, 0x12, 0x29, 0x22, 0x72, 0x59, 0xa5, 0x19, 0xd8, 0x25, 0x67, 0x2a, 0xa5, - 0x7b, 0x0a, 0x07, 0xeb, 0xbb, 0xf0, 0x53, 0x68, 0x7f, 0xa3, 0xcb, 0x3a, 0xbe, 0xb2, 0xc4, 0x87, - 0xb0, 0x97, 0x87, 0x49, 0x46, 0x4d, 0x80, 0x81, 0x69, 0x4e, 0xad, 0xf7, 0x68, 0xf8, 0x12, 0x1e, - 0x1b, 0xbb, 0x2a, 0xa0, 0x37, 0x19, 0x55, 0x1a, 0x3b, 0x60, 0x2f, 0x58, 0xa2, 0xa9, 0x54, 0x0e, - 0xaa, 0xbc, 0x35, 0xed, 0xf0, 0x0a, 0x9e, 0xdc, 0x73, 0x95, 0xe0, 0xa9, 0xa2, 0xf8, 0x1c, 0x6c, - 0x61, 0xa0, 0x8a, 0xdc, 0x1f, 0xbf, 0xda, 0x25, 0xa2, 0x3a, 0xf2, 0x66, 0xc4, 0xf8, 0x27, 0x82, - 0x47, 0x67, 0xeb, 0x54, 0x9c, 0x83, 0x5d, 0xaf, 0xc4, 0x6f, 0x77, 0x99, 0xdc, 0x5c, 0xe3, 0xbe, - 0xdb, 0x51, 0x65, 0xee, 0x9a, 0x2c, 0x56, 0x77, 0x5e, 0xeb, 0xf7, 0x9d, 0xd7, 0xfa, 0x51, 0x78, - 0x68, 0x55, 0x78, 0xe8, 0x57, 0xe1, 0xa1, 0x3f, 0x85, 0x87, 0xbe, 0x9c, 0xff, 0xdf, 0x5b, 0xfc, - 0xb0, 0x01, 0x7c, 0xb6, 0x66, 0xdd, 0xea, 0xf7, 0x7f, 0xf3, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe6, - 0x72, 0xde, 0x35, 0xe4, 0x03, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/introspection/v1/introspection.proto containerd-1.5.9/api/services/introspection/v1/introspection.proto --- containerd-1.2.6/api/services/introspection/v1/introspection.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/introspection/v1/introspection.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,9 +1,26 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.introspection.v1; import "github.com/containerd/containerd/api/types/platform.proto"; import "google/rpc/status.proto"; +import "google/protobuf/empty.proto"; import weak "gogoproto/gogo.proto"; option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection"; @@ -14,6 +31,8 @@ // Clients can use this to detect features and capabilities when using // containerd. rpc Plugins(PluginsRequest) returns (PluginsResponse); + // Server returns information about the containerd server + rpc Server(google.protobuf.Empty) returns (ServerResponse); } message Plugin { @@ -79,3 +98,7 @@ message PluginsResponse { repeated Plugin plugins = 1 [(gogoproto.nullable) = false]; } + +message ServerResponse { + string uuid = 1 [(gogoproto.customname) = "UUID"]; +} diff -Nru containerd-1.2.6/api/services/leases/v1/leases.pb.go containerd-1.5.9/api/services/leases/v1/leases.pb.go --- containerd-1.2.6/api/services/leases/v1/leases.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/leases/v1/leases.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,42 +1,25 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/leases/v1/leases.proto -/* - Package leases is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/leases/v1/leases.proto - - It has these top-level messages: - Lease - CreateRequest - CreateResponse - DeleteRequest - ListRequest - ListResponse -*/ package leases -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" - -import time "time" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -48,37 +31,130 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Lease is an object which retains resources while it exists. type Lease struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` - Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Lease) Reset() { *m = Lease{} } +func (*Lease) ProtoMessage() {} +func (*Lease) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{0} +} +func (m *Lease) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Lease) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Lease.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Lease) XXX_Merge(src proto.Message) { + xxx_messageInfo_Lease.Merge(m, src) +} +func (m *Lease) XXX_Size() int { + return m.Size() +} +func (m *Lease) XXX_DiscardUnknown() { + xxx_messageInfo_Lease.DiscardUnknown(m) } -func (m *Lease) Reset() { *m = Lease{} } -func (*Lease) ProtoMessage() {} -func (*Lease) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{0} } +var xxx_messageInfo_Lease proto.InternalMessageInfo type CreateRequest struct { // ID is used to identity the lease, when the id is not set the service // generates a random identifier for the lease. - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateRequest) Reset() { *m = CreateRequest{} } +func (*CreateRequest) ProtoMessage() {} +func (*CreateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{1} +} +func (m *CreateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateRequest.Merge(m, src) +} +func (m *CreateRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateRequest.DiscardUnknown(m) } -func (m *CreateRequest) Reset() { *m = CreateRequest{} } -func (*CreateRequest) ProtoMessage() {} -func (*CreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{1} } +var xxx_messageInfo_CreateRequest proto.InternalMessageInfo type CreateResponse struct { - Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"` + Lease *Lease `protobuf:"bytes,1,opt,name=lease,proto3" json:"lease,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateResponse) Reset() { *m = CreateResponse{} } +func (*CreateResponse) ProtoMessage() {} +func (*CreateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{2} +} +func (m *CreateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateResponse.Merge(m, src) +} +func (m *CreateResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateResponse.DiscardUnknown(m) } -func (m *CreateResponse) Reset() { *m = CreateResponse{} } -func (*CreateResponse) ProtoMessage() {} -func (*CreateResponse) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{2} } +var xxx_messageInfo_CreateResponse proto.InternalMessageInfo type DeleteRequest struct { ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -86,36 +162,386 @@ // synchronously before returning to the caller // // Default is false - Sync bool `protobuf:"varint,2,opt,name=sync,proto3" json:"sync,omitempty"` + Sync bool `protobuf:"varint,2,opt,name=sync,proto3" json:"sync,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } +func (*DeleteRequest) ProtoMessage() {} +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{3} +} +func (m *DeleteRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteRequest.Merge(m, src) +} +func (m *DeleteRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteRequest.DiscardUnknown(m) } -func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } -func (*DeleteRequest) ProtoMessage() {} -func (*DeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{3} } +var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo type ListRequest struct { - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListRequest) Reset() { *m = ListRequest{} } +func (*ListRequest) ProtoMessage() {} +func (*ListRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{4} +} +func (m *ListRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRequest.Merge(m, src) +} +func (m *ListRequest) XXX_Size() int { + return m.Size() +} +func (m *ListRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListRequest.DiscardUnknown(m) } -func (m *ListRequest) Reset() { *m = ListRequest{} } -func (*ListRequest) ProtoMessage() {} -func (*ListRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{4} } +var xxx_messageInfo_ListRequest proto.InternalMessageInfo type ListResponse struct { - Leases []*Lease `protobuf:"bytes,1,rep,name=leases" json:"leases,omitempty"` + Leases []*Lease `protobuf:"bytes,1,rep,name=leases,proto3" json:"leases,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListResponse) Reset() { *m = ListResponse{} } +func (*ListResponse) ProtoMessage() {} +func (*ListResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{5} +} +func (m *ListResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListResponse.Merge(m, src) +} +func (m *ListResponse) XXX_Size() int { + return m.Size() +} +func (m *ListResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListResponse proto.InternalMessageInfo + +type Resource struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // For snapshotter resource, there are many snapshotter types here, like + // overlayfs, devmapper etc. The type will be formatted with type, + // like "snapshotter/overlayfs". + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Resource) Reset() { *m = Resource{} } +func (*Resource) ProtoMessage() {} +func (*Resource) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{6} +} +func (m *Resource) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Resource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Resource.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Resource) XXX_Merge(src proto.Message) { + xxx_messageInfo_Resource.Merge(m, src) +} +func (m *Resource) XXX_Size() int { + return m.Size() +} +func (m *Resource) XXX_DiscardUnknown() { + xxx_messageInfo_Resource.DiscardUnknown(m) +} + +var xxx_messageInfo_Resource proto.InternalMessageInfo + +type AddResourceRequest struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Resource Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AddResourceRequest) Reset() { *m = AddResourceRequest{} } +func (*AddResourceRequest) ProtoMessage() {} +func (*AddResourceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{7} +} +func (m *AddResourceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddResourceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddResourceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddResourceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddResourceRequest.Merge(m, src) +} +func (m *AddResourceRequest) XXX_Size() int { + return m.Size() +} +func (m *AddResourceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AddResourceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AddResourceRequest proto.InternalMessageInfo + +type DeleteResourceRequest struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Resource Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResourceRequest) Reset() { *m = DeleteResourceRequest{} } +func (*DeleteResourceRequest) ProtoMessage() {} +func (*DeleteResourceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{8} +} +func (m *DeleteResourceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteResourceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteResourceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteResourceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResourceRequest.Merge(m, src) +} +func (m *DeleteResourceRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteResourceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResourceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteResourceRequest proto.InternalMessageInfo + +type ListResourcesRequest struct { + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListResourcesRequest) Reset() { *m = ListResourcesRequest{} } +func (*ListResourcesRequest) ProtoMessage() {} +func (*ListResourcesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{9} +} +func (m *ListResourcesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListResourcesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListResourcesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListResourcesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListResourcesRequest.Merge(m, src) +} +func (m *ListResourcesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListResourcesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListResourcesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListResourcesRequest proto.InternalMessageInfo + +type ListResourcesResponse struct { + Resources []Resource `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListResourcesResponse) Reset() { *m = ListResourcesResponse{} } +func (*ListResourcesResponse) ProtoMessage() {} +func (*ListResourcesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fefd70dfe8d93cbf, []int{10} +} +func (m *ListResourcesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListResourcesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListResourcesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListResourcesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListResourcesResponse.Merge(m, src) +} +func (m *ListResourcesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListResourcesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListResourcesResponse.DiscardUnknown(m) } -func (m *ListResponse) Reset() { *m = ListResponse{} } -func (*ListResponse) ProtoMessage() {} -func (*ListResponse) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{5} } +var xxx_messageInfo_ListResourcesResponse proto.InternalMessageInfo func init() { proto.RegisterType((*Lease)(nil), "containerd.services.leases.v1.Lease") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.leases.v1.Lease.LabelsEntry") proto.RegisterType((*CreateRequest)(nil), "containerd.services.leases.v1.CreateRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.leases.v1.CreateRequest.LabelsEntry") proto.RegisterType((*CreateResponse)(nil), "containerd.services.leases.v1.CreateResponse") proto.RegisterType((*DeleteRequest)(nil), "containerd.services.leases.v1.DeleteRequest") proto.RegisterType((*ListRequest)(nil), "containerd.services.leases.v1.ListRequest") proto.RegisterType((*ListResponse)(nil), "containerd.services.leases.v1.ListResponse") + proto.RegisterType((*Resource)(nil), "containerd.services.leases.v1.Resource") + proto.RegisterType((*AddResourceRequest)(nil), "containerd.services.leases.v1.AddResourceRequest") + proto.RegisterType((*DeleteResourceRequest)(nil), "containerd.services.leases.v1.DeleteResourceRequest") + proto.RegisterType((*ListResourcesRequest)(nil), "containerd.services.leases.v1.ListResourcesRequest") + proto.RegisterType((*ListResourcesResponse)(nil), "containerd.services.leases.v1.ListResourcesResponse") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/leases/v1/leases.proto", fileDescriptor_fefd70dfe8d93cbf) +} + +var fileDescriptor_fefd70dfe8d93cbf = []byte{ + // 644 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xce, 0x26, 0xa9, 0x49, 0x26, 0xb4, 0x42, 0xab, 0xb6, 0x8a, 0x8c, 0x48, 0x22, 0x0b, 0xa9, + 0x11, 0x3f, 0x36, 0x4d, 0x2b, 0x54, 0x5a, 0x84, 0xd4, 0xb4, 0x95, 0xa8, 0x88, 0x10, 0xb2, 0x38, + 0x54, 0x1c, 0xa8, 0x1c, 0x7b, 0x1b, 0x2c, 0x9c, 0xd8, 0x78, 0x37, 0x41, 0xe9, 0x89, 0x47, 0xe0, + 0x61, 0x78, 0x88, 0x1e, 0x39, 0x21, 0x4e, 0x85, 0xe6, 0xc6, 0x5b, 0x20, 0xef, 0x0f, 0x6d, 0x5a, + 0xb5, 0x76, 0x11, 0xe2, 0x36, 0x1b, 0x7f, 0xdf, 0xcc, 0x37, 0x33, 0xdf, 0x6e, 0x60, 0xbb, 0xe7, + 0xb3, 0x77, 0xc3, 0xae, 0xe9, 0x86, 0x7d, 0xcb, 0x0d, 0x07, 0xcc, 0xf1, 0x07, 0x24, 0xf6, 0xce, + 0x86, 0x4e, 0xe4, 0x5b, 0x94, 0xc4, 0x23, 0xdf, 0x25, 0xd4, 0x0a, 0x88, 0x43, 0x09, 0xb5, 0x46, + 0xcb, 0x32, 0x32, 0xa3, 0x38, 0x64, 0x21, 0xbe, 0x73, 0x8a, 0x37, 0x15, 0xd6, 0x94, 0x88, 0xd1, + 0xb2, 0x3e, 0xdf, 0x0b, 0x7b, 0x21, 0x47, 0x5a, 0x49, 0x24, 0x48, 0xfa, 0xed, 0x5e, 0x18, 0xf6, + 0x02, 0x62, 0xf1, 0x53, 0x77, 0x78, 0x60, 0x91, 0x7e, 0xc4, 0xc6, 0xf2, 0x63, 0xfd, 0xfc, 0x47, + 0xe6, 0xf7, 0x09, 0x65, 0x4e, 0x3f, 0x12, 0x00, 0xe3, 0x17, 0x82, 0x99, 0x4e, 0x52, 0x01, 0x2f, + 0x42, 0xde, 0xf7, 0xaa, 0xa8, 0x81, 0x9a, 0xe5, 0xb6, 0x36, 0x39, 0xae, 0xe7, 0x77, 0xb7, 0xed, + 0xbc, 0xef, 0xe1, 0x2d, 0x00, 0x37, 0x26, 0x0e, 0x23, 0xde, 0xbe, 0xc3, 0xaa, 0xf9, 0x06, 0x6a, + 0x56, 0x5a, 0xba, 0x29, 0xf2, 0x9a, 0x2a, 0xaf, 0xf9, 0x5a, 0xe5, 0x6d, 0x97, 0x8e, 0x8e, 0xeb, + 0xb9, 0xcf, 0x3f, 0xea, 0xc8, 0x2e, 0x4b, 0xde, 0x26, 0xc3, 0xcf, 0x41, 0x0b, 0x9c, 0x2e, 0x09, + 0x68, 0xb5, 0xd0, 0x28, 0x34, 0x2b, 0xad, 0x47, 0xe6, 0x95, 0xad, 0x9a, 0x5c, 0x92, 0xd9, 0xe1, + 0x94, 0x9d, 0x01, 0x8b, 0xc7, 0xb6, 0xe4, 0xeb, 0x4f, 0xa0, 0x72, 0xe6, 0x67, 0x7c, 0x0b, 0x0a, + 0xef, 0xc9, 0x58, 0xc8, 0xb6, 0x93, 0x10, 0xcf, 0xc3, 0xcc, 0xc8, 0x09, 0x86, 0x84, 0x4b, 0x2d, + 0xdb, 0xe2, 0xb0, 0x9e, 0x5f, 0x43, 0xc6, 0x17, 0x04, 0xb3, 0x5b, 0x5c, 0x92, 0x4d, 0x3e, 0x0c, + 0x09, 0x65, 0x97, 0xf6, 0xfc, 0xea, 0x9c, 0xdc, 0xb5, 0x14, 0xb9, 0x53, 0x59, 0xff, 0xb5, 0xec, + 0x0e, 0xcc, 0xa9, 0xfc, 0x34, 0x0a, 0x07, 0x94, 0xe0, 0x75, 0x98, 0xe1, 0xb5, 0x39, 0xbf, 0xd2, + 0xba, 0x9b, 0x65, 0x98, 0xb6, 0xa0, 0x18, 0x1b, 0x30, 0xbb, 0x4d, 0x02, 0x92, 0x3e, 0x03, 0x0c, + 0x45, 0x3a, 0x1e, 0xb8, 0x5c, 0x4f, 0xc9, 0xe6, 0xb1, 0xb1, 0x04, 0x95, 0x8e, 0x4f, 0x99, 0xa2, + 0x56, 0xe1, 0xc6, 0x81, 0x1f, 0x30, 0x12, 0xd3, 0x2a, 0x6a, 0x14, 0x9a, 0x65, 0x5b, 0x1d, 0x8d, + 0x0e, 0xdc, 0x14, 0x40, 0xa9, 0xf8, 0x29, 0x68, 0x42, 0x0f, 0x07, 0x66, 0x95, 0x2c, 0x39, 0xc6, + 0x63, 0x28, 0xd9, 0x84, 0x86, 0xc3, 0xd8, 0x25, 0x57, 0xc9, 0x65, 0xe3, 0x48, 0x8d, 0x8f, 0xc7, + 0xc6, 0x47, 0xc0, 0x9b, 0x9e, 0xa7, 0xa8, 0x69, 0x0d, 0xef, 0x42, 0x29, 0x96, 0x50, 0x69, 0xf3, + 0xa5, 0x14, 0x95, 0x2a, 0x73, 0xbb, 0x98, 0x78, 0xde, 0xfe, 0x43, 0x37, 0x0e, 0x61, 0x41, 0x0d, + 0xf9, 0xbf, 0xd7, 0x36, 0x61, 0x5e, 0x8e, 0x9e, 0x9f, 0x69, 0x4a, 0x69, 0xc3, 0x83, 0x85, 0x73, + 0x78, 0xb9, 0xb3, 0x17, 0x50, 0x56, 0x49, 0xd5, 0xda, 0xae, 0x29, 0xea, 0x94, 0xdf, 0xfa, 0x56, + 0x04, 0x8d, 0x2f, 0x95, 0x62, 0x02, 0x9a, 0xf0, 0x33, 0x7e, 0x70, 0x9d, 0x6b, 0xa5, 0x3f, 0xcc, + 0x88, 0x96, 0xf2, 0x5f, 0x82, 0x26, 0x76, 0x90, 0x5a, 0x66, 0xea, 0x3e, 0xe8, 0x8b, 0x17, 0xde, + 0xb6, 0x9d, 0xe4, 0x41, 0xc5, 0xfb, 0x50, 0x4c, 0xe6, 0x84, 0xef, 0xa5, 0x59, 0xf7, 0xf4, 0x82, + 0xe8, 0xf7, 0x33, 0x61, 0xa5, 0xe0, 0x3d, 0xa8, 0x9c, 0x71, 0x2b, 0x5e, 0x4e, 0xe1, 0x5e, 0x74, + 0xf6, 0xa5, 0xd2, 0xdf, 0xc2, 0xdc, 0xb4, 0x1d, 0xf1, 0x6a, 0xc6, 0x91, 0x64, 0xcb, 0x7f, 0x08, + 0xb3, 0x53, 0x16, 0xc2, 0x2b, 0xd9, 0xfa, 0x9e, 0x32, 0xa8, 0xbe, 0x7a, 0x3d, 0x92, 0x98, 0x5a, + 0x7b, 0xef, 0xe8, 0xa4, 0x96, 0xfb, 0x7e, 0x52, 0xcb, 0x7d, 0x9a, 0xd4, 0xd0, 0xd1, 0xa4, 0x86, + 0xbe, 0x4e, 0x6a, 0xe8, 0xe7, 0xa4, 0x86, 0xde, 0x3c, 0xfb, 0xcb, 0xff, 0xe4, 0x0d, 0x11, 0xed, + 0xe5, 0xba, 0x1a, 0xef, 0x73, 0xe5, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0d, 0xfe, 0x39, 0x67, + 0xde, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -126,8 +552,9 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Leases service - +// LeasesClient is the client API for Leases service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type LeasesClient interface { // Create creates a new lease for managing changes to metadata. A lease // can be used to protect objects from being removed. @@ -135,10 +562,16 @@ // Delete deletes the lease and makes any unreferenced objects created // during the lease eligible for garbage collection if not referenced // or retained by other resources during the lease. - Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) + Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*types.Empty, error) // List lists all active leases, returning the full list of // leases and optionally including the referenced resources. List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) + // AddResource references the resource by the provided lease. + AddResource(ctx context.Context, in *AddResourceRequest, opts ...grpc.CallOption) (*types.Empty, error) + // DeleteResource dereferences the resource by the provided lease. + DeleteResource(ctx context.Context, in *DeleteResourceRequest, opts ...grpc.CallOption) (*types.Empty, error) + // ListResources lists all the resources referenced by the lease. + ListResources(ctx context.Context, in *ListResourcesRequest, opts ...grpc.CallOption) (*ListResourcesResponse, error) } type leasesClient struct { @@ -151,16 +584,16 @@ func (c *leasesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { out := new(CreateResponse) - err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Create", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Create", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *leasesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) { - out := new(google_protobuf1.Empty) - err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Delete", in, out, c.cc, opts...) +func (c *leasesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Delete", in, out, opts...) if err != nil { return nil, err } @@ -169,15 +602,41 @@ func (c *leasesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { out := new(ListResponse) - err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/List", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/List", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *leasesClient) AddResource(ctx context.Context, in *AddResourceRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/AddResource", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *leasesClient) DeleteResource(ctx context.Context, in *DeleteResourceRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/DeleteResource", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Leases service +func (c *leasesClient) ListResources(ctx context.Context, in *ListResourcesRequest, opts ...grpc.CallOption) (*ListResourcesResponse, error) { + out := new(ListResourcesResponse) + err := c.cc.Invoke(ctx, "/containerd.services.leases.v1.Leases/ListResources", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} +// LeasesServer is the server API for Leases service. type LeasesServer interface { // Create creates a new lease for managing changes to metadata. A lease // can be used to protect objects from being removed. @@ -185,10 +644,39 @@ // Delete deletes the lease and makes any unreferenced objects created // during the lease eligible for garbage collection if not referenced // or retained by other resources during the lease. - Delete(context.Context, *DeleteRequest) (*google_protobuf1.Empty, error) + Delete(context.Context, *DeleteRequest) (*types.Empty, error) // List lists all active leases, returning the full list of // leases and optionally including the referenced resources. List(context.Context, *ListRequest) (*ListResponse, error) + // AddResource references the resource by the provided lease. + AddResource(context.Context, *AddResourceRequest) (*types.Empty, error) + // DeleteResource dereferences the resource by the provided lease. + DeleteResource(context.Context, *DeleteResourceRequest) (*types.Empty, error) + // ListResources lists all the resources referenced by the lease. + ListResources(context.Context, *ListResourcesRequest) (*ListResourcesResponse, error) +} + +// UnimplementedLeasesServer can be embedded to have forward compatible implementations. +type UnimplementedLeasesServer struct { +} + +func (*UnimplementedLeasesServer) Create(ctx context.Context, req *CreateRequest) (*CreateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (*UnimplementedLeasesServer) Delete(ctx context.Context, req *DeleteRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") +} +func (*UnimplementedLeasesServer) List(ctx context.Context, req *ListRequest) (*ListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedLeasesServer) AddResource(ctx context.Context, req *AddResourceRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddResource not implemented") +} +func (*UnimplementedLeasesServer) DeleteResource(ctx context.Context, req *DeleteResourceRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteResource not implemented") +} +func (*UnimplementedLeasesServer) ListResources(ctx context.Context, req *ListResourcesRequest) (*ListResourcesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListResources not implemented") } func RegisterLeasesServer(s *grpc.Server, srv LeasesServer) { @@ -249,6 +737,60 @@ return interceptor(ctx, in, info, handler) } +func _Leases_AddResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddResourceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LeasesServer).AddResource(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.leases.v1.Leases/AddResource", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LeasesServer).AddResource(ctx, req.(*AddResourceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Leases_DeleteResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteResourceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LeasesServer).DeleteResource(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.leases.v1.Leases/DeleteResource", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LeasesServer).DeleteResource(ctx, req.(*DeleteResourceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Leases_ListResources_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListResourcesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LeasesServer).ListResources(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.leases.v1.Leases/ListResources", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LeasesServer).ListResources(ctx, req.(*ListResourcesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Leases_serviceDesc = grpc.ServiceDesc{ ServiceName: "containerd.services.leases.v1.Leases", HandlerType: (*LeasesServer)(nil), @@ -265,6 +807,18 @@ MethodName: "List", Handler: _Leases_List_Handler, }, + { + MethodName: "AddResource", + Handler: _Leases_AddResource_Handler, + }, + { + MethodName: "DeleteResource", + Handler: _Leases_DeleteResource_Handler, + }, + { + MethodName: "ListResources", + Handler: _Leases_ListResources_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "github.com/containerd/containerd/api/services/leases/v1/leases.proto", @@ -273,7 +827,7 @@ func (m *Lease) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -281,48 +835,60 @@ } func (m *Lease) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Lease) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - dAtA[i] = 0x12 - i++ - i = encodeVarintLeases(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt))) - n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n1 if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x1a - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v))) - i = encodeVarintLeases(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintLeases(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintLeases(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintLeases(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a } } - return i, nil + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintLeases(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *CreateRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -330,40 +896,52 @@ } func (m *CreateRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x1a - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v))) - i = encodeVarintLeases(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintLeases(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintLeases(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintLeases(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a } } - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *CreateResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -371,27 +949,38 @@ } func (m *CreateResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Lease != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(m.Lease.Size())) - n2, err := m.Lease.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Lease.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeases(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -399,33 +988,43 @@ } func (m *DeleteRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Sync { - dAtA[i] = 0x10 - i++ + i-- if m.Sync { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -433,32 +1032,35 @@ } func (m *ListRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintLeases(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *ListResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -466,42 +1068,262 @@ } func (m *ListResponse) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Leases) > 0 { - for _, msg := range m.Leases { + for iNdEx := len(m.Leases) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Leases[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeases(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0xa - i++ - i = encodeVarintLeases(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + } + } + return len(dAtA) - i, nil +} + +func (m *Resource) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Resource) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Resource) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Type) > 0 { + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintLeases(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddResourceRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddResourceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddResourceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Resource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeases(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DeleteResourceRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeleteResourceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteResourceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Resource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeases(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListResourcesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListResourcesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListResourcesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintLeases(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListResourcesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListResourcesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListResourcesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Resources) > 0 { + for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Resources[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLeases(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func encodeVarintLeases(dAtA []byte, offset int, v uint64) int { + offset -= sovLeases(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Lease) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovLeases(uint64(l)) } - l = types.SizeOfStdTime(m.CreatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovLeases(uint64(l)) if len(m.Labels) > 0 { for k, v := range m.Labels { @@ -511,10 +1333,16 @@ n += mapEntrySize + 1 + sovLeases(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -529,20 +1357,32 @@ n += mapEntrySize + 1 + sovLeases(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Lease != nil { l = m.Lease.Size() n += 1 + l + sovLeases(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -552,10 +1392,16 @@ if m.Sync { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -564,10 +1410,16 @@ n += 1 + l + sovLeases(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Leases) > 0 { @@ -576,19 +1428,105 @@ n += 1 + l + sovLeases(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } -func sovLeases(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break +func (m *Resource) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ID) + if l > 0 { + n += 1 + l + sovLeases(uint64(l)) + } + l = len(m.Type) + if l > 0 { + n += 1 + l + sovLeases(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *AddResourceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ID) + if l > 0 { + n += 1 + l + sovLeases(uint64(l)) + } + l = m.Resource.Size() + n += 1 + l + sovLeases(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *DeleteResourceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ID) + if l > 0 { + n += 1 + l + sovLeases(uint64(l)) + } + l = m.Resource.Size() + n += 1 + l + sovLeases(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ListResourcesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ID) + if l > 0 { + n += 1 + l + sovLeases(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ListResourcesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Resources) > 0 { + for _, e := range m.Resources { + l = e.Size() + n += 1 + l + sovLeases(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } + +func sovLeases(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} func sozLeases(x uint64) (n int) { return sovLeases(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } @@ -600,7 +1538,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -608,8 +1546,9 @@ mapStringForLabels += "}" s := strings.Join([]string{`&Lease{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -622,7 +1561,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -631,6 +1570,7 @@ s := strings.Join([]string{`&CreateRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -640,7 +1580,8 @@ return "nil" } s := strings.Join([]string{`&CreateResponse{`, - `Lease:` + strings.Replace(fmt.Sprintf("%v", this.Lease), "Lease", "Lease", 1) + `,`, + `Lease:` + strings.Replace(this.Lease.String(), "Lease", "Lease", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -652,6 +1593,7 @@ s := strings.Join([]string{`&DeleteRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Sync:` + fmt.Sprintf("%v", this.Sync) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -662,6 +1604,7 @@ } s := strings.Join([]string{`&ListRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -670,8 +1613,77 @@ if this == nil { return "nil" } + repeatedStringForLeases := "[]*Lease{" + for _, f := range this.Leases { + repeatedStringForLeases += strings.Replace(f.String(), "Lease", "Lease", 1) + "," + } + repeatedStringForLeases += "}" s := strings.Join([]string{`&ListResponse{`, - `Leases:` + strings.Replace(fmt.Sprintf("%v", this.Leases), "Lease", "Lease", 1) + `,`, + `Leases:` + repeatedStringForLeases + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *Resource) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Resource{`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `Type:` + fmt.Sprintf("%v", this.Type) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *AddResourceRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AddResourceRequest{`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `Resource:` + strings.Replace(strings.Replace(this.Resource.String(), "Resource", "Resource", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *DeleteResourceRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&DeleteResourceRequest{`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `Resource:` + strings.Replace(strings.Replace(this.Resource.String(), "Resource", "Resource", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *ListResourcesRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ListResourcesRequest{`, + `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *ListResourcesResponse) String() string { + if this == nil { + return "nil" + } + repeatedStringForResources := "[]Resource{" + for _, f := range this.Resources { + repeatedStringForResources += strings.Replace(strings.Replace(f.String(), "Resource", "Resource", 1), `&`, ``, 1) + "," + } + repeatedStringForResources += "}" + s := strings.Join([]string{`&ListResourcesResponse{`, + `Resources:` + repeatedStringForResources + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -699,7 +1711,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -727,7 +1739,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -737,6 +1749,9 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -756,7 +1771,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -765,10 +1780,13 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -786,7 +1804,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -795,6 +1813,9 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -815,7 +1836,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -832,7 +1853,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -842,6 +1863,9 @@ return ErrInvalidLengthLeases } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthLeases + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -858,7 +1882,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -868,6 +1892,9 @@ return ErrInvalidLengthLeases } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthLeases + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -879,7 +1906,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > postIndex { @@ -888,7 +1915,575 @@ iNdEx += skippy } } - m.Labels[mapkey] = mapvalue + m.Labels[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CreateRequest) 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 ErrIntOverflowLeases + } + 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: CreateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + 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 ErrInvalidLengthLeases + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLeases + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Labels == nil { + m.Labels = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthLeases + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthLeases + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthLeases + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthLeases + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Labels[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CreateResponse) 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 ErrIntOverflowLeases + } + 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: CreateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Lease", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLeases + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Lease == nil { + m.Lease = &Lease{} + } + if err := m.Lease.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeleteRequest) 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 ErrIntOverflowLeases + } + 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: DeleteRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + 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 ErrInvalidLengthLeases + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sync", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Sync = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListRequest) 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 ErrIntOverflowLeases + } + 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: ListRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + 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 ErrInvalidLengthLeases + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLeases(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLeases + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListResponse) 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 ErrIntOverflowLeases + } + 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: ListResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Leases", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLeases + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Leases = append(m.Leases, &Lease{}) + if err := m.Leases[len(m.Leases)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -896,12 +2491,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -911,7 +2507,7 @@ } return nil } -func (m *CreateRequest) Unmarshal(dAtA []byte) error { +func (m *Resource) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -926,7 +2522,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -934,10 +2530,10 @@ fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CreateRequest: wiretype end group for non-group") + return fmt.Errorf("proto: Resource: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CreateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Resource: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -954,7 +2550,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -964,16 +2560,19 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } m.ID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowLeases @@ -983,109 +2582,23 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthLeases + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { return ErrInvalidLengthLeases } - postIndex := iNdEx + msglen if postIndex > l { return io.ErrUnexpectedEOF } - if m.Labels == nil { - m.Labels = make(map[string]string) - } - var mapkey string - var mapvalue string - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLeases - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - var stringLenmapkey uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLeases - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapkey := int(stringLenmapkey) - if intStringLenmapkey < 0 { - return ErrInvalidLengthLeases - } - postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey > l { - return io.ErrUnexpectedEOF - } - mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) - iNdEx = postStringIndexmapkey - } else if fieldNum == 2 { - var stringLenmapvalue uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLeases - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapvalue := int(stringLenmapvalue) - if intStringLenmapvalue < 0 { - return ErrInvalidLengthLeases - } - postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue > l { - return io.ErrUnexpectedEOF - } - mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) - iNdEx = postStringIndexmapvalue - } else { - iNdEx = entryPreIndex - skippy, err := skipLeases(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthLeases - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - m.Labels[mapkey] = mapvalue + m.Type = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1093,12 +2606,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1108,7 +2622,7 @@ } return nil } -func (m *CreateResponse) Unmarshal(dAtA []byte) error { +func (m *AddResourceRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1123,7 +2637,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1131,15 +2645,47 @@ fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CreateResponse: wiretype end group for non-group") + return fmt.Errorf("proto: AddResourceRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CreateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AddResourceRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Lease", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLeases + } + 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 ErrInvalidLengthLeases + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1151,7 +2697,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1160,13 +2706,13 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Lease == nil { - m.Lease = &Lease{} - } - if err := m.Lease.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Resource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1176,12 +2722,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1191,7 +2738,7 @@ } return nil } -func (m *DeleteRequest) Unmarshal(dAtA []byte) error { +func (m *DeleteResourceRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1206,7 +2753,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1214,10 +2761,10 @@ fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: DeleteRequest: wiretype end group for non-group") + return fmt.Errorf("proto: DeleteResourceRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: DeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: DeleteResourceRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1234,7 +2781,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1244,16 +2791,19 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } m.ID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Sync", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } - var v int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowLeases @@ -1263,24 +2813,38 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.Sync = bool(v != 0) + if msglen < 0 { + return ErrInvalidLengthLeases + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Resource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipLeases(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1290,7 +2854,7 @@ } return nil } -func (m *ListRequest) Unmarshal(dAtA []byte) error { +func (m *ListResourcesRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1305,7 +2869,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1313,15 +2877,15 @@ fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ListRequest: wiretype end group for non-group") + return fmt.Errorf("proto: ListResourcesRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ListRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ListResourcesRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1333,7 +2897,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1343,10 +2907,13 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex])) + m.ID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1354,12 +2921,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1369,7 +2937,7 @@ } return nil } -func (m *ListResponse) Unmarshal(dAtA []byte) error { +func (m *ListResourcesResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1384,7 +2952,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1392,15 +2960,15 @@ fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ListResponse: wiretype end group for non-group") + return fmt.Errorf("proto: ListResourcesResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ListResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ListResourcesResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Leases", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Resources", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1412,7 +2980,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1421,11 +2989,14 @@ return ErrInvalidLengthLeases } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLeases + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Leases = append(m.Leases, &Lease{}) - if err := m.Leases[len(m.Leases)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Resources = append(m.Resources, Resource{}) + if err := m.Resources[len(m.Resources)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1435,12 +3006,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthLeases } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1453,6 +3025,7 @@ func skipLeases(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1484,10 +3057,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1504,94 +3075,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthLeases } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowLeases - } - 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 := skipLeases(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupLeases + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthLeases + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthLeases = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowLeases = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthLeases = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowLeases = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupLeases = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/leases/v1/leases.proto", fileDescriptorLeases) -} - -var fileDescriptorLeases = []byte{ - // 515 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xdf, 0x8a, 0xd3, 0x40, - 0x14, 0xc6, 0x3b, 0xe9, 0x36, 0x6e, 0x4f, 0x5d, 0x91, 0x61, 0x59, 0x4a, 0xc4, 0xb4, 0x04, 0xc1, - 0xe2, 0x9f, 0x89, 0x5b, 0x6f, 0xd6, 0x5d, 0x11, 0xec, 0x76, 0x41, 0x21, 0x88, 0x04, 0x2f, 0x16, - 0x6f, 0x96, 0x34, 0x3d, 0x1b, 0x83, 0x69, 0x12, 0x33, 0xd3, 0x42, 0xef, 0x7c, 0x04, 0x1f, 0xc1, - 0x87, 0xf0, 0x21, 0x7a, 0xe9, 0xa5, 0x57, 0xab, 0x9b, 0x3b, 0xdf, 0x42, 0x32, 0x93, 0xb0, 0x7f, - 0x44, 0x5b, 0x65, 0xef, 0xce, 0xcc, 0x7c, 0xdf, 0x99, 0xdf, 0xf9, 0xc2, 0x04, 0x86, 0x41, 0x28, - 0xde, 0x4d, 0x47, 0xcc, 0x4f, 0x26, 0xb6, 0x9f, 0xc4, 0xc2, 0x0b, 0x63, 0xcc, 0xc6, 0xe7, 0x4b, - 0x2f, 0x0d, 0x6d, 0x8e, 0xd9, 0x2c, 0xf4, 0x91, 0xdb, 0x11, 0x7a, 0x1c, 0xb9, 0x3d, 0xdb, 0x2e, - 0x2b, 0x96, 0x66, 0x89, 0x48, 0xe8, 0xed, 0x33, 0x3d, 0xab, 0xb4, 0xac, 0x54, 0xcc, 0xb6, 0x8d, - 0xcd, 0x20, 0x09, 0x12, 0xa9, 0xb4, 0x8b, 0x4a, 0x99, 0x8c, 0x5b, 0x41, 0x92, 0x04, 0x11, 0xda, - 0x72, 0x35, 0x9a, 0x1e, 0xdb, 0x38, 0x49, 0xc5, 0xbc, 0x3c, 0xec, 0x5c, 0x3e, 0x14, 0xe1, 0x04, - 0xb9, 0xf0, 0x26, 0xa9, 0x12, 0x58, 0x3f, 0x09, 0x34, 0x9c, 0xe2, 0x06, 0xba, 0x05, 0x5a, 0x38, - 0x6e, 0x93, 0x2e, 0xe9, 0x35, 0x07, 0x7a, 0x7e, 0xd2, 0xd1, 0x5e, 0x0e, 0x5d, 0x2d, 0x1c, 0xd3, - 0x7d, 0x00, 0x3f, 0x43, 0x4f, 0xe0, 0xf8, 0xc8, 0x13, 0x6d, 0xad, 0x4b, 0x7a, 0xad, 0xbe, 0xc1, - 0x54, 0x5f, 0x56, 0xf5, 0x65, 0x6f, 0xaa, 0xbe, 0x83, 0xf5, 0xc5, 0x49, 0xa7, 0xf6, 0xe9, 0x7b, - 0x87, 0xb8, 0xcd, 0xd2, 0xf7, 0x5c, 0xd0, 0x17, 0xa0, 0x47, 0xde, 0x08, 0x23, 0xde, 0xae, 0x77, - 0xeb, 0xbd, 0x56, 0xff, 0x11, 0xfb, 0xeb, 0xa8, 0x4c, 0x22, 0x31, 0x47, 0x5a, 0x0e, 0x62, 0x91, - 0xcd, 0xdd, 0xd2, 0x6f, 0x3c, 0x81, 0xd6, 0xb9, 0x6d, 0x7a, 0x13, 0xea, 0xef, 0x71, 0xae, 0xb0, - 0xdd, 0xa2, 0xa4, 0x9b, 0xd0, 0x98, 0x79, 0xd1, 0x14, 0x25, 0x6a, 0xd3, 0x55, 0x8b, 0x5d, 0x6d, - 0x87, 0x58, 0x5f, 0x08, 0x6c, 0xec, 0x4b, 0x24, 0x17, 0x3f, 0x4c, 0x91, 0x8b, 0x3f, 0xce, 0xfc, - 0xfa, 0x12, 0xee, 0xce, 0x12, 0xdc, 0x0b, 0x5d, 0xaf, 0x1a, 0xdb, 0x81, 0x1b, 0x55, 0x7f, 0x9e, - 0x26, 0x31, 0x47, 0xba, 0x0b, 0x0d, 0x79, 0xb7, 0xf4, 0xb7, 0xfa, 0x77, 0x56, 0x09, 0xd3, 0x55, - 0x16, 0x6b, 0x0f, 0x36, 0x86, 0x18, 0xe1, 0xf2, 0x0c, 0x28, 0xac, 0xf1, 0x79, 0xec, 0x4b, 0x9e, - 0x75, 0x57, 0xd6, 0xd6, 0x5d, 0x68, 0x39, 0x21, 0x17, 0x95, 0xb5, 0x0d, 0xd7, 0x8e, 0xc3, 0x48, - 0x60, 0xc6, 0xdb, 0xa4, 0x5b, 0xef, 0x35, 0xdd, 0x6a, 0x69, 0x39, 0x70, 0x5d, 0x09, 0x4b, 0xe2, - 0xa7, 0xa0, 0x2b, 0x1e, 0x29, 0x5c, 0x15, 0xb9, 0xf4, 0xf4, 0x3f, 0x6b, 0xa0, 0xcb, 0x1d, 0x4e, - 0x11, 0x74, 0x15, 0x06, 0x7d, 0xf0, 0x2f, 0xdf, 0xc4, 0x78, 0xb8, 0xa2, 0xba, 0xe4, 0x7d, 0x05, - 0xba, 0x4a, 0x69, 0xe9, 0x35, 0x17, 0xc2, 0x34, 0xb6, 0x7e, 0x7b, 0x18, 0x07, 0xc5, 0x6b, 0xa4, - 0x47, 0xb0, 0x56, 0xe4, 0x41, 0xef, 0x2d, 0x9b, 0xfb, 0x2c, 0x5d, 0xe3, 0xfe, 0x4a, 0x5a, 0x05, - 0x3c, 0x38, 0x5c, 0x9c, 0x9a, 0xb5, 0x6f, 0xa7, 0x66, 0xed, 0x63, 0x6e, 0x92, 0x45, 0x6e, 0x92, - 0xaf, 0xb9, 0x49, 0x7e, 0xe4, 0x26, 0x79, 0xfb, 0xec, 0x3f, 0x7f, 0x4d, 0x7b, 0xaa, 0x3a, 0xac, - 0x8d, 0x74, 0x39, 0xcc, 0xe3, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x14, 0x74, 0xdd, 0x12, 0xe5, - 0x04, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/leases/v1/leases.proto containerd-1.5.9/api/services/leases/v1/leases.proto --- containerd-1.2.6/api/services/leases/v1/leases.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/leases/v1/leases.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,18 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ syntax = "proto3"; package containerd.services.leases.v1; @@ -22,6 +37,15 @@ // List lists all active leases, returning the full list of // leases and optionally including the referenced resources. rpc List(ListRequest) returns (ListResponse); + + // AddResource references the resource by the provided lease. + rpc AddResource(AddResourceRequest) returns (google.protobuf.Empty); + + // DeleteResource dereferences the resource by the provided lease. + rpc DeleteResource(DeleteResourceRequest) returns (google.protobuf.Empty); + + // ListResources lists all the resources referenced by the lease. + rpc ListResources(ListResourcesRequest) returns (ListResourcesResponse); } // Lease is an object which retains resources while it exists. @@ -62,3 +86,32 @@ message ListResponse { repeated Lease leases = 1; } + +message Resource { + string id = 1; + + // For snapshotter resource, there are many snapshotter types here, like + // overlayfs, devmapper etc. The type will be formatted with type, + // like "snapshotter/overlayfs". + string type = 2; +} + +message AddResourceRequest { + string id = 1; + + Resource resource = 2 [(gogoproto.nullable) = false]; +} + +message DeleteResourceRequest { + string id = 1; + + Resource resource = 2 [(gogoproto.nullable) = false]; +} + +message ListResourcesRequest { + string id = 1; +} + +message ListResourcesResponse { + repeated Resource resources = 1 [(gogoproto.nullable) = false]; +} diff -Nru containerd-1.2.6/api/services/namespaces/v1/namespace.pb.go containerd-1.5.9/api/services/namespaces/v1/namespace.pb.go --- containerd-1.2.6/api/services/namespaces/v1/namespace.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/namespaces/v1/namespace.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,42 +1,23 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/namespaces/v1/namespace.proto -/* - Package namespaces is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/namespaces/v1/namespace.proto - - It has these top-level messages: - Namespace - GetNamespaceRequest - GetNamespaceResponse - ListNamespacesRequest - ListNamespacesResponse - CreateNamespaceRequest - CreateNamespaceResponse - UpdateNamespaceRequest - UpdateNamespaceResponse - DeleteNamespaceRequest -*/ package namespaces -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + types "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -47,7 +28,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Namespace struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -57,60 +38,277 @@ // // Note that to add a new value to this field, read the existing set and // include the entire result in the update call. - Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Namespace) Reset() { *m = Namespace{} } +func (*Namespace) ProtoMessage() {} +func (*Namespace) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{0} +} +func (m *Namespace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Namespace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Namespace.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Namespace) XXX_Merge(src proto.Message) { + xxx_messageInfo_Namespace.Merge(m, src) +} +func (m *Namespace) XXX_Size() int { + return m.Size() +} +func (m *Namespace) XXX_DiscardUnknown() { + xxx_messageInfo_Namespace.DiscardUnknown(m) } -func (m *Namespace) Reset() { *m = Namespace{} } -func (*Namespace) ProtoMessage() {} -func (*Namespace) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{0} } +var xxx_messageInfo_Namespace proto.InternalMessageInfo type GetNamespaceRequest struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetNamespaceRequest) Reset() { *m = GetNamespaceRequest{} } +func (*GetNamespaceRequest) ProtoMessage() {} +func (*GetNamespaceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{1} +} +func (m *GetNamespaceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetNamespaceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetNamespaceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetNamespaceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetNamespaceRequest.Merge(m, src) +} +func (m *GetNamespaceRequest) XXX_Size() int { + return m.Size() +} +func (m *GetNamespaceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetNamespaceRequest.DiscardUnknown(m) } -func (m *GetNamespaceRequest) Reset() { *m = GetNamespaceRequest{} } -func (*GetNamespaceRequest) ProtoMessage() {} -func (*GetNamespaceRequest) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{1} } +var xxx_messageInfo_GetNamespaceRequest proto.InternalMessageInfo type GetNamespaceResponse struct { - Namespace Namespace `protobuf:"bytes,1,opt,name=namespace" json:"namespace"` + Namespace Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetNamespaceResponse) Reset() { *m = GetNamespaceResponse{} } +func (*GetNamespaceResponse) ProtoMessage() {} +func (*GetNamespaceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{2} +} +func (m *GetNamespaceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetNamespaceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetNamespaceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetNamespaceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetNamespaceResponse.Merge(m, src) +} +func (m *GetNamespaceResponse) XXX_Size() int { + return m.Size() +} +func (m *GetNamespaceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetNamespaceResponse.DiscardUnknown(m) } -func (m *GetNamespaceResponse) Reset() { *m = GetNamespaceResponse{} } -func (*GetNamespaceResponse) ProtoMessage() {} -func (*GetNamespaceResponse) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{2} } +var xxx_messageInfo_GetNamespaceResponse proto.InternalMessageInfo type ListNamespacesRequest struct { - Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListNamespacesRequest) Reset() { *m = ListNamespacesRequest{} } +func (*ListNamespacesRequest) ProtoMessage() {} +func (*ListNamespacesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{3} +} +func (m *ListNamespacesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListNamespacesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListNamespacesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListNamespacesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListNamespacesRequest.Merge(m, src) +} +func (m *ListNamespacesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListNamespacesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListNamespacesRequest.DiscardUnknown(m) } -func (m *ListNamespacesRequest) Reset() { *m = ListNamespacesRequest{} } -func (*ListNamespacesRequest) ProtoMessage() {} -func (*ListNamespacesRequest) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{3} } +var xxx_messageInfo_ListNamespacesRequest proto.InternalMessageInfo type ListNamespacesResponse struct { - Namespaces []Namespace `protobuf:"bytes,1,rep,name=namespaces" json:"namespaces"` + Namespaces []Namespace `protobuf:"bytes,1,rep,name=namespaces,proto3" json:"namespaces"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListNamespacesResponse) Reset() { *m = ListNamespacesResponse{} } +func (*ListNamespacesResponse) ProtoMessage() {} +func (*ListNamespacesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{4} +} +func (m *ListNamespacesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListNamespacesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListNamespacesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListNamespacesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListNamespacesResponse.Merge(m, src) +} +func (m *ListNamespacesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListNamespacesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListNamespacesResponse.DiscardUnknown(m) } -func (m *ListNamespacesResponse) Reset() { *m = ListNamespacesResponse{} } -func (*ListNamespacesResponse) ProtoMessage() {} -func (*ListNamespacesResponse) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{4} } +var xxx_messageInfo_ListNamespacesResponse proto.InternalMessageInfo type CreateNamespaceRequest struct { - Namespace Namespace `protobuf:"bytes,1,opt,name=namespace" json:"namespace"` + Namespace Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateNamespaceRequest) Reset() { *m = CreateNamespaceRequest{} } +func (*CreateNamespaceRequest) ProtoMessage() {} +func (*CreateNamespaceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{5} +} +func (m *CreateNamespaceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateNamespaceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateNamespaceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateNamespaceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateNamespaceRequest.Merge(m, src) +} +func (m *CreateNamespaceRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateNamespaceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateNamespaceRequest.DiscardUnknown(m) } -func (m *CreateNamespaceRequest) Reset() { *m = CreateNamespaceRequest{} } -func (*CreateNamespaceRequest) ProtoMessage() {} -func (*CreateNamespaceRequest) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{5} } +var xxx_messageInfo_CreateNamespaceRequest proto.InternalMessageInfo type CreateNamespaceResponse struct { - Namespace Namespace `protobuf:"bytes,1,opt,name=namespace" json:"namespace"` + Namespace Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateNamespaceResponse) Reset() { *m = CreateNamespaceResponse{} } +func (*CreateNamespaceResponse) ProtoMessage() {} +func (*CreateNamespaceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{6} +} +func (m *CreateNamespaceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateNamespaceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateNamespaceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateNamespaceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateNamespaceResponse.Merge(m, src) +} +func (m *CreateNamespaceResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateNamespaceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateNamespaceResponse.DiscardUnknown(m) } -func (m *CreateNamespaceResponse) Reset() { *m = CreateNamespaceResponse{} } -func (*CreateNamespaceResponse) ProtoMessage() {} -func (*CreateNamespaceResponse) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{6} } +var xxx_messageInfo_CreateNamespaceResponse proto.InternalMessageInfo // UpdateNamespaceRequest updates the metadata for a namespace. // @@ -121,38 +319,132 @@ // Namespace provides the target value, as declared by the mask, for the update. // // The namespace field must be set. - Namespace Namespace `protobuf:"bytes,1,opt,name=namespace" json:"namespace"` + Namespace Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace"` // UpdateMask specifies which fields to perform the update on. If empty, // the operation applies to all fields. // // For the most part, this applies only to selectively updating labels on // the namespace. While field masks are typically limited to ascii alphas // and digits, we just take everything after the "labels." as the map key. - UpdateMask *google_protobuf2.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` + UpdateMask *types.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateNamespaceRequest) Reset() { *m = UpdateNamespaceRequest{} } +func (*UpdateNamespaceRequest) ProtoMessage() {} +func (*UpdateNamespaceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{7} +} +func (m *UpdateNamespaceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateNamespaceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateNamespaceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateNamespaceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateNamespaceRequest.Merge(m, src) +} +func (m *UpdateNamespaceRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateNamespaceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateNamespaceRequest.DiscardUnknown(m) } -func (m *UpdateNamespaceRequest) Reset() { *m = UpdateNamespaceRequest{} } -func (*UpdateNamespaceRequest) ProtoMessage() {} -func (*UpdateNamespaceRequest) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{7} } +var xxx_messageInfo_UpdateNamespaceRequest proto.InternalMessageInfo type UpdateNamespaceResponse struct { - Namespace Namespace `protobuf:"bytes,1,opt,name=namespace" json:"namespace"` + Namespace Namespace `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateNamespaceResponse) Reset() { *m = UpdateNamespaceResponse{} } +func (*UpdateNamespaceResponse) ProtoMessage() {} +func (*UpdateNamespaceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{8} +} +func (m *UpdateNamespaceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateNamespaceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateNamespaceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateNamespaceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateNamespaceResponse.Merge(m, src) +} +func (m *UpdateNamespaceResponse) XXX_Size() int { + return m.Size() +} +func (m *UpdateNamespaceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateNamespaceResponse.DiscardUnknown(m) } -func (m *UpdateNamespaceResponse) Reset() { *m = UpdateNamespaceResponse{} } -func (*UpdateNamespaceResponse) ProtoMessage() {} -func (*UpdateNamespaceResponse) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{8} } +var xxx_messageInfo_UpdateNamespaceResponse proto.InternalMessageInfo type DeleteNamespaceRequest struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteNamespaceRequest) Reset() { *m = DeleteNamespaceRequest{} } +func (*DeleteNamespaceRequest) ProtoMessage() {} +func (*DeleteNamespaceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8c41761eaeea4fd3, []int{9} +} +func (m *DeleteNamespaceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteNamespaceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteNamespaceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteNamespaceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteNamespaceRequest.Merge(m, src) +} +func (m *DeleteNamespaceRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteNamespaceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteNamespaceRequest.DiscardUnknown(m) } -func (m *DeleteNamespaceRequest) Reset() { *m = DeleteNamespaceRequest{} } -func (*DeleteNamespaceRequest) ProtoMessage() {} -func (*DeleteNamespaceRequest) Descriptor() ([]byte, []int) { return fileDescriptorNamespace, []int{9} } +var xxx_messageInfo_DeleteNamespaceRequest proto.InternalMessageInfo func init() { proto.RegisterType((*Namespace)(nil), "containerd.services.namespaces.v1.Namespace") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.namespaces.v1.Namespace.LabelsEntry") proto.RegisterType((*GetNamespaceRequest)(nil), "containerd.services.namespaces.v1.GetNamespaceRequest") proto.RegisterType((*GetNamespaceResponse)(nil), "containerd.services.namespaces.v1.GetNamespaceResponse") proto.RegisterType((*ListNamespacesRequest)(nil), "containerd.services.namespaces.v1.ListNamespacesRequest") @@ -164,6 +456,49 @@ proto.RegisterType((*DeleteNamespaceRequest)(nil), "containerd.services.namespaces.v1.DeleteNamespaceRequest") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/namespaces/v1/namespace.proto", fileDescriptor_8c41761eaeea4fd3) +} + +var fileDescriptor_8c41761eaeea4fd3 = []byte{ + // 551 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcd, 0x6e, 0xd3, 0x4c, + 0x14, 0xcd, 0x24, 0xf9, 0x2c, 0xe5, 0x7a, 0xf3, 0x69, 0x08, 0x26, 0x32, 0x92, 0x09, 0x5e, 0x15, + 0xa9, 0x1a, 0xab, 0x41, 0x82, 0xfe, 0xec, 0x0a, 0x6d, 0x17, 0x14, 0x84, 0x2c, 0x21, 0x21, 0x58, + 0x80, 0x93, 0x4c, 0x5c, 0x13, 0xc7, 0x36, 0x9e, 0xb1, 0xa5, 0x88, 0x05, 0xbc, 0x0d, 0x1b, 0x1e, + 0x24, 0x4b, 0x96, 0xac, 0x50, 0x9b, 0x27, 0x41, 0x33, 0x76, 0xe2, 0xd0, 0x18, 0xe1, 0x06, 0xca, + 0xee, 0x5e, 0x7b, 0xce, 0x3d, 0x67, 0xae, 0xce, 0xb1, 0xe1, 0x89, 0xeb, 0xf1, 0xb3, 0xa4, 0x4f, + 0x06, 0xe1, 0xc4, 0x1a, 0x84, 0x01, 0x77, 0xbc, 0x80, 0xc6, 0xc3, 0xd5, 0xd2, 0x89, 0x3c, 0x8b, + 0xd1, 0x38, 0xf5, 0x06, 0x94, 0x59, 0x81, 0x33, 0xa1, 0x2c, 0x72, 0x44, 0x99, 0xee, 0x14, 0x1d, + 0x89, 0xe2, 0x90, 0x87, 0xf8, 0x6e, 0x01, 0x23, 0x0b, 0x08, 0x29, 0x20, 0x24, 0xdd, 0xd1, 0xdb, + 0x6e, 0xe8, 0x86, 0xf2, 0xb4, 0x25, 0xaa, 0x0c, 0xa8, 0xdf, 0x76, 0xc3, 0xd0, 0xf5, 0xa9, 0x25, + 0xbb, 0x7e, 0x32, 0xb2, 0xe8, 0x24, 0xe2, 0xd3, 0xfc, 0x65, 0xf7, 0xf2, 0xcb, 0x91, 0x47, 0xfd, + 0xe1, 0x9b, 0x89, 0xc3, 0xc6, 0xd9, 0x09, 0xf3, 0x0b, 0x82, 0xd6, 0xb3, 0x05, 0x0d, 0xc6, 0xd0, + 0x14, 0x9c, 0x1d, 0xd4, 0x45, 0x5b, 0x2d, 0x5b, 0xd6, 0xf8, 0x39, 0x28, 0xbe, 0xd3, 0xa7, 0x3e, + 0xeb, 0xd4, 0xbb, 0x8d, 0x2d, 0xb5, 0xb7, 0x4b, 0x7e, 0x2b, 0x95, 0x2c, 0x27, 0x92, 0x53, 0x09, + 0x3d, 0x0a, 0x78, 0x3c, 0xb5, 0xf3, 0x39, 0xfa, 0x1e, 0xa8, 0x2b, 0x8f, 0xf1, 0xff, 0xd0, 0x18, + 0xd3, 0x69, 0xce, 0x29, 0x4a, 0xdc, 0x86, 0xff, 0x52, 0xc7, 0x4f, 0x68, 0xa7, 0x2e, 0x9f, 0x65, + 0xcd, 0x7e, 0x7d, 0x17, 0x99, 0xf7, 0xe0, 0xc6, 0x09, 0xe5, 0xcb, 0xf1, 0x36, 0x7d, 0x9f, 0x50, + 0xc6, 0xcb, 0x74, 0x9b, 0x67, 0xd0, 0xfe, 0xf9, 0x28, 0x8b, 0xc2, 0x80, 0x89, 0xfb, 0xb4, 0x96, + 0x62, 0x25, 0x40, 0xed, 0x6d, 0x5f, 0xe5, 0x4a, 0x87, 0xcd, 0xd9, 0xf7, 0x3b, 0x35, 0xbb, 0x18, + 0x62, 0x5a, 0x70, 0xf3, 0xd4, 0x63, 0x05, 0x15, 0x5b, 0xc8, 0xd2, 0x40, 0x19, 0x79, 0x3e, 0xa7, + 0x71, 0x2e, 0x2c, 0xef, 0x4c, 0x1f, 0xb4, 0xcb, 0x80, 0x5c, 0x9c, 0x0d, 0x50, 0xd0, 0x76, 0x90, + 0x5c, 0xf8, 0x26, 0xea, 0x56, 0xa6, 0x98, 0xef, 0x40, 0x7b, 0x14, 0x53, 0x87, 0xd3, 0xb5, 0xb5, + 0xfd, 0xfd, 0x55, 0x8c, 0xe1, 0xd6, 0x1a, 0xd7, 0xb5, 0xed, 0xfd, 0x33, 0x02, 0xed, 0x45, 0x34, + 0xfc, 0x27, 0x37, 0xc3, 0x07, 0xa0, 0x26, 0x92, 0x4b, 0xa6, 0x47, 0x3a, 0x53, 0xed, 0xe9, 0x24, + 0x0b, 0x18, 0x59, 0x04, 0x8c, 0x1c, 0x8b, 0x80, 0x3d, 0x75, 0xd8, 0xd8, 0x86, 0xec, 0xb8, 0xa8, + 0xc5, 0x5a, 0xd6, 0x84, 0x5e, 0xdb, 0x5a, 0xb6, 0x41, 0x7b, 0x4c, 0x7d, 0x5a, 0xb2, 0x95, 0x92, + 0x98, 0xf4, 0xce, 0x9b, 0x00, 0x85, 0x11, 0x71, 0x0a, 0x8d, 0x13, 0xca, 0xf1, 0x83, 0x0a, 0x12, + 0x4a, 0x82, 0xa8, 0x3f, 0xbc, 0x32, 0x2e, 0x5f, 0xc3, 0x07, 0x68, 0x8a, 0x48, 0xe0, 0x2a, 0x5f, + 0x97, 0xd2, 0xb0, 0xe9, 0x7b, 0x1b, 0x20, 0x73, 0xf2, 0x8f, 0xa0, 0x64, 0xae, 0xc5, 0x55, 0x86, + 0x94, 0x87, 0x49, 0xdf, 0xdf, 0x04, 0x5a, 0x08, 0xc8, 0xfc, 0x51, 0x49, 0x40, 0xb9, 0xe7, 0x2b, + 0x09, 0xf8, 0x95, 0x0b, 0x5f, 0x83, 0x92, 0x79, 0xa6, 0x92, 0x80, 0x72, 0x7b, 0xe9, 0xda, 0x5a, + 0x1a, 0x8e, 0xc4, 0xbf, 0xe8, 0xf0, 0xed, 0xec, 0xc2, 0xa8, 0x7d, 0xbb, 0x30, 0x6a, 0x9f, 0xe6, + 0x06, 0x9a, 0xcd, 0x0d, 0xf4, 0x75, 0x6e, 0xa0, 0xf3, 0xb9, 0x81, 0x5e, 0x1d, 0xff, 0xc1, 0x2f, + 0xf4, 0xa0, 0xe8, 0x5e, 0xd6, 0xfa, 0x8a, 0xe4, 0xbc, 0xff, 0x23, 0x00, 0x00, 0xff, 0xff, 0x4f, + 0x4a, 0x87, 0xf3, 0x95, 0x07, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -172,14 +507,15 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Namespaces service - +// NamespacesClient is the client API for Namespaces service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type NamespacesClient interface { Get(ctx context.Context, in *GetNamespaceRequest, opts ...grpc.CallOption) (*GetNamespaceResponse, error) List(ctx context.Context, in *ListNamespacesRequest, opts ...grpc.CallOption) (*ListNamespacesResponse, error) Create(ctx context.Context, in *CreateNamespaceRequest, opts ...grpc.CallOption) (*CreateNamespaceResponse, error) Update(ctx context.Context, in *UpdateNamespaceRequest, opts ...grpc.CallOption) (*UpdateNamespaceResponse, error) - Delete(ctx context.Context, in *DeleteNamespaceRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) + Delete(ctx context.Context, in *DeleteNamespaceRequest, opts ...grpc.CallOption) (*types.Empty, error) } type namespacesClient struct { @@ -192,7 +528,7 @@ func (c *namespacesClient) Get(ctx context.Context, in *GetNamespaceRequest, opts ...grpc.CallOption) (*GetNamespaceResponse, error) { out := new(GetNamespaceResponse) - err := grpc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Get", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Get", in, out, opts...) if err != nil { return nil, err } @@ -201,7 +537,7 @@ func (c *namespacesClient) List(ctx context.Context, in *ListNamespacesRequest, opts ...grpc.CallOption) (*ListNamespacesResponse, error) { out := new(ListNamespacesResponse) - err := grpc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/List", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/List", in, out, opts...) if err != nil { return nil, err } @@ -210,7 +546,7 @@ func (c *namespacesClient) Create(ctx context.Context, in *CreateNamespaceRequest, opts ...grpc.CallOption) (*CreateNamespaceResponse, error) { out := new(CreateNamespaceResponse) - err := grpc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Create", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Create", in, out, opts...) if err != nil { return nil, err } @@ -219,30 +555,49 @@ func (c *namespacesClient) Update(ctx context.Context, in *UpdateNamespaceRequest, opts ...grpc.CallOption) (*UpdateNamespaceResponse, error) { out := new(UpdateNamespaceResponse) - err := grpc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Update", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Update", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *namespacesClient) Delete(ctx context.Context, in *DeleteNamespaceRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) { - out := new(google_protobuf1.Empty) - err := grpc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Delete", in, out, c.cc, opts...) +func (c *namespacesClient) Delete(ctx context.Context, in *DeleteNamespaceRequest, opts ...grpc.CallOption) (*types.Empty, error) { + out := new(types.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.namespaces.v1.Namespaces/Delete", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Namespaces service - +// NamespacesServer is the server API for Namespaces service. type NamespacesServer interface { Get(context.Context, *GetNamespaceRequest) (*GetNamespaceResponse, error) List(context.Context, *ListNamespacesRequest) (*ListNamespacesResponse, error) Create(context.Context, *CreateNamespaceRequest) (*CreateNamespaceResponse, error) Update(context.Context, *UpdateNamespaceRequest) (*UpdateNamespaceResponse, error) - Delete(context.Context, *DeleteNamespaceRequest) (*google_protobuf1.Empty, error) + Delete(context.Context, *DeleteNamespaceRequest) (*types.Empty, error) +} + +// UnimplementedNamespacesServer can be embedded to have forward compatible implementations. +type UnimplementedNamespacesServer struct { +} + +func (*UnimplementedNamespacesServer) Get(ctx context.Context, req *GetNamespaceRequest) (*GetNamespaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") +} +func (*UnimplementedNamespacesServer) List(ctx context.Context, req *ListNamespacesRequest) (*ListNamespacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedNamespacesServer) Create(ctx context.Context, req *CreateNamespaceRequest) (*CreateNamespaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (*UnimplementedNamespacesServer) Update(ctx context.Context, req *UpdateNamespaceRequest) (*UpdateNamespaceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedNamespacesServer) Delete(ctx context.Context, req *DeleteNamespaceRequest) (*types.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func RegisterNamespacesServer(s *grpc.Server, srv NamespacesServer) { @@ -371,7 +726,7 @@ func (m *Namespace) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -379,40 +734,52 @@ } func (m *Namespace) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Namespace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x12 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovNamespace(uint64(len(k))) + 1 + len(v) + sovNamespace(uint64(len(v))) - i = encodeVarintNamespace(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintNamespace(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) i = encodeVarintNamespace(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) + i-- + dAtA[i] = 0xa + i = encodeVarintNamespace(dAtA, i, uint64(baseI-i)) + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintNamespace(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) } } - return i, nil + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *GetNamespaceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -420,23 +787,33 @@ } func (m *GetNamespaceRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetNamespaceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetNamespaceResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -444,25 +821,36 @@ } func (m *GetNamespaceResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetNamespaceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.Namespace.Size())) - n1, err := m.Namespace.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n1 - return i, nil + { + size, err := m.Namespace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ListNamespacesRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -470,23 +858,33 @@ } func (m *ListNamespacesRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListNamespacesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filter) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Filter) + copy(dAtA[i:], m.Filter) i = encodeVarintNamespace(dAtA, i, uint64(len(m.Filter))) - i += copy(dAtA[i:], m.Filter) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListNamespacesResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -494,29 +892,40 @@ } func (m *ListNamespacesResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListNamespacesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Namespaces) > 0 { - for _, msg := range m.Namespaces { - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Namespaces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Namespaces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *CreateNamespaceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -524,25 +933,36 @@ } func (m *CreateNamespaceRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateNamespaceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.Namespace.Size())) - n2, err := m.Namespace.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n2 - return i, nil + { + size, err := m.Namespace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CreateNamespaceResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -550,25 +970,36 @@ } func (m *CreateNamespaceResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateNamespaceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.Namespace.Size())) - n3, err := m.Namespace.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Namespace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) } - i += n3 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateNamespaceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -576,35 +1007,48 @@ } func (m *UpdateNamespaceRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateNamespaceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.Namespace.Size())) - n4, err := m.Namespace.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n4 if m.UpdateMask != nil { + { + size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x12 - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.UpdateMask.Size())) - n5, err := m.UpdateMask.MarshalTo(dAtA[i:]) + } + { + size, err := m.Namespace.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n5 + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) } - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateNamespaceResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -612,25 +1056,36 @@ } func (m *UpdateNamespaceResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateNamespaceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintNamespace(dAtA, i, uint64(m.Namespace.Size())) - n6, err := m.Namespace.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Namespace.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNamespace(dAtA, i, uint64(size)) } - i += n6 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *DeleteNamespaceRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -638,29 +1093,44 @@ } func (m *DeleteNamespaceRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteNamespaceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Name) + copy(dAtA[i:], m.Name) i = encodeVarintNamespace(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintNamespace(dAtA []byte, offset int, v uint64) int { + offset -= sovNamespace(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Namespace) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -675,38 +1145,62 @@ n += mapEntrySize + 1 + sovNamespace(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetNamespaceRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovNamespace(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetNamespaceResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Namespace.Size() n += 1 + l + sovNamespace(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListNamespacesRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Filter) if l > 0 { n += 1 + l + sovNamespace(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListNamespacesResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Namespaces) > 0 { @@ -715,26 +1209,44 @@ n += 1 + l + sovNamespace(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateNamespaceRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Namespace.Size() n += 1 + l + sovNamespace(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateNamespaceResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Namespace.Size() n += 1 + l + sovNamespace(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateNamespaceRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Namespace.Size() @@ -743,36 +1255,44 @@ l = m.UpdateMask.Size() n += 1 + l + sovNamespace(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateNamespaceResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Namespace.Size() n += 1 + l + sovNamespace(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteNamespaceRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) if l > 0 { n += 1 + l + sovNamespace(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovNamespace(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozNamespace(x uint64) (n int) { return sovNamespace(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -785,7 +1305,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -794,6 +1314,7 @@ s := strings.Join([]string{`&Namespace{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -804,6 +1325,7 @@ } s := strings.Join([]string{`&GetNamespaceRequest{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -814,6 +1336,7 @@ } s := strings.Join([]string{`&GetNamespaceResponse{`, `Namespace:` + strings.Replace(strings.Replace(this.Namespace.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -824,6 +1347,7 @@ } s := strings.Join([]string{`&ListNamespacesRequest{`, `Filter:` + fmt.Sprintf("%v", this.Filter) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -832,8 +1356,14 @@ if this == nil { return "nil" } + repeatedStringForNamespaces := "[]Namespace{" + for _, f := range this.Namespaces { + repeatedStringForNamespaces += strings.Replace(strings.Replace(f.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + "," + } + repeatedStringForNamespaces += "}" s := strings.Join([]string{`&ListNamespacesResponse{`, - `Namespaces:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Namespaces), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, + `Namespaces:` + repeatedStringForNamespaces + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -844,6 +1374,7 @@ } s := strings.Join([]string{`&CreateNamespaceRequest{`, `Namespace:` + strings.Replace(strings.Replace(this.Namespace.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -854,6 +1385,7 @@ } s := strings.Join([]string{`&CreateNamespaceResponse{`, `Namespace:` + strings.Replace(strings.Replace(this.Namespace.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -864,7 +1396,8 @@ } s := strings.Join([]string{`&UpdateNamespaceRequest{`, `Namespace:` + strings.Replace(strings.Replace(this.Namespace.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, - `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf2.FieldMask", 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types.FieldMask", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -875,6 +1408,7 @@ } s := strings.Join([]string{`&UpdateNamespaceResponse{`, `Namespace:` + strings.Replace(strings.Replace(this.Namespace.String(), "Namespace", "Namespace", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -885,6 +1419,7 @@ } s := strings.Join([]string{`&DeleteNamespaceRequest{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -912,7 +1447,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -940,7 +1475,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -950,6 +1485,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -969,7 +1507,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -978,6 +1516,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -998,7 +1539,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1015,7 +1556,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1025,6 +1566,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1041,7 +1585,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1051,6 +1595,9 @@ return ErrInvalidLengthNamespace } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthNamespace + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1062,7 +1609,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > postIndex { @@ -1079,12 +1626,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1109,7 +1657,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1137,7 +1685,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1147,6 +1695,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1158,12 +1709,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1188,7 +1740,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1216,7 +1768,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1225,6 +1777,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1238,12 +1793,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1268,7 +1824,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1296,7 +1852,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1306,6 +1862,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1317,12 +1876,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1347,7 +1907,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1375,7 +1935,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1384,6 +1944,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1398,12 +1961,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1428,7 +1992,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1456,7 +2020,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1465,6 +2029,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1478,12 +2045,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1508,7 +2076,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1536,7 +2104,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1545,6 +2113,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1558,12 +2129,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1588,7 +2160,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1616,7 +2188,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1625,6 +2197,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1646,7 +2221,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1655,11 +2230,14 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } if m.UpdateMask == nil { - m.UpdateMask = &google_protobuf2.FieldMask{} + m.UpdateMask = &types.FieldMask{} } if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1671,12 +2249,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1701,7 +2280,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1729,7 +2308,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1738,6 +2317,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1751,12 +2333,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1781,7 +2364,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1809,7 +2392,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1819,6 +2402,9 @@ return ErrInvalidLengthNamespace } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNamespace + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1830,12 +2416,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthNamespace } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1848,6 +2435,7 @@ func skipNamespace(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1879,10 +2467,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1899,96 +2485,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthNamespace } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowNamespace - } - 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 := skipNamespace(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupNamespace + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthNamespace + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthNamespace = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowNamespace = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthNamespace = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowNamespace = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupNamespace = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/namespaces/v1/namespace.proto", fileDescriptorNamespace) -} - -var fileDescriptorNamespace = []byte{ - // 551 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0xcd, 0x24, 0xf9, 0x2c, 0xe5, 0x7a, 0xf3, 0x69, 0x08, 0x26, 0x32, 0x92, 0x09, 0x5e, 0x15, - 0xa9, 0x1a, 0xab, 0x41, 0x82, 0xfe, 0xec, 0x0a, 0x6d, 0x17, 0x14, 0x84, 0x2c, 0x21, 0x21, 0x58, - 0x80, 0x93, 0x4c, 0x5c, 0x13, 0xc7, 0x36, 0x9e, 0xb1, 0xa5, 0x88, 0x05, 0xbc, 0x0d, 0x1b, 0x1e, - 0x24, 0x4b, 0x96, 0xac, 0x50, 0x9b, 0x27, 0x41, 0x33, 0x76, 0xe2, 0xd0, 0x18, 0xe1, 0x06, 0xca, - 0xee, 0x5e, 0x7b, 0xce, 0x3d, 0x67, 0xae, 0xce, 0xb1, 0xe1, 0x89, 0xeb, 0xf1, 0xb3, 0xa4, 0x4f, - 0x06, 0xe1, 0xc4, 0x1a, 0x84, 0x01, 0x77, 0xbc, 0x80, 0xc6, 0xc3, 0xd5, 0xd2, 0x89, 0x3c, 0x8b, - 0xd1, 0x38, 0xf5, 0x06, 0x94, 0x59, 0x81, 0x33, 0xa1, 0x2c, 0x72, 0x44, 0x99, 0xee, 0x14, 0x1d, - 0x89, 0xe2, 0x90, 0x87, 0xf8, 0x6e, 0x01, 0x23, 0x0b, 0x08, 0x29, 0x20, 0x24, 0xdd, 0xd1, 0xdb, - 0x6e, 0xe8, 0x86, 0xf2, 0xb4, 0x25, 0xaa, 0x0c, 0xa8, 0xdf, 0x76, 0xc3, 0xd0, 0xf5, 0xa9, 0x25, - 0xbb, 0x7e, 0x32, 0xb2, 0xe8, 0x24, 0xe2, 0xd3, 0xfc, 0x65, 0xf7, 0xf2, 0xcb, 0x91, 0x47, 0xfd, - 0xe1, 0x9b, 0x89, 0xc3, 0xc6, 0xd9, 0x09, 0xf3, 0x0b, 0x82, 0xd6, 0xb3, 0x05, 0x0d, 0xc6, 0xd0, - 0x14, 0x9c, 0x1d, 0xd4, 0x45, 0x5b, 0x2d, 0x5b, 0xd6, 0xf8, 0x39, 0x28, 0xbe, 0xd3, 0xa7, 0x3e, - 0xeb, 0xd4, 0xbb, 0x8d, 0x2d, 0xb5, 0xb7, 0x4b, 0x7e, 0x2b, 0x95, 0x2c, 0x27, 0x92, 0x53, 0x09, - 0x3d, 0x0a, 0x78, 0x3c, 0xb5, 0xf3, 0x39, 0xfa, 0x1e, 0xa8, 0x2b, 0x8f, 0xf1, 0xff, 0xd0, 0x18, - 0xd3, 0x69, 0xce, 0x29, 0x4a, 0xdc, 0x86, 0xff, 0x52, 0xc7, 0x4f, 0x68, 0xa7, 0x2e, 0x9f, 0x65, - 0xcd, 0x7e, 0x7d, 0x17, 0x99, 0xf7, 0xe0, 0xc6, 0x09, 0xe5, 0xcb, 0xf1, 0x36, 0x7d, 0x9f, 0x50, - 0xc6, 0xcb, 0x74, 0x9b, 0x67, 0xd0, 0xfe, 0xf9, 0x28, 0x8b, 0xc2, 0x80, 0x89, 0xfb, 0xb4, 0x96, - 0x62, 0x25, 0x40, 0xed, 0x6d, 0x5f, 0xe5, 0x4a, 0x87, 0xcd, 0xd9, 0xf7, 0x3b, 0x35, 0xbb, 0x18, - 0x62, 0x5a, 0x70, 0xf3, 0xd4, 0x63, 0x05, 0x15, 0x5b, 0xc8, 0xd2, 0x40, 0x19, 0x79, 0x3e, 0xa7, - 0x71, 0x2e, 0x2c, 0xef, 0x4c, 0x1f, 0xb4, 0xcb, 0x80, 0x5c, 0x9c, 0x0d, 0x50, 0xd0, 0x76, 0x90, - 0x5c, 0xf8, 0x26, 0xea, 0x56, 0xa6, 0x98, 0xef, 0x40, 0x7b, 0x14, 0x53, 0x87, 0xd3, 0xb5, 0xb5, - 0xfd, 0xfd, 0x55, 0x8c, 0xe1, 0xd6, 0x1a, 0xd7, 0xb5, 0xed, 0xfd, 0x33, 0x02, 0xed, 0x45, 0x34, - 0xfc, 0x27, 0x37, 0xc3, 0x07, 0xa0, 0x26, 0x92, 0x4b, 0xa6, 0x47, 0x3a, 0x53, 0xed, 0xe9, 0x24, - 0x0b, 0x18, 0x59, 0x04, 0x8c, 0x1c, 0x8b, 0x80, 0x3d, 0x75, 0xd8, 0xd8, 0x86, 0xec, 0xb8, 0xa8, - 0xc5, 0x5a, 0xd6, 0x84, 0x5e, 0xdb, 0x5a, 0xb6, 0x41, 0x7b, 0x4c, 0x7d, 0x5a, 0xb2, 0x95, 0x92, - 0x98, 0xf4, 0xce, 0x9b, 0x00, 0x85, 0x11, 0x71, 0x0a, 0x8d, 0x13, 0xca, 0xf1, 0x83, 0x0a, 0x12, - 0x4a, 0x82, 0xa8, 0x3f, 0xbc, 0x32, 0x2e, 0x5f, 0xc3, 0x07, 0x68, 0x8a, 0x48, 0xe0, 0x2a, 0x5f, - 0x97, 0xd2, 0xb0, 0xe9, 0x7b, 0x1b, 0x20, 0x73, 0xf2, 0x8f, 0xa0, 0x64, 0xae, 0xc5, 0x55, 0x86, - 0x94, 0x87, 0x49, 0xdf, 0xdf, 0x04, 0x5a, 0x08, 0xc8, 0xfc, 0x51, 0x49, 0x40, 0xb9, 0xe7, 0x2b, - 0x09, 0xf8, 0x95, 0x0b, 0x5f, 0x83, 0x92, 0x79, 0xa6, 0x92, 0x80, 0x72, 0x7b, 0xe9, 0xda, 0x5a, - 0x1a, 0x8e, 0xc4, 0xbf, 0xe8, 0xf0, 0xed, 0xec, 0xc2, 0xa8, 0x7d, 0xbb, 0x30, 0x6a, 0x9f, 0xe6, - 0x06, 0x9a, 0xcd, 0x0d, 0xf4, 0x75, 0x6e, 0xa0, 0xf3, 0xb9, 0x81, 0x5e, 0x1d, 0xff, 0xc1, 0x2f, - 0xf4, 0xa0, 0xe8, 0x5e, 0xd6, 0xfa, 0x8a, 0xe4, 0xbc, 0xff, 0x23, 0x00, 0x00, 0xff, 0xff, 0x4f, - 0x4a, 0x87, 0xf3, 0x95, 0x07, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/namespaces/v1/namespace.proto containerd-1.5.9/api/services/namespaces/v1/namespace.proto --- containerd-1.2.6/api/services/namespaces/v1/namespace.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/namespaces/v1/namespace.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.namespaces.v1; diff -Nru containerd-1.2.6/api/services/snapshots/v1/snapshots.pb.go containerd-1.5.9/api/services/snapshots/v1/snapshots.pb.go --- containerd-1.2.6/api/services/snapshots/v1/snapshots.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/snapshots/v1/snapshots.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,55 +1,26 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto -/* - Package snapshots is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto - - It has these top-level messages: - PrepareSnapshotRequest - PrepareSnapshotResponse - ViewSnapshotRequest - ViewSnapshotResponse - MountsRequest - MountsResponse - RemoveSnapshotRequest - CommitSnapshotRequest - StatSnapshotRequest - Info - StatSnapshotResponse - UpdateSnapshotRequest - UpdateSnapshotResponse - ListSnapshotsRequest - ListSnapshotsResponse - UsageRequest - UsageResponse -*/ package snapshots -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" -import containerd_types "github.com/containerd/containerd/api/types" - -import time "time" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" -import sortkeys "github.com/gogo/protobuf/sortkeys" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types1 "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -61,7 +32,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Kind int32 @@ -78,6 +49,7 @@ 2: "ACTIVE", 3: "COMMITTED", } + var Kind_value = map[string]int32{ "UNKNOWN": 0, "VIEW": 1, @@ -88,7 +60,10 @@ func (x Kind) String() string { return proto.EnumName(Kind_name, int32(x)) } -func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{0} } + +func (Kind) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{0} +} type PrepareSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` @@ -97,20 +72,82 @@ // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PrepareSnapshotRequest) Reset() { *m = PrepareSnapshotRequest{} } +func (*PrepareSnapshotRequest) ProtoMessage() {} +func (*PrepareSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{0} +} +func (m *PrepareSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PrepareSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PrepareSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PrepareSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PrepareSnapshotRequest.Merge(m, src) +} +func (m *PrepareSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *PrepareSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PrepareSnapshotRequest.DiscardUnknown(m) } -func (m *PrepareSnapshotRequest) Reset() { *m = PrepareSnapshotRequest{} } -func (*PrepareSnapshotRequest) ProtoMessage() {} -func (*PrepareSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{0} } +var xxx_messageInfo_PrepareSnapshotRequest proto.InternalMessageInfo type PrepareSnapshotResponse struct { - Mounts []*containerd_types.Mount `protobuf:"bytes,1,rep,name=mounts" json:"mounts,omitempty"` + Mounts []*types.Mount `protobuf:"bytes,1,rep,name=mounts,proto3" json:"mounts,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PrepareSnapshotResponse) Reset() { *m = PrepareSnapshotResponse{} } +func (*PrepareSnapshotResponse) ProtoMessage() {} +func (*PrepareSnapshotResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{1} +} +func (m *PrepareSnapshotResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PrepareSnapshotResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PrepareSnapshotResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PrepareSnapshotResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PrepareSnapshotResponse.Merge(m, src) +} +func (m *PrepareSnapshotResponse) XXX_Size() int { + return m.Size() +} +func (m *PrepareSnapshotResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PrepareSnapshotResponse.DiscardUnknown(m) } -func (m *PrepareSnapshotResponse) Reset() { *m = PrepareSnapshotResponse{} } -func (*PrepareSnapshotResponse) ProtoMessage() {} -func (*PrepareSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{1} } +var xxx_messageInfo_PrepareSnapshotResponse proto.InternalMessageInfo type ViewSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` @@ -119,46 +156,201 @@ // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ViewSnapshotRequest) Reset() { *m = ViewSnapshotRequest{} } +func (*ViewSnapshotRequest) ProtoMessage() {} +func (*ViewSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{2} +} +func (m *ViewSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ViewSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ViewSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ViewSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ViewSnapshotRequest.Merge(m, src) +} +func (m *ViewSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *ViewSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ViewSnapshotRequest.DiscardUnknown(m) } -func (m *ViewSnapshotRequest) Reset() { *m = ViewSnapshotRequest{} } -func (*ViewSnapshotRequest) ProtoMessage() {} -func (*ViewSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{2} } +var xxx_messageInfo_ViewSnapshotRequest proto.InternalMessageInfo type ViewSnapshotResponse struct { - Mounts []*containerd_types.Mount `protobuf:"bytes,1,rep,name=mounts" json:"mounts,omitempty"` + Mounts []*types.Mount `protobuf:"bytes,1,rep,name=mounts,proto3" json:"mounts,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ViewSnapshotResponse) Reset() { *m = ViewSnapshotResponse{} } +func (*ViewSnapshotResponse) ProtoMessage() {} +func (*ViewSnapshotResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{3} +} +func (m *ViewSnapshotResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ViewSnapshotResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ViewSnapshotResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ViewSnapshotResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ViewSnapshotResponse.Merge(m, src) +} +func (m *ViewSnapshotResponse) XXX_Size() int { + return m.Size() +} +func (m *ViewSnapshotResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ViewSnapshotResponse.DiscardUnknown(m) } -func (m *ViewSnapshotResponse) Reset() { *m = ViewSnapshotResponse{} } -func (*ViewSnapshotResponse) ProtoMessage() {} -func (*ViewSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{3} } +var xxx_messageInfo_ViewSnapshotResponse proto.InternalMessageInfo type MountsRequest struct { - Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MountsRequest) Reset() { *m = MountsRequest{} } +func (*MountsRequest) ProtoMessage() {} +func (*MountsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{4} +} +func (m *MountsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MountsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MountsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MountsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_MountsRequest.Merge(m, src) +} +func (m *MountsRequest) XXX_Size() int { + return m.Size() +} +func (m *MountsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_MountsRequest.DiscardUnknown(m) } -func (m *MountsRequest) Reset() { *m = MountsRequest{} } -func (*MountsRequest) ProtoMessage() {} -func (*MountsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{4} } +var xxx_messageInfo_MountsRequest proto.InternalMessageInfo type MountsResponse struct { - Mounts []*containerd_types.Mount `protobuf:"bytes,1,rep,name=mounts" json:"mounts,omitempty"` + Mounts []*types.Mount `protobuf:"bytes,1,rep,name=mounts,proto3" json:"mounts,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MountsResponse) Reset() { *m = MountsResponse{} } +func (*MountsResponse) ProtoMessage() {} +func (*MountsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{5} +} +func (m *MountsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MountsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MountsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MountsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MountsResponse.Merge(m, src) +} +func (m *MountsResponse) XXX_Size() int { + return m.Size() +} +func (m *MountsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MountsResponse.DiscardUnknown(m) } -func (m *MountsResponse) Reset() { *m = MountsResponse{} } -func (*MountsResponse) ProtoMessage() {} -func (*MountsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{5} } +var xxx_messageInfo_MountsResponse proto.InternalMessageInfo type RemoveSnapshotRequest struct { - Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RemoveSnapshotRequest) Reset() { *m = RemoveSnapshotRequest{} } +func (*RemoveSnapshotRequest) ProtoMessage() {} +func (*RemoveSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{6} +} +func (m *RemoveSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RemoveSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RemoveSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RemoveSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RemoveSnapshotRequest.Merge(m, src) +} +func (m *RemoveSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *RemoveSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RemoveSnapshotRequest.DiscardUnknown(m) } -func (m *RemoveSnapshotRequest) Reset() { *m = RemoveSnapshotRequest{} } -func (*RemoveSnapshotRequest) ProtoMessage() {} -func (*RemoveSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{6} } +var xxx_messageInfo_RemoveSnapshotRequest proto.InternalMessageInfo type CommitSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` @@ -167,117 +359,482 @@ // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommitSnapshotRequest) Reset() { *m = CommitSnapshotRequest{} } +func (*CommitSnapshotRequest) ProtoMessage() {} +func (*CommitSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{7} +} +func (m *CommitSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CommitSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CommitSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CommitSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommitSnapshotRequest.Merge(m, src) +} +func (m *CommitSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *CommitSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CommitSnapshotRequest.DiscardUnknown(m) } -func (m *CommitSnapshotRequest) Reset() { *m = CommitSnapshotRequest{} } -func (*CommitSnapshotRequest) ProtoMessage() {} -func (*CommitSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{7} } +var xxx_messageInfo_CommitSnapshotRequest proto.InternalMessageInfo type StatSnapshotRequest struct { - Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatSnapshotRequest) Reset() { *m = StatSnapshotRequest{} } +func (*StatSnapshotRequest) ProtoMessage() {} +func (*StatSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{8} +} +func (m *StatSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatSnapshotRequest.Merge(m, src) +} +func (m *StatSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *StatSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StatSnapshotRequest.DiscardUnknown(m) } -func (m *StatSnapshotRequest) Reset() { *m = StatSnapshotRequest{} } -func (*StatSnapshotRequest) ProtoMessage() {} -func (*StatSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{8} } +var xxx_messageInfo_StatSnapshotRequest proto.InternalMessageInfo type Info struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` Kind Kind `protobuf:"varint,3,opt,name=kind,proto3,enum=containerd.services.snapshots.v1.Kind" json:"kind,omitempty"` // CreatedAt provides the time at which the snapshot was created. - CreatedAt time.Time `protobuf:"bytes,4,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + CreatedAt time.Time `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3,stdtime" json:"created_at"` // UpdatedAt provides the time the info was last updated. - UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3,stdtime" json:"updated_at"` // Labels are arbitrary data on snapshots. // // The combined size of a key/value pair cannot exceed 4096 bytes. - Labels map[string]string `protobuf:"bytes,6,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Labels map[string]string `protobuf:"bytes,6,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Info) Reset() { *m = Info{} } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{9} +} +func (m *Info) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Info.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Info) XXX_Merge(src proto.Message) { + xxx_messageInfo_Info.Merge(m, src) +} +func (m *Info) XXX_Size() int { + return m.Size() +} +func (m *Info) XXX_DiscardUnknown() { + xxx_messageInfo_Info.DiscardUnknown(m) } -func (m *Info) Reset() { *m = Info{} } -func (*Info) ProtoMessage() {} -func (*Info) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{9} } +var xxx_messageInfo_Info proto.InternalMessageInfo type StatSnapshotResponse struct { - Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatSnapshotResponse) Reset() { *m = StatSnapshotResponse{} } +func (*StatSnapshotResponse) ProtoMessage() {} +func (*StatSnapshotResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{10} +} +func (m *StatSnapshotResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatSnapshotResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatSnapshotResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatSnapshotResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatSnapshotResponse.Merge(m, src) +} +func (m *StatSnapshotResponse) XXX_Size() int { + return m.Size() +} +func (m *StatSnapshotResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatSnapshotResponse.DiscardUnknown(m) } -func (m *StatSnapshotResponse) Reset() { *m = StatSnapshotResponse{} } -func (*StatSnapshotResponse) ProtoMessage() {} -func (*StatSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{10} } +var xxx_messageInfo_StatSnapshotResponse proto.InternalMessageInfo type UpdateSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` - Info Info `protobuf:"bytes,2,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,2,opt,name=info,proto3" json:"info"` // UpdateMask specifies which fields to perform the update on. If empty, // the operation applies to all fields. // // In info, Name, Parent, Kind, Created are immutable, // other field may be updated using this mask. // If no mask is provided, all mutable field are updated. - UpdateMask *google_protobuf2.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` + UpdateMask *types1.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateSnapshotRequest) Reset() { *m = UpdateSnapshotRequest{} } +func (*UpdateSnapshotRequest) ProtoMessage() {} +func (*UpdateSnapshotRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{11} +} +func (m *UpdateSnapshotRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateSnapshotRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateSnapshotRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateSnapshotRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateSnapshotRequest.Merge(m, src) +} +func (m *UpdateSnapshotRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateSnapshotRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateSnapshotRequest.DiscardUnknown(m) } -func (m *UpdateSnapshotRequest) Reset() { *m = UpdateSnapshotRequest{} } -func (*UpdateSnapshotRequest) ProtoMessage() {} -func (*UpdateSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{11} } +var xxx_messageInfo_UpdateSnapshotRequest proto.InternalMessageInfo type UpdateSnapshotResponse struct { - Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` + Info Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateSnapshotResponse) Reset() { *m = UpdateSnapshotResponse{} } +func (*UpdateSnapshotResponse) ProtoMessage() {} +func (*UpdateSnapshotResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{12} +} +func (m *UpdateSnapshotResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateSnapshotResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateSnapshotResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateSnapshotResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateSnapshotResponse.Merge(m, src) +} +func (m *UpdateSnapshotResponse) XXX_Size() int { + return m.Size() +} +func (m *UpdateSnapshotResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateSnapshotResponse.DiscardUnknown(m) } -func (m *UpdateSnapshotResponse) Reset() { *m = UpdateSnapshotResponse{} } -func (*UpdateSnapshotResponse) ProtoMessage() {} -func (*UpdateSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{12} } +var xxx_messageInfo_UpdateSnapshotResponse proto.InternalMessageInfo type ListSnapshotsRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + // Filters contains one or more filters using the syntax defined in the + // containerd filter package. + // + // The returned result will be those that match any of the provided + // filters. Expanded, images that match the following will be + // returned: + // + // filters[0] or filters[1] or ... or filters[n-1] or filters[n] + // + // If filters is zero-length or nil, all items will be returned. + Filters []string `protobuf:"bytes,2,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListSnapshotsRequest) Reset() { *m = ListSnapshotsRequest{} } +func (*ListSnapshotsRequest) ProtoMessage() {} +func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{13} +} +func (m *ListSnapshotsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListSnapshotsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListSnapshotsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListSnapshotsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListSnapshotsRequest.Merge(m, src) +} +func (m *ListSnapshotsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListSnapshotsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListSnapshotsRequest.DiscardUnknown(m) } -func (m *ListSnapshotsRequest) Reset() { *m = ListSnapshotsRequest{} } -func (*ListSnapshotsRequest) ProtoMessage() {} -func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{13} } +var xxx_messageInfo_ListSnapshotsRequest proto.InternalMessageInfo type ListSnapshotsResponse struct { - Info []Info `protobuf:"bytes,1,rep,name=info" json:"info"` + Info []Info `protobuf:"bytes,1,rep,name=info,proto3" json:"info"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListSnapshotsResponse) Reset() { *m = ListSnapshotsResponse{} } +func (*ListSnapshotsResponse) ProtoMessage() {} +func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{14} +} +func (m *ListSnapshotsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListSnapshotsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListSnapshotsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListSnapshotsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListSnapshotsResponse.Merge(m, src) +} +func (m *ListSnapshotsResponse) XXX_Size() int { + return m.Size() +} +func (m *ListSnapshotsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListSnapshotsResponse.DiscardUnknown(m) } -func (m *ListSnapshotsResponse) Reset() { *m = ListSnapshotsResponse{} } -func (*ListSnapshotsResponse) ProtoMessage() {} -func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{14} } +var xxx_messageInfo_ListSnapshotsResponse proto.InternalMessageInfo type UsageRequest struct { - Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UsageRequest) Reset() { *m = UsageRequest{} } +func (*UsageRequest) ProtoMessage() {} +func (*UsageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{15} +} +func (m *UsageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UsageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UsageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UsageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UsageRequest.Merge(m, src) +} +func (m *UsageRequest) XXX_Size() int { + return m.Size() +} +func (m *UsageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UsageRequest.DiscardUnknown(m) } -func (m *UsageRequest) Reset() { *m = UsageRequest{} } -func (*UsageRequest) ProtoMessage() {} -func (*UsageRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{15} } +var xxx_messageInfo_UsageRequest proto.InternalMessageInfo type UsageResponse struct { - Size_ int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` - Inodes int64 `protobuf:"varint,2,opt,name=inodes,proto3" json:"inodes,omitempty"` + Size_ int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` + Inodes int64 `protobuf:"varint,2,opt,name=inodes,proto3" json:"inodes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UsageResponse) Reset() { *m = UsageResponse{} } +func (*UsageResponse) ProtoMessage() {} +func (*UsageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{16} +} +func (m *UsageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UsageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UsageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UsageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UsageResponse.Merge(m, src) +} +func (m *UsageResponse) XXX_Size() int { + return m.Size() +} +func (m *UsageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UsageResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_UsageResponse proto.InternalMessageInfo + +type CleanupRequest struct { + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *UsageResponse) Reset() { *m = UsageResponse{} } -func (*UsageResponse) ProtoMessage() {} -func (*UsageResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{16} } +func (m *CleanupRequest) Reset() { *m = CleanupRequest{} } +func (*CleanupRequest) ProtoMessage() {} +func (*CleanupRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cfc0ddf12791f168, []int{17} +} +func (m *CleanupRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CleanupRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CleanupRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CleanupRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CleanupRequest.Merge(m, src) +} +func (m *CleanupRequest) XXX_Size() int { + return m.Size() +} +func (m *CleanupRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CleanupRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CleanupRequest proto.InternalMessageInfo func init() { + proto.RegisterEnum("containerd.services.snapshots.v1.Kind", Kind_name, Kind_value) proto.RegisterType((*PrepareSnapshotRequest)(nil), "containerd.services.snapshots.v1.PrepareSnapshotRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.snapshots.v1.PrepareSnapshotRequest.LabelsEntry") proto.RegisterType((*PrepareSnapshotResponse)(nil), "containerd.services.snapshots.v1.PrepareSnapshotResponse") proto.RegisterType((*ViewSnapshotRequest)(nil), "containerd.services.snapshots.v1.ViewSnapshotRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.snapshots.v1.ViewSnapshotRequest.LabelsEntry") proto.RegisterType((*ViewSnapshotResponse)(nil), "containerd.services.snapshots.v1.ViewSnapshotResponse") proto.RegisterType((*MountsRequest)(nil), "containerd.services.snapshots.v1.MountsRequest") proto.RegisterType((*MountsResponse)(nil), "containerd.services.snapshots.v1.MountsResponse") proto.RegisterType((*RemoveSnapshotRequest)(nil), "containerd.services.snapshots.v1.RemoveSnapshotRequest") proto.RegisterType((*CommitSnapshotRequest)(nil), "containerd.services.snapshots.v1.CommitSnapshotRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.snapshots.v1.CommitSnapshotRequest.LabelsEntry") proto.RegisterType((*StatSnapshotRequest)(nil), "containerd.services.snapshots.v1.StatSnapshotRequest") proto.RegisterType((*Info)(nil), "containerd.services.snapshots.v1.Info") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.snapshots.v1.Info.LabelsEntry") proto.RegisterType((*StatSnapshotResponse)(nil), "containerd.services.snapshots.v1.StatSnapshotResponse") proto.RegisterType((*UpdateSnapshotRequest)(nil), "containerd.services.snapshots.v1.UpdateSnapshotRequest") proto.RegisterType((*UpdateSnapshotResponse)(nil), "containerd.services.snapshots.v1.UpdateSnapshotResponse") @@ -285,7 +842,81 @@ proto.RegisterType((*ListSnapshotsResponse)(nil), "containerd.services.snapshots.v1.ListSnapshotsResponse") proto.RegisterType((*UsageRequest)(nil), "containerd.services.snapshots.v1.UsageRequest") proto.RegisterType((*UsageResponse)(nil), "containerd.services.snapshots.v1.UsageResponse") - proto.RegisterEnum("containerd.services.snapshots.v1.Kind", Kind_name, Kind_value) + proto.RegisterType((*CleanupRequest)(nil), "containerd.services.snapshots.v1.CleanupRequest") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto", fileDescriptor_cfc0ddf12791f168) +} + +var fileDescriptor_cfc0ddf12791f168 = []byte{ + // 1047 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0xda, 0x5b, 0x27, 0x79, 0x4e, 0x82, 0x99, 0x3a, 0xae, 0xb5, 0x20, 0x67, 0xe5, 0x03, + 0x8a, 0x38, 0xec, 0xb6, 0x46, 0xb4, 0x69, 0x73, 0xc1, 0x71, 0x0c, 0x72, 0xd2, 0xa4, 0x68, 0xf3, + 0xa7, 0x4d, 0x41, 0x54, 0x1b, 0x7b, 0xec, 0xac, 0xec, 0xfd, 0x83, 0x67, 0xec, 0xca, 0x20, 0x21, + 0x8e, 0x55, 0x4e, 0x7c, 0x81, 0x9c, 0xe0, 0x43, 0x20, 0x3e, 0x41, 0x8e, 0x48, 0x5c, 0x38, 0x01, + 0xcd, 0x97, 0xe0, 0x84, 0x40, 0x33, 0x3b, 0xeb, 0x7f, 0x71, 0xe5, 0xb5, 0x6b, 0x6e, 0x33, 0x3b, + 0xf3, 0xde, 0xfb, 0xbd, 0xdf, 0x9b, 0xf7, 0x9b, 0x59, 0xd8, 0xad, 0x5b, 0xf4, 0xbc, 0x7d, 0xa6, + 0x55, 0x5c, 0x5b, 0xaf, 0xb8, 0x0e, 0x35, 0x2d, 0x07, 0xb7, 0xaa, 0x83, 0x43, 0xd3, 0xb3, 0x74, + 0x82, 0x5b, 0x1d, 0xab, 0x82, 0x89, 0x4e, 0x1c, 0xd3, 0x23, 0xe7, 0x2e, 0x25, 0x7a, 0xe7, 0x5e, + 0x7f, 0xa2, 0x79, 0x2d, 0x97, 0xba, 0x48, 0xed, 0x5b, 0x69, 0x81, 0x85, 0xd6, 0xdf, 0xd4, 0xb9, + 0xa7, 0xa4, 0xea, 0x6e, 0xdd, 0xe5, 0x9b, 0x75, 0x36, 0xf2, 0xed, 0x94, 0xf7, 0xea, 0xae, 0x5b, + 0x6f, 0x62, 0x9d, 0xcf, 0xce, 0xda, 0x35, 0x1d, 0xdb, 0x1e, 0xed, 0x8a, 0x45, 0x75, 0x74, 0xb1, + 0x66, 0xe1, 0x66, 0xf5, 0x85, 0x6d, 0x92, 0x86, 0xd8, 0xb1, 0x3e, 0xba, 0x83, 0x5a, 0x36, 0x26, + 0xd4, 0xb4, 0x3d, 0xb1, 0xe1, 0x7e, 0xa8, 0x1c, 0x69, 0xd7, 0xc3, 0x44, 0xb7, 0xdd, 0xb6, 0x43, + 0x7d, 0xbb, 0xdc, 0x3f, 0x12, 0xa4, 0x3f, 0x6f, 0x61, 0xcf, 0x6c, 0xe1, 0x43, 0x91, 0x85, 0x81, + 0xbf, 0x6e, 0x63, 0x42, 0x91, 0x0a, 0x89, 0x20, 0x31, 0x8a, 0x5b, 0x19, 0x49, 0x95, 0x36, 0x96, + 0x8c, 0xc1, 0x4f, 0x28, 0x09, 0xb1, 0x06, 0xee, 0x66, 0xa2, 0x7c, 0x85, 0x0d, 0x51, 0x1a, 0xe2, + 0xcc, 0x95, 0x43, 0x33, 0x31, 0xfe, 0x51, 0xcc, 0xd0, 0x97, 0x10, 0x6f, 0x9a, 0x67, 0xb8, 0x49, + 0x32, 0xb2, 0x1a, 0xdb, 0x48, 0xe4, 0x77, 0xb4, 0x49, 0x3c, 0x6a, 0xe3, 0x51, 0x69, 0x8f, 0xb9, + 0x9b, 0x92, 0x43, 0x5b, 0x5d, 0x43, 0xf8, 0x54, 0x1e, 0x42, 0x62, 0xe0, 0x73, 0x00, 0x4b, 0xea, + 0xc3, 0x4a, 0xc1, 0xad, 0x8e, 0xd9, 0x6c, 0x63, 0x01, 0xd5, 0x9f, 0x3c, 0x8a, 0x6e, 0x4a, 0xb9, + 0x5d, 0xb8, 0x73, 0x23, 0x10, 0xf1, 0x5c, 0x87, 0x60, 0xa4, 0x43, 0x9c, 0x33, 0x45, 0x32, 0x12, + 0xc7, 0x7c, 0x67, 0x10, 0x33, 0x67, 0x52, 0xdb, 0x67, 0xeb, 0x86, 0xd8, 0x96, 0xfb, 0x5b, 0x82, + 0xdb, 0x27, 0x16, 0x7e, 0xf9, 0x7f, 0x12, 0x79, 0x3a, 0x42, 0x64, 0x61, 0x32, 0x91, 0x63, 0x20, + 0xcd, 0x9b, 0xc5, 0xcf, 0x20, 0x35, 0x1c, 0x65, 0x56, 0x0a, 0x8b, 0xb0, 0xc2, 0x3f, 0x90, 0xb7, + 0xe0, 0x2e, 0x57, 0x80, 0xd5, 0xc0, 0xc9, 0xac, 0x38, 0xf6, 0x60, 0xcd, 0xc0, 0xb6, 0xdb, 0x99, + 0x47, 0x53, 0xb0, 0x73, 0xb1, 0x56, 0x74, 0x6d, 0xdb, 0xa2, 0xd3, 0x7b, 0x43, 0x20, 0x3b, 0xa6, + 0x1d, 0x50, 0xce, 0xc7, 0x41, 0x84, 0x58, 0xbf, 0x32, 0x5f, 0x8c, 0x9c, 0x8a, 0xe2, 0xe4, 0x53, + 0x31, 0x16, 0xd0, 0xbc, 0xcf, 0x45, 0x19, 0x6e, 0x1f, 0x52, 0x93, 0xce, 0x83, 0xc4, 0x7f, 0xa3, + 0x20, 0x97, 0x9d, 0x9a, 0xdb, 0x63, 0x44, 0x1a, 0x60, 0xa4, 0xdf, 0x2d, 0xd1, 0xa1, 0x6e, 0x79, + 0x04, 0x72, 0xc3, 0x72, 0xaa, 0x9c, 0xaa, 0xd5, 0xfc, 0x07, 0x93, 0x59, 0xd9, 0xb3, 0x9c, 0xaa, + 0xc1, 0x6d, 0x50, 0x11, 0xa0, 0xd2, 0xc2, 0x26, 0xc5, 0xd5, 0x17, 0x26, 0xcd, 0xc8, 0xaa, 0xb4, + 0x91, 0xc8, 0x2b, 0x9a, 0xaf, 0xc3, 0x5a, 0xa0, 0xc3, 0xda, 0x51, 0xa0, 0xc3, 0xdb, 0x8b, 0x57, + 0x7f, 0xac, 0x47, 0x7e, 0xf8, 0x73, 0x5d, 0x32, 0x96, 0x84, 0x5d, 0x81, 0x32, 0x27, 0x6d, 0xaf, + 0x1a, 0x38, 0xb9, 0x35, 0x8d, 0x13, 0x61, 0x57, 0xa0, 0x68, 0xb7, 0x57, 0xdd, 0x38, 0xaf, 0x6e, + 0x7e, 0x72, 0x1e, 0x8c, 0xa9, 0x79, 0x17, 0xf3, 0x19, 0xa4, 0x86, 0x8b, 0x29, 0x9a, 0xeb, 0x13, + 0x90, 0x2d, 0xa7, 0xe6, 0x72, 0x27, 0x89, 0x30, 0x24, 0x33, 0x70, 0xdb, 0x32, 0xcb, 0xd4, 0xe0, + 0x96, 0xb9, 0x9f, 0x25, 0x58, 0x3b, 0xe6, 0xe9, 0x4e, 0x7f, 0x52, 0x82, 0xe8, 0xd1, 0x59, 0xa3, + 0xa3, 0x2d, 0x48, 0xf8, 0x5c, 0xf3, 0x0b, 0x97, 0x9f, 0x95, 0x71, 0x45, 0xfa, 0x94, 0xdd, 0xc9, + 0xfb, 0x26, 0x69, 0x18, 0xa2, 0xa4, 0x6c, 0x9c, 0x7b, 0x0e, 0xe9, 0x51, 0xe4, 0x73, 0xa3, 0xc5, + 0x80, 0xd4, 0x63, 0x8b, 0xf4, 0x08, 0x9f, 0x42, 0x13, 0x33, 0xb0, 0x50, 0xb3, 0x9a, 0x14, 0xb7, + 0x48, 0x26, 0xaa, 0xc6, 0x36, 0x96, 0x8c, 0x60, 0x9a, 0x3b, 0x85, 0xb5, 0x11, 0x9f, 0x37, 0xe0, + 0xc6, 0x66, 0x84, 0xbb, 0x0d, 0xcb, 0xc7, 0xc4, 0xac, 0xe3, 0xb7, 0xe9, 0xf2, 0x2d, 0x58, 0x11, + 0x3e, 0x04, 0x2c, 0x04, 0x32, 0xb1, 0xbe, 0xf1, 0xbb, 0x3d, 0x66, 0xf0, 0x31, 0xeb, 0x76, 0xcb, + 0x71, 0xab, 0x98, 0x70, 0xcb, 0x98, 0x21, 0x66, 0xb9, 0x3c, 0xac, 0x16, 0x9b, 0xd8, 0x74, 0xda, + 0x5e, 0x68, 0x08, 0x1f, 0xbe, 0x92, 0x40, 0x66, 0x4d, 0x8f, 0xde, 0x87, 0x85, 0xe3, 0x83, 0xbd, + 0x83, 0x27, 0x4f, 0x0f, 0x92, 0x11, 0xe5, 0x9d, 0x8b, 0x4b, 0x35, 0xc1, 0x3e, 0x1f, 0x3b, 0x0d, + 0xc7, 0x7d, 0xe9, 0xa0, 0x34, 0xc8, 0x27, 0xe5, 0xd2, 0xd3, 0xa4, 0xa4, 0x2c, 0x5f, 0x5c, 0xaa, + 0x8b, 0x6c, 0x89, 0x5d, 0x78, 0x48, 0x81, 0x78, 0xa1, 0x78, 0x54, 0x3e, 0x29, 0x25, 0xa3, 0xca, + 0xea, 0xc5, 0xa5, 0x0a, 0x6c, 0xa5, 0x50, 0xa1, 0x56, 0x07, 0x23, 0x15, 0x96, 0x8a, 0x4f, 0xf6, + 0xf7, 0xcb, 0x47, 0x47, 0xa5, 0x9d, 0x64, 0x4c, 0x79, 0xf7, 0xe2, 0x52, 0x5d, 0x61, 0xcb, 0xbe, + 0xf2, 0x52, 0x5c, 0x55, 0x96, 0x5f, 0xfd, 0x98, 0x8d, 0xfc, 0xf2, 0x53, 0x96, 0x23, 0xc8, 0xff, + 0xb6, 0x08, 0x4b, 0xbd, 0xba, 0xa0, 0xef, 0x60, 0x41, 0x3c, 0x4c, 0xd0, 0xe6, 0xac, 0x8f, 0x25, + 0xe5, 0xe1, 0x0c, 0x96, 0x82, 0xf8, 0x36, 0xc8, 0x3c, 0xc3, 0x8f, 0x67, 0x7a, 0x60, 0x28, 0xf7, + 0xa7, 0x35, 0x13, 0x61, 0x1b, 0x10, 0xf7, 0xef, 0x6e, 0xa4, 0x4f, 0xf6, 0x30, 0xf4, 0x54, 0x50, + 0xee, 0x86, 0x37, 0x10, 0xc1, 0x4e, 0x21, 0xee, 0x17, 0x03, 0x3d, 0x98, 0xf1, 0xc2, 0x54, 0xd2, + 0x37, 0x74, 0xa2, 0xc4, 0x1e, 0xf6, 0xcc, 0xb5, 0xff, 0x80, 0x08, 0xe3, 0x7a, 0xec, 0x53, 0xe3, + 0x8d, 0xae, 0xdb, 0x20, 0x33, 0x1d, 0x0e, 0x53, 0x99, 0x31, 0x97, 0x6f, 0x98, 0xca, 0x8c, 0x95, + 0xf9, 0x6f, 0x21, 0xee, 0x2b, 0x5d, 0x98, 0x8c, 0xc6, 0xaa, 0xb9, 0xb2, 0x39, 0xbd, 0xa1, 0x08, + 0xde, 0x05, 0x99, 0xc9, 0x16, 0x0a, 0x01, 0x7e, 0x9c, 0x64, 0x2a, 0x0f, 0xa6, 0xb6, 0xf3, 0x03, + 0xdf, 0x95, 0xd0, 0x39, 0xdc, 0xe2, 0x92, 0x84, 0xb4, 0x10, 0xe8, 0x07, 0xf4, 0x4f, 0xd1, 0x43, + 0xef, 0x17, 0x49, 0x1e, 0xc2, 0x82, 0xd0, 0x2f, 0x14, 0xe2, 0x2c, 0x0f, 0x4b, 0xdd, 0x9b, 0x4e, + 0xcb, 0xf6, 0x57, 0x57, 0xaf, 0xb3, 0x91, 0xdf, 0x5f, 0x67, 0x23, 0xdf, 0x5f, 0x67, 0xa5, 0xab, + 0xeb, 0xac, 0xf4, 0xeb, 0x75, 0x56, 0xfa, 0xeb, 0x3a, 0x2b, 0x3d, 0xdf, 0x99, 0xfd, 0xb7, 0x78, + 0xab, 0x37, 0x79, 0x16, 0x39, 0x8b, 0xf3, 0x88, 0x1f, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0x20, + 0x9c, 0x85, 0x7f, 0x67, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -296,18 +927,20 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Snapshots service - +// SnapshotsClient is the client API for Snapshots service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type SnapshotsClient interface { Prepare(ctx context.Context, in *PrepareSnapshotRequest, opts ...grpc.CallOption) (*PrepareSnapshotResponse, error) View(ctx context.Context, in *ViewSnapshotRequest, opts ...grpc.CallOption) (*ViewSnapshotResponse, error) Mounts(ctx context.Context, in *MountsRequest, opts ...grpc.CallOption) (*MountsResponse, error) - Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) - Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) + Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*types1.Empty, error) + Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*types1.Empty, error) Stat(ctx context.Context, in *StatSnapshotRequest, opts ...grpc.CallOption) (*StatSnapshotResponse, error) Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) Usage(ctx context.Context, in *UsageRequest, opts ...grpc.CallOption) (*UsageResponse, error) + Cleanup(ctx context.Context, in *CleanupRequest, opts ...grpc.CallOption) (*types1.Empty, error) } type snapshotsClient struct { @@ -320,7 +953,7 @@ func (c *snapshotsClient) Prepare(ctx context.Context, in *PrepareSnapshotRequest, opts ...grpc.CallOption) (*PrepareSnapshotResponse, error) { out := new(PrepareSnapshotResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Prepare", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Prepare", in, out, opts...) if err != nil { return nil, err } @@ -329,7 +962,7 @@ func (c *snapshotsClient) View(ctx context.Context, in *ViewSnapshotRequest, opts ...grpc.CallOption) (*ViewSnapshotResponse, error) { out := new(ViewSnapshotResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/View", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/View", in, out, opts...) if err != nil { return nil, err } @@ -338,25 +971,25 @@ func (c *snapshotsClient) Mounts(ctx context.Context, in *MountsRequest, opts ...grpc.CallOption) (*MountsResponse, error) { out := new(MountsResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Mounts", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Mounts", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *snapshotsClient) Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) { - out := new(google_protobuf1.Empty) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Commit", in, out, c.cc, opts...) +func (c *snapshotsClient) Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Commit", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *snapshotsClient) Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) { - out := new(google_protobuf1.Empty) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Remove", in, out, c.cc, opts...) +func (c *snapshotsClient) Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Remove", in, out, opts...) if err != nil { return nil, err } @@ -365,7 +998,7 @@ func (c *snapshotsClient) Stat(ctx context.Context, in *StatSnapshotRequest, opts ...grpc.CallOption) (*StatSnapshotResponse, error) { out := new(StatSnapshotResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Stat", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Stat", in, out, opts...) if err != nil { return nil, err } @@ -374,7 +1007,7 @@ func (c *snapshotsClient) Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) { out := new(UpdateSnapshotResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Update", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Update", in, out, opts...) if err != nil { return nil, err } @@ -382,7 +1015,7 @@ } func (c *snapshotsClient) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Snapshots_serviceDesc.Streams[0], c.cc, "/containerd.services.snapshots.v1.Snapshots/List", opts...) + stream, err := c.cc.NewStream(ctx, &_Snapshots_serviceDesc.Streams[0], "/containerd.services.snapshots.v1.Snapshots/List", opts...) if err != nil { return nil, err } @@ -415,25 +1048,69 @@ func (c *snapshotsClient) Usage(ctx context.Context, in *UsageRequest, opts ...grpc.CallOption) (*UsageResponse, error) { out := new(UsageResponse) - err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Usage", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Usage", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Snapshots service +func (c *snapshotsClient) Cleanup(ctx context.Context, in *CleanupRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Cleanup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} +// SnapshotsServer is the server API for Snapshots service. type SnapshotsServer interface { Prepare(context.Context, *PrepareSnapshotRequest) (*PrepareSnapshotResponse, error) View(context.Context, *ViewSnapshotRequest) (*ViewSnapshotResponse, error) Mounts(context.Context, *MountsRequest) (*MountsResponse, error) - Commit(context.Context, *CommitSnapshotRequest) (*google_protobuf1.Empty, error) - Remove(context.Context, *RemoveSnapshotRequest) (*google_protobuf1.Empty, error) + Commit(context.Context, *CommitSnapshotRequest) (*types1.Empty, error) + Remove(context.Context, *RemoveSnapshotRequest) (*types1.Empty, error) Stat(context.Context, *StatSnapshotRequest) (*StatSnapshotResponse, error) Update(context.Context, *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) List(*ListSnapshotsRequest, Snapshots_ListServer) error Usage(context.Context, *UsageRequest) (*UsageResponse, error) + Cleanup(context.Context, *CleanupRequest) (*types1.Empty, error) +} + +// UnimplementedSnapshotsServer can be embedded to have forward compatible implementations. +type UnimplementedSnapshotsServer struct { +} + +func (*UnimplementedSnapshotsServer) Prepare(ctx context.Context, req *PrepareSnapshotRequest) (*PrepareSnapshotResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Prepare not implemented") +} +func (*UnimplementedSnapshotsServer) View(ctx context.Context, req *ViewSnapshotRequest) (*ViewSnapshotResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method View not implemented") +} +func (*UnimplementedSnapshotsServer) Mounts(ctx context.Context, req *MountsRequest) (*MountsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mounts not implemented") +} +func (*UnimplementedSnapshotsServer) Commit(ctx context.Context, req *CommitSnapshotRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Commit not implemented") +} +func (*UnimplementedSnapshotsServer) Remove(ctx context.Context, req *RemoveSnapshotRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Remove not implemented") +} +func (*UnimplementedSnapshotsServer) Stat(ctx context.Context, req *StatSnapshotRequest) (*StatSnapshotResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Stat not implemented") +} +func (*UnimplementedSnapshotsServer) Update(ctx context.Context, req *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedSnapshotsServer) List(req *ListSnapshotsRequest, srv Snapshots_ListServer) error { + return status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedSnapshotsServer) Usage(ctx context.Context, req *UsageRequest) (*UsageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Usage not implemented") +} +func (*UnimplementedSnapshotsServer) Cleanup(ctx context.Context, req *CleanupRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Cleanup not implemented") } func RegisterSnapshotsServer(s *grpc.Server, srv SnapshotsServer) { @@ -605,6 +1282,24 @@ return interceptor(ctx, in, info, handler) } +func _Snapshots_Cleanup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CleanupRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SnapshotsServer).Cleanup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.snapshots.v1.Snapshots/Cleanup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SnapshotsServer).Cleanup(ctx, req.(*CleanupRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Snapshots_serviceDesc = grpc.ServiceDesc{ ServiceName: "containerd.services.snapshots.v1.Snapshots", HandlerType: (*SnapshotsServer)(nil), @@ -641,6 +1336,10 @@ MethodName: "Usage", Handler: _Snapshots_Usage_Handler, }, + { + MethodName: "Cleanup", + Handler: _Snapshots_Cleanup_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -655,7 +1354,7 @@ func (m *PrepareSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -663,52 +1362,66 @@ } func (m *PrepareSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrepareSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) - } - if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) - } - if len(m.Parent) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x22 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) - i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintSnapshots(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 } } - return i, nil + if len(m.Parent) > 0 { + i -= len(m.Parent) + copy(dAtA[i:], m.Parent) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *PrepareSnapshotResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -716,29 +1429,40 @@ } func (m *PrepareSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrepareSnapshotResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Mounts) > 0 { - for _, msg := range m.Mounts { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Mounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Mounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *ViewSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -746,82 +1470,107 @@ } func (m *ViewSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ViewSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) - } - if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) - } - if len(m.Parent) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x22 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) - i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintSnapshots(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 } } - return i, nil -} - -func (m *ViewSnapshotResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err + if len(m.Parent) > 0 { + i -= len(m.Parent) + copy(dAtA[i:], m.Parent) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ViewSnapshotResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } return dAtA[:n], nil } func (m *ViewSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ViewSnapshotResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Mounts) > 0 { - for _, msg := range m.Mounts { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Mounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Mounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *MountsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -829,29 +1578,40 @@ } func (m *MountsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MountsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Key) + copy(dAtA[i:], m.Key) i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *MountsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -859,29 +1619,40 @@ } func (m *MountsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MountsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Mounts) > 0 { - for _, msg := range m.Mounts { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Mounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Mounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *RemoveSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -889,29 +1660,40 @@ } func (m *RemoveSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RemoveSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Key) + copy(dAtA[i:], m.Key) i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i-- + dAtA[i] = 0x12 + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CommitSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -919,52 +1701,66 @@ } func (m *CommitSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CommitSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) - } - if len(m.Name) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) - } - if len(m.Key) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x22 - i++ + for k := range m.Labels { v := m.Labels[k] - mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) - i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ + baseI := i + i -= len(v) + copy(dAtA[i:], v) i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintSnapshots(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 } } - return i, nil + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *StatSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -972,29 +1768,40 @@ } func (m *StatSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Key) + copy(dAtA[i:], m.Key) i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *Info) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1002,67 +1809,80 @@ } func (m *Info) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Info) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Name) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Name))) - i += copy(dAtA[i:], m.Name) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Parent) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) + if len(m.Labels) > 0 { + for k := range m.Labels { + v := m.Labels[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintSnapshots(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x32 + } } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintSnapshots(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x2a + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintSnapshots(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x22 if m.Kind != 0 { - dAtA[i] = 0x18 - i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Kind)) + i-- + dAtA[i] = 0x18 } - dAtA[i] = 0x22 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt))) - n1, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - dAtA[i] = 0x2a - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(types.SizeOfStdTime(m.UpdatedAt))) - n2, err := types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.Parent) > 0 { + i -= len(m.Parent) + copy(dAtA[i:], m.Parent) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) + i-- + dAtA[i] = 0x12 } - i += n2 - if len(m.Labels) > 0 { - for k, _ := range m.Labels { - dAtA[i] = 0x32 - i++ - v := m.Labels[k] - mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) - i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) - i += copy(dAtA[i:], k) - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) - i += copy(dAtA[i:], v) - } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StatSnapshotResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1070,25 +1890,36 @@ } func (m *StatSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatSnapshotResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) - n3, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) } - i += n3 - return i, nil + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *UpdateSnapshotRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1096,41 +1927,55 @@ } func (m *UpdateSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateSnapshotRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - dAtA[i] = 0x12 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) - n4, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n4 if m.UpdateMask != nil { + { + size, err := m.UpdateMask.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x1a - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(m.UpdateMask.Size())) - n5, err := m.UpdateMask.MarshalTo(dAtA[i:]) + } + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n5 + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *UpdateSnapshotResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1138,25 +1983,36 @@ } func (m *UpdateSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateSnapshotResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) - n6, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - i += n6 - return i, nil + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ListSnapshotsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1164,23 +2020,42 @@ } func (m *ListSnapshotsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListSnapshotsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Filters) > 0 { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListSnapshotsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1188,29 +2063,40 @@ } func (m *ListSnapshotsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListSnapshotsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Info) > 0 { - for _, msg := range m.Info { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Info) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Info[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSnapshots(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *UsageRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1218,29 +2104,40 @@ } func (m *UsageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UsageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Snapshotter) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) - i += copy(dAtA[i:], m.Snapshotter) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Key) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Key) + copy(dAtA[i:], m.Key) i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) - i += copy(dAtA[i:], m.Key) + i-- + dAtA[i] = 0x12 + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *UsageResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1248,33 +2145,81 @@ } func (m *UsageResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UsageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Size_ != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintSnapshots(dAtA, i, uint64(m.Size_)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Inodes != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Inodes)) + i-- + dAtA[i] = 0x10 + } + if m.Size_ != 0 { + i = encodeVarintSnapshots(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil +} + +func (m *CleanupRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CleanupRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CleanupRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Snapshotter) > 0 { + i -= len(m.Snapshotter) + copy(dAtA[i:], m.Snapshotter) + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func encodeVarintSnapshots(dAtA []byte, offset int, v uint64) int { + offset -= sovSnapshots(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *PrepareSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1297,10 +2242,16 @@ n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PrepareSnapshotResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Mounts) > 0 { @@ -1309,10 +2260,16 @@ n += 1 + l + sovSnapshots(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ViewSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1335,10 +2292,16 @@ n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ViewSnapshotResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Mounts) > 0 { @@ -1347,10 +2310,16 @@ n += 1 + l + sovSnapshots(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *MountsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1361,10 +2330,16 @@ if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *MountsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Mounts) > 0 { @@ -1373,10 +2348,16 @@ n += 1 + l + sovSnapshots(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *RemoveSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1387,10 +2368,16 @@ if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CommitSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1413,10 +2400,16 @@ n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1427,10 +2420,16 @@ if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *Info) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Name) @@ -1444,9 +2443,9 @@ if m.Kind != 0 { n += 1 + sovSnapshots(uint64(m.Kind)) } - l = types.SizeOfStdTime(m.CreatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) n += 1 + l + sovSnapshots(uint64(l)) - l = types.SizeOfStdTime(m.UpdatedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) n += 1 + l + sovSnapshots(uint64(l)) if len(m.Labels) > 0 { for k, v := range m.Labels { @@ -1456,18 +2455,30 @@ n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatSnapshotResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Info.Size() n += 1 + l + sovSnapshots(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateSnapshotRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1480,28 +2491,52 @@ l = m.UpdateMask.Size() n += 1 + l + sovSnapshots(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateSnapshotResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = m.Info.Size() n += 1 + l + sovSnapshots(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListSnapshotsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Filters) > 0 { + for _, s := range m.Filters { + l = len(s) + n += 1 + l + sovSnapshots(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListSnapshotsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Info) > 0 { @@ -1510,10 +2545,16 @@ n += 1 + l + sovSnapshots(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UsageRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Snapshotter) @@ -1524,10 +2565,16 @@ if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UsageResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Size_ != 0 { @@ -1536,18 +2583,30 @@ if m.Inodes != 0 { n += 1 + sovSnapshots(uint64(m.Inodes)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CleanupRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Snapshotter) + if l > 0 { + n += 1 + l + sovSnapshots(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovSnapshots(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozSnapshots(x uint64) (n int) { return sovSnapshots(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1560,7 +2619,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1571,6 +2630,7 @@ `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1579,8 +2639,14 @@ if this == nil { return "nil" } + repeatedStringForMounts := "[]*Mount{" + for _, f := range this.Mounts { + repeatedStringForMounts += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForMounts += "}" s := strings.Join([]string{`&PrepareSnapshotResponse{`, - `Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "containerd_types.Mount", 1) + `,`, + `Mounts:` + repeatedStringForMounts + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1593,7 +2659,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1604,6 +2670,7 @@ `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1612,8 +2679,14 @@ if this == nil { return "nil" } + repeatedStringForMounts := "[]*Mount{" + for _, f := range this.Mounts { + repeatedStringForMounts += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForMounts += "}" s := strings.Join([]string{`&ViewSnapshotResponse{`, - `Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "containerd_types.Mount", 1) + `,`, + `Mounts:` + repeatedStringForMounts + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1625,6 +2698,7 @@ s := strings.Join([]string{`&MountsRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1633,8 +2707,14 @@ if this == nil { return "nil" } + repeatedStringForMounts := "[]*Mount{" + for _, f := range this.Mounts { + repeatedStringForMounts += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForMounts += "}" s := strings.Join([]string{`&MountsResponse{`, - `Mounts:` + strings.Replace(fmt.Sprintf("%v", this.Mounts), "Mount", "containerd_types.Mount", 1) + `,`, + `Mounts:` + repeatedStringForMounts + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1646,6 +2726,7 @@ s := strings.Join([]string{`&RemoveSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1658,7 +2739,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1669,6 +2750,7 @@ `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1680,6 +2762,7 @@ s := strings.Join([]string{`&StatSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1692,7 +2775,7 @@ for k, _ := range this.Labels { keysForLabels = append(keysForLabels, k) } - sortkeys.Strings(keysForLabels) + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) mapStringForLabels := "map[string]string{" for _, k := range keysForLabels { mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) @@ -1702,9 +2785,10 @@ `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, - `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, - `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CreatedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.UpdatedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, `Labels:` + mapStringForLabels + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1715,6 +2799,7 @@ } s := strings.Join([]string{`&StatSnapshotResponse{`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1726,7 +2811,8 @@ s := strings.Join([]string{`&UpdateSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, - `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf2.FieldMask", 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "types1.FieldMask", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1737,6 +2823,7 @@ } s := strings.Join([]string{`&UpdateSnapshotResponse{`, `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1747,6 +2834,8 @@ } s := strings.Join([]string{`&ListSnapshotsRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, + `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1755,8 +2844,14 @@ if this == nil { return "nil" } + repeatedStringForInfo := "[]Info{" + for _, f := range this.Info { + repeatedStringForInfo += strings.Replace(strings.Replace(f.String(), "Info", "Info", 1), `&`, ``, 1) + "," + } + repeatedStringForInfo += "}" s := strings.Join([]string{`&ListSnapshotsResponse{`, - `Info:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Info), "Info", "Info", 1), `&`, ``, 1) + `,`, + `Info:` + repeatedStringForInfo + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1768,6 +2863,7 @@ s := strings.Join([]string{`&UsageRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1779,6 +2875,18 @@ s := strings.Join([]string{`&UsageResponse{`, `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, `Inodes:` + fmt.Sprintf("%v", this.Inodes) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CleanupRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CleanupRequest{`, + `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1806,7 +2914,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1834,7 +2942,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1844,6 +2952,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1863,7 +2974,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1873,6 +2984,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1892,7 +3006,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1902,6 +3016,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1921,7 +3038,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1930,6 +3047,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1950,7 +3070,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1967,7 +3087,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1977,6 +3097,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1993,7 +3116,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2003,6 +3126,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -2014,7 +3140,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > postIndex { @@ -2031,12 +3157,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2061,7 +3188,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2089,7 +3216,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2098,10 +3225,13 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Mounts = append(m.Mounts, &containerd_types.Mount{}) + m.Mounts = append(m.Mounts, &types.Mount{}) if err := m.Mounts[len(m.Mounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2112,12 +3242,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2142,7 +3273,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2170,7 +3301,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2180,6 +3311,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2199,7 +3333,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2209,6 +3343,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2228,7 +3365,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2238,6 +3375,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2257,7 +3397,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2266,6 +3406,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2286,7 +3429,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2303,7 +3446,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2313,6 +3456,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -2329,7 +3475,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2339,6 +3485,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -2350,7 +3499,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > postIndex { @@ -2367,12 +3516,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2397,7 +3547,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2425,7 +3575,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2434,10 +3584,13 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Mounts = append(m.Mounts, &containerd_types.Mount{}) + m.Mounts = append(m.Mounts, &types.Mount{}) if err := m.Mounts[len(m.Mounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2448,12 +3601,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2478,7 +3632,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2506,7 +3660,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2516,6 +3670,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2535,7 +3692,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2545,6 +3702,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2556,12 +3716,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2586,7 +3747,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2614,7 +3775,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2623,10 +3784,13 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Mounts = append(m.Mounts, &containerd_types.Mount{}) + m.Mounts = append(m.Mounts, &types.Mount{}) if err := m.Mounts[len(m.Mounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2637,12 +3801,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2667,7 +3832,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2695,7 +3860,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2705,6 +3870,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2724,7 +3892,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2734,6 +3902,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2745,12 +3916,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2775,7 +3947,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2803,7 +3975,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2813,6 +3985,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2832,7 +4007,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2842,6 +4017,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2861,7 +4039,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2871,6 +4049,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2890,7 +4071,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2899,6 +4080,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2919,7 +4103,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2936,7 +4120,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2946,6 +4130,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -2962,7 +4149,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2972,6 +4159,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -2983,7 +4173,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > postIndex { @@ -3000,12 +4190,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3030,7 +4221,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3058,7 +4249,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3068,6 +4259,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3087,7 +4281,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3097,6 +4291,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3108,12 +4305,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3138,7 +4336,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3166,7 +4364,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3176,6 +4374,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3195,7 +4396,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3205,6 +4406,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3224,7 +4428,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Kind |= (Kind(b) & 0x7F) << shift + m.Kind |= Kind(b&0x7F) << shift if b < 0x80 { break } @@ -3243,7 +4447,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3252,10 +4456,13 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3273,7 +4480,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3282,10 +4489,13 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3303,7 +4513,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3312,6 +4522,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3332,7 +4545,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3349,7 +4562,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= (uint64(b) & 0x7F) << shift + stringLenmapkey |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3359,6 +4572,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -3375,7 +4591,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= (uint64(b) & 0x7F) << shift + stringLenmapvalue |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3385,6 +4601,9 @@ return ErrInvalidLengthSnapshots } postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthSnapshots + } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -3396,7 +4615,7 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > postIndex { @@ -3413,12 +4632,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3443,7 +4663,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3471,7 +4691,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3480,6 +4700,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3493,12 +4716,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3523,7 +4747,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3551,7 +4775,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3561,6 +4785,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3580,7 +4807,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3589,6 +4816,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3610,7 +4840,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3619,11 +4849,14 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } if m.UpdateMask == nil { - m.UpdateMask = &google_protobuf2.FieldMask{} + m.UpdateMask = &types1.FieldMask{} } if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3635,12 +4868,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3665,7 +4899,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3693,7 +4927,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3702,6 +4936,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3715,12 +4952,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3745,7 +4983,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3773,7 +5011,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3783,23 +5021,59 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } m.Snapshotter = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3824,7 +5098,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3852,7 +5126,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3861,6 +5135,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3875,12 +5152,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3905,7 +5183,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3933,7 +5211,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3943,6 +5221,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3962,7 +5243,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3972,6 +5253,9 @@ return ErrInvalidLengthSnapshots } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3983,12 +5267,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4013,7 +5298,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4041,7 +5326,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift + m.Size_ |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -4060,23 +5345,107 @@ } b := dAtA[iNdEx] iNdEx++ - m.Inodes |= (int64(b) & 0x7F) << shift + m.Inodes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSnapshots(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSnapshots + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CleanupRequest) 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 ErrIntOverflowSnapshots + } + 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: CleanupRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CleanupRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Snapshotter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + 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 ErrInvalidLengthSnapshots + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSnapshots + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Snapshotter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthSnapshots } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4089,6 +5458,7 @@ func skipSnapshots(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -4120,10 +5490,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -4140,124 +5508,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthSnapshots } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSnapshots - } - 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 := skipSnapshots(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSnapshots + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthSnapshots + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthSnapshots = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowSnapshots = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthSnapshots = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSnapshots = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSnapshots = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto", fileDescriptorSnapshots) -} - -var fileDescriptorSnapshots = []byte{ - // 1007 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1a, 0x47, - 0x14, 0x67, 0x60, 0x8d, 0xe3, 0x87, 0xed, 0xd2, 0x09, 0x26, 0x68, 0x5b, 0xe1, 0x15, 0x87, 0xca, - 0xea, 0x61, 0x37, 0xa1, 0x6a, 0xe2, 0xc4, 0x97, 0x62, 0x4c, 0x2b, 0xec, 0xd8, 0xa9, 0x36, 0xb6, - 0x13, 0xa7, 0x55, 0xa3, 0x35, 0x8c, 0xf1, 0x0a, 0x76, 0x97, 0x32, 0x03, 0x11, 0xad, 0x54, 0xf5, - 0x18, 0xf9, 0xd4, 0x2f, 0xe0, 0x53, 0xfb, 0x21, 0xaa, 0x7e, 0x02, 0x1f, 0x7b, 0xec, 0xa9, 0x6d, - 0xfc, 0x25, 0x7a, 0xea, 0x1f, 0xcd, 0xec, 0x2c, 0x60, 0x4c, 0xc5, 0x82, 0xc9, 0x6d, 0x66, 0x67, - 0x7e, 0xef, 0xfd, 0xe6, 0xf7, 0xe6, 0xbd, 0x37, 0x0b, 0xdb, 0x35, 0x9b, 0x9d, 0xb6, 0x8f, 0xf5, - 0x8a, 0xe7, 0x18, 0x15, 0xcf, 0x65, 0x96, 0xed, 0x92, 0x56, 0x75, 0x70, 0x68, 0x35, 0x6d, 0x83, - 0x92, 0x56, 0xc7, 0xae, 0x10, 0x6a, 0x50, 0xd7, 0x6a, 0xd2, 0x53, 0x8f, 0x51, 0xa3, 0x73, 0xaf, - 0x3f, 0xd1, 0x9b, 0x2d, 0x8f, 0x79, 0x58, 0xeb, 0xa3, 0xf4, 0x00, 0xa1, 0xf7, 0x37, 0x75, 0xee, - 0xa9, 0xa9, 0x9a, 0x57, 0xf3, 0xc4, 0x66, 0x83, 0x8f, 0x7c, 0x9c, 0xfa, 0x5e, 0xcd, 0xf3, 0x6a, - 0x0d, 0x62, 0x88, 0xd9, 0x71, 0xfb, 0xc4, 0x20, 0x4e, 0x93, 0x75, 0xe5, 0xa2, 0x36, 0xbc, 0x78, - 0x62, 0x93, 0x46, 0xf5, 0xa5, 0x63, 0xd1, 0xba, 0xdc, 0xb1, 0x3a, 0xbc, 0x83, 0xd9, 0x0e, 0xa1, - 0xcc, 0x72, 0x9a, 0x72, 0xc3, 0xfd, 0x50, 0x67, 0x64, 0xdd, 0x26, 0xa1, 0x86, 0xe3, 0xb5, 0x5d, - 0xe6, 0xe3, 0x72, 0x7f, 0x23, 0x48, 0x7f, 0xde, 0x22, 0x4d, 0xab, 0x45, 0x9e, 0xca, 0x53, 0x98, - 0xe4, 0xeb, 0x36, 0xa1, 0x0c, 0x6b, 0x90, 0x08, 0x0e, 0xc6, 0x48, 0x2b, 0x83, 0x34, 0xb4, 0xb6, - 0x60, 0x0e, 0x7e, 0xc2, 0x49, 0x88, 0xd5, 0x49, 0x37, 0x13, 0x15, 0x2b, 0x7c, 0x88, 0xd3, 0x10, - 0xe7, 0xa6, 0x5c, 0x96, 0x89, 0x89, 0x8f, 0x72, 0x86, 0xbf, 0x84, 0x78, 0xc3, 0x3a, 0x26, 0x0d, - 0x9a, 0x51, 0xb4, 0xd8, 0x5a, 0x22, 0xbf, 0xa5, 0x8f, 0xd3, 0x51, 0x1f, 0xcd, 0x4a, 0x7f, 0x2c, - 0xcc, 0x94, 0x5c, 0xd6, 0xea, 0x9a, 0xd2, 0xa6, 0xfa, 0x10, 0x12, 0x03, 0x9f, 0x03, 0x5a, 0xa8, - 0x4f, 0x2b, 0x05, 0x73, 0x1d, 0xab, 0xd1, 0x26, 0x92, 0xaa, 0x3f, 0x79, 0x14, 0x5d, 0x47, 0xb9, - 0x6d, 0xb8, 0x73, 0xcd, 0x11, 0x6d, 0x7a, 0x2e, 0x25, 0xd8, 0x80, 0xb8, 0x50, 0x8a, 0x66, 0x90, - 0xe0, 0x7c, 0x67, 0x90, 0xb3, 0x50, 0x52, 0xdf, 0xe5, 0xeb, 0xa6, 0xdc, 0x96, 0xfb, 0x0b, 0xc1, - 0xed, 0x43, 0x9b, 0xbc, 0x7a, 0x9b, 0x42, 0x1e, 0x0d, 0x09, 0x59, 0x18, 0x2f, 0xe4, 0x08, 0x4a, - 0xb3, 0x56, 0xf1, 0x33, 0x48, 0x5d, 0xf5, 0x32, 0xad, 0x84, 0x45, 0x58, 0x12, 0x1f, 0xe8, 0x0d, - 0xb4, 0xcb, 0x15, 0x60, 0x39, 0x30, 0x32, 0x2d, 0x8f, 0x1d, 0x58, 0x31, 0x89, 0xe3, 0x75, 0x66, - 0x91, 0x14, 0xfc, 0x5e, 0xac, 0x14, 0x3d, 0xc7, 0xb1, 0xd9, 0xe4, 0xd6, 0x30, 0x28, 0xae, 0xe5, - 0x04, 0x92, 0x8b, 0x71, 0xe0, 0x21, 0xd6, 0x8f, 0xcc, 0x17, 0x43, 0xb7, 0xa2, 0x38, 0xfe, 0x56, - 0x8c, 0x24, 0x34, 0xeb, 0x7b, 0x51, 0x86, 0xdb, 0x4f, 0x99, 0xc5, 0x66, 0x21, 0xe2, 0xbf, 0x51, - 0x50, 0xca, 0xee, 0x89, 0xd7, 0x53, 0x04, 0x0d, 0x28, 0xd2, 0xcf, 0x96, 0xe8, 0x95, 0x6c, 0x79, - 0x04, 0x4a, 0xdd, 0x76, 0xab, 0x42, 0xaa, 0xe5, 0xfc, 0x07, 0xe3, 0x55, 0xd9, 0xb1, 0xdd, 0xaa, - 0x29, 0x30, 0xb8, 0x08, 0x50, 0x69, 0x11, 0x8b, 0x91, 0xea, 0x4b, 0x8b, 0x65, 0x14, 0x0d, 0xad, - 0x25, 0xf2, 0xaa, 0xee, 0xd7, 0x61, 0x3d, 0xa8, 0xc3, 0xfa, 0x7e, 0x50, 0x87, 0x37, 0x6f, 0x5d, - 0xfc, 0xbe, 0x1a, 0xf9, 0xe1, 0x8f, 0x55, 0x64, 0x2e, 0x48, 0x5c, 0x81, 0x71, 0x23, 0xed, 0x66, - 0x35, 0x30, 0x32, 0x37, 0x89, 0x11, 0x89, 0x2b, 0x30, 0xbc, 0xdd, 0x8b, 0x6e, 0x5c, 0x44, 0x37, - 0x3f, 0xfe, 0x1c, 0x5c, 0xa9, 0x59, 0x07, 0xf3, 0x39, 0xa4, 0xae, 0x06, 0x53, 0x26, 0xd7, 0x27, - 0xa0, 0xd8, 0xee, 0x89, 0x27, 0x8c, 0x24, 0xc2, 0x88, 0xcc, 0xc9, 0x6d, 0x2a, 0xfc, 0xa4, 0xa6, - 0x40, 0xe6, 0x7e, 0x46, 0xb0, 0x72, 0x20, 0x8e, 0x3b, 0xf9, 0x4d, 0x09, 0xbc, 0x47, 0xa7, 0xf5, - 0x8e, 0x37, 0x20, 0xe1, 0x6b, 0x2d, 0x1a, 0xae, 0xb8, 0x2b, 0xa3, 0x82, 0xf4, 0x29, 0xef, 0xc9, - 0xbb, 0x16, 0xad, 0x9b, 0x32, 0xa4, 0x7c, 0x9c, 0x7b, 0x01, 0xe9, 0x61, 0xe6, 0x33, 0x93, 0x65, - 0x1d, 0x52, 0x8f, 0x6d, 0xda, 0x13, 0x3c, 0x7c, 0x4d, 0xcc, 0x1d, 0xc1, 0xca, 0x10, 0xf2, 0x1a, - 0xa9, 0xd8, 0x94, 0xa4, 0x36, 0x61, 0xf1, 0x80, 0x5a, 0x35, 0x72, 0x93, 0x5c, 0xde, 0x80, 0x25, - 0x69, 0x43, 0xd2, 0xc2, 0xa0, 0x50, 0xfb, 0x1b, 0x3f, 0xa7, 0x63, 0xa6, 0x18, 0xf3, 0x9c, 0xb6, - 0x5d, 0xaf, 0x4a, 0xa8, 0x40, 0xc6, 0x4c, 0x39, 0xfb, 0xf0, 0x35, 0x02, 0x85, 0xa7, 0x29, 0x7e, - 0x1f, 0xe6, 0x0f, 0xf6, 0x76, 0xf6, 0x9e, 0x3c, 0xdb, 0x4b, 0x46, 0xd4, 0x77, 0xce, 0xce, 0xb5, - 0x04, 0xff, 0x7c, 0xe0, 0xd6, 0x5d, 0xef, 0x95, 0x8b, 0xd3, 0xa0, 0x1c, 0x96, 0x4b, 0xcf, 0x92, - 0x48, 0x5d, 0x3c, 0x3b, 0xd7, 0x6e, 0xf1, 0x25, 0xde, 0xa2, 0xb0, 0x0a, 0xf1, 0x42, 0x71, 0xbf, - 0x7c, 0x58, 0x4a, 0x46, 0xd5, 0xe5, 0xb3, 0x73, 0x0d, 0xf8, 0x4a, 0xa1, 0xc2, 0xec, 0x0e, 0xc1, - 0x1a, 0x2c, 0x14, 0x9f, 0xec, 0xee, 0x96, 0xf7, 0xf7, 0x4b, 0x5b, 0xc9, 0x98, 0xfa, 0xee, 0xd9, - 0xb9, 0xb6, 0xc4, 0x97, 0xfd, 0x5a, 0xc9, 0x48, 0x55, 0x5d, 0x7c, 0xfd, 0x63, 0x36, 0xf2, 0xcb, - 0x4f, 0x59, 0xc1, 0x20, 0xff, 0xcf, 0x3c, 0x2c, 0xf4, 0x34, 0xc6, 0xdf, 0xc1, 0xbc, 0x7c, 0x4a, - 0xe0, 0xf5, 0x69, 0x9f, 0x37, 0xea, 0xc3, 0x29, 0x90, 0x52, 0xc4, 0x36, 0x28, 0xe2, 0x84, 0x1f, - 0x4f, 0xf5, 0x24, 0x50, 0xef, 0x4f, 0x0a, 0x93, 0x6e, 0xeb, 0x10, 0xf7, 0xbb, 0x2d, 0x36, 0xc6, - 0x5b, 0xb8, 0xd2, 0xdc, 0xd5, 0xbb, 0xe1, 0x01, 0xd2, 0xd9, 0x11, 0xc4, 0xfd, 0x60, 0xe0, 0x07, - 0x53, 0xb6, 0x38, 0x35, 0x7d, 0x2d, 0xb3, 0x4b, 0xfc, 0x29, 0xce, 0x4d, 0xfb, 0x2d, 0x3f, 0x8c, - 0xe9, 0x91, 0x8f, 0x83, 0xff, 0x35, 0xdd, 0x06, 0x85, 0x57, 0xce, 0x30, 0x91, 0x19, 0xd1, 0x2e, - 0xc3, 0x44, 0x66, 0x64, 0x61, 0xfe, 0x16, 0xe2, 0x7e, 0x6d, 0x0a, 0x73, 0xa2, 0x91, 0xf5, 0x57, - 0x5d, 0x9f, 0x1c, 0x28, 0x9d, 0x77, 0x41, 0xe1, 0x25, 0x08, 0x87, 0x20, 0x3f, 0xaa, 0xc8, 0xa9, - 0x0f, 0x26, 0xc6, 0xf9, 0x8e, 0xef, 0x22, 0x7c, 0x0a, 0x73, 0xa2, 0xbc, 0x60, 0x3d, 0x04, 0xfb, - 0x81, 0x5a, 0xa6, 0x1a, 0xa1, 0xf7, 0xfb, 0xbe, 0x36, 0xbf, 0xba, 0x78, 0x93, 0x8d, 0xfc, 0xf6, - 0x26, 0x1b, 0xf9, 0xfe, 0x32, 0x8b, 0x2e, 0x2e, 0xb3, 0xe8, 0xd7, 0xcb, 0x2c, 0xfa, 0xf3, 0x32, - 0x8b, 0x5e, 0x6c, 0x4d, 0xff, 0xcf, 0xb9, 0xd1, 0x9b, 0x3c, 0x8f, 0x1c, 0xc7, 0xc5, 0x55, 0xfa, - 0xe8, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xa0, 0xb2, 0xda, 0xc4, 0x0e, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/snapshots/v1/snapshots.proto containerd-1.5.9/api/services/snapshots/v1/snapshots.proto --- containerd-1.2.6/api/services/snapshots/v1/snapshots.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/snapshots/v1/snapshots.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.snapshots.v1; @@ -21,6 +37,7 @@ rpc Update(UpdateSnapshotRequest) returns (UpdateSnapshotResponse); rpc List(ListSnapshotsRequest) returns (stream ListSnapshotsResponse); rpc Usage(UsageRequest) returns (UsageResponse); + rpc Cleanup(CleanupRequest) returns (google.protobuf.Empty); } message PrepareSnapshotRequest { @@ -133,6 +150,18 @@ message ListSnapshotsRequest{ string snapshotter = 1; + + // Filters contains one or more filters using the syntax defined in the + // containerd filter package. + // + // The returned result will be those that match any of the provided + // filters. Expanded, images that match the following will be + // returned: + // + // filters[0] or filters[1] or ... or filters[n-1] or filters[n] + // + // If filters is zero-length or nil, all items will be returned. + repeated string filters = 2; } message ListSnapshotsResponse { @@ -148,3 +177,7 @@ int64 size = 1; int64 inodes = 2; } + +message CleanupRequest { + string snapshotter = 1; +} diff -Nru containerd-1.2.6/api/services/tasks/v1/tasks.pb.go containerd-1.5.9/api/services/tasks/v1/tasks.pb.go --- containerd-1.2.6/api/services/tasks/v1/tasks.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/tasks/v1/tasks.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,68 +1,28 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/tasks/v1/tasks.proto -/* - Package tasks is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/tasks/v1/tasks.proto - - It has these top-level messages: - CreateTaskRequest - CreateTaskResponse - StartRequest - StartResponse - DeleteTaskRequest - DeleteResponse - DeleteProcessRequest - GetRequest - GetResponse - ListTasksRequest - ListTasksResponse - KillRequest - ExecProcessRequest - ExecProcessResponse - ResizePtyRequest - CloseIORequest - PauseTaskRequest - ResumeTaskRequest - ListPidsRequest - ListPidsResponse - CheckpointTaskRequest - CheckpointTaskResponse - UpdateTaskRequest - MetricsRequest - MetricsResponse - WaitRequest - WaitResponse -*/ package tasks -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/types" -import google_protobuf1 "github.com/gogo/protobuf/types" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import containerd_types "github.com/containerd/containerd/api/types" -import containerd_types1 "github.com/containerd/containerd/api/types" -import containerd_types2 "github.com/containerd/containerd/api/types" -import containerd_v1_types "github.com/containerd/containerd/api/types/task" -import _ "github.com/gogo/protobuf/types" - -import time "time" -import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + task "github.com/containerd/containerd/api/types/task" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types1 "github.com/gogo/protobuf/types" + github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -74,7 +34,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type CreateTaskRequest struct { ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` @@ -84,116 +44,488 @@ // These are for mounts that cannot be performed in the user namespace. // Typically, these mounts should be resolved from snapshots specified on // the container object. - Rootfs []*containerd_types.Mount `protobuf:"bytes,3,rep,name=rootfs" json:"rootfs,omitempty"` - Stdin string `protobuf:"bytes,4,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"` - Terminal bool `protobuf:"varint,7,opt,name=terminal,proto3" json:"terminal,omitempty"` - Checkpoint *containerd_types2.Descriptor `protobuf:"bytes,8,opt,name=checkpoint" json:"checkpoint,omitempty"` - Options *google_protobuf1.Any `protobuf:"bytes,9,opt,name=options" json:"options,omitempty"` + Rootfs []*types.Mount `protobuf:"bytes,3,rep,name=rootfs,proto3" json:"rootfs,omitempty"` + Stdin string `protobuf:"bytes,4,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,7,opt,name=terminal,proto3" json:"terminal,omitempty"` + Checkpoint *types.Descriptor `protobuf:"bytes,8,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + Options *types1.Any `protobuf:"bytes,9,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } +func (*CreateTaskRequest) ProtoMessage() {} +func (*CreateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{0} +} +func (m *CreateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskRequest.Merge(m, src) +} +func (m *CreateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskRequest.DiscardUnknown(m) } -func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } -func (*CreateTaskRequest) ProtoMessage() {} -func (*CreateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{0} } +var xxx_messageInfo_CreateTaskRequest proto.InternalMessageInfo type CreateTaskResponse struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } +func (*CreateTaskResponse) ProtoMessage() {} +func (*CreateTaskResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{1} +} +func (m *CreateTaskResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskResponse.Merge(m, src) +} +func (m *CreateTaskResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskResponse.DiscardUnknown(m) } -func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } -func (*CreateTaskResponse) ProtoMessage() {} -func (*CreateTaskResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{1} } +var xxx_messageInfo_CreateTaskResponse proto.InternalMessageInfo type StartRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartRequest) Reset() { *m = StartRequest{} } +func (*StartRequest) ProtoMessage() {} +func (*StartRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{2} +} +func (m *StartRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartRequest.Merge(m, src) +} +func (m *StartRequest) XXX_Size() int { + return m.Size() +} +func (m *StartRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StartRequest.DiscardUnknown(m) } -func (m *StartRequest) Reset() { *m = StartRequest{} } -func (*StartRequest) ProtoMessage() {} -func (*StartRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{2} } +var xxx_messageInfo_StartRequest proto.InternalMessageInfo type StartResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartResponse) Reset() { *m = StartResponse{} } +func (*StartResponse) ProtoMessage() {} +func (*StartResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{3} +} +func (m *StartResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartResponse.Merge(m, src) +} +func (m *StartResponse) XXX_Size() int { + return m.Size() +} +func (m *StartResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StartResponse.DiscardUnknown(m) } -func (m *StartResponse) Reset() { *m = StartResponse{} } -func (*StartResponse) ProtoMessage() {} -func (*StartResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{3} } +var xxx_messageInfo_StartResponse proto.InternalMessageInfo type DeleteTaskRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteTaskRequest) Reset() { *m = DeleteTaskRequest{} } +func (*DeleteTaskRequest) ProtoMessage() {} +func (*DeleteTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{4} +} +func (m *DeleteTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteTaskRequest.Merge(m, src) +} +func (m *DeleteTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteTaskRequest.DiscardUnknown(m) } -func (m *DeleteTaskRequest) Reset() { *m = DeleteTaskRequest{} } -func (*DeleteTaskRequest) ProtoMessage() {} -func (*DeleteTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{4} } +var xxx_messageInfo_DeleteTaskRequest proto.InternalMessageInfo type DeleteResponse struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` - ExitStatus uint32 `protobuf:"varint,3,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,4,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + ExitStatus uint32 `protobuf:"varint,3,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,4,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{5} +} +func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResponse.Merge(m, src) +} +func (m *DeleteResponse) XXX_Size() int { + return m.Size() +} +func (m *DeleteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResponse.DiscardUnknown(m) } -func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } -func (*DeleteResponse) ProtoMessage() {} -func (*DeleteResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{5} } +var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo type DeleteProcessRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteProcessRequest) Reset() { *m = DeleteProcessRequest{} } +func (*DeleteProcessRequest) ProtoMessage() {} +func (*DeleteProcessRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{6} +} +func (m *DeleteProcessRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteProcessRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteProcessRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteProcessRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteProcessRequest.Merge(m, src) +} +func (m *DeleteProcessRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteProcessRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteProcessRequest.DiscardUnknown(m) } -func (m *DeleteProcessRequest) Reset() { *m = DeleteProcessRequest{} } -func (*DeleteProcessRequest) ProtoMessage() {} -func (*DeleteProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{6} } +var xxx_messageInfo_DeleteProcessRequest proto.InternalMessageInfo type GetRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetRequest) Reset() { *m = GetRequest{} } +func (*GetRequest) ProtoMessage() {} +func (*GetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{7} +} +func (m *GetRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetRequest.Merge(m, src) +} +func (m *GetRequest) XXX_Size() int { + return m.Size() +} +func (m *GetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetRequest.DiscardUnknown(m) } -func (m *GetRequest) Reset() { *m = GetRequest{} } -func (*GetRequest) ProtoMessage() {} -func (*GetRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{7} } +var xxx_messageInfo_GetRequest proto.InternalMessageInfo type GetResponse struct { - Process *containerd_v1_types.Process `protobuf:"bytes,1,opt,name=process" json:"process,omitempty"` + Process *task.Process `protobuf:"bytes,1,opt,name=process,proto3" json:"process,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetResponse) Reset() { *m = GetResponse{} } +func (*GetResponse) ProtoMessage() {} +func (*GetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{8} +} +func (m *GetResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetResponse.Merge(m, src) +} +func (m *GetResponse) XXX_Size() int { + return m.Size() +} +func (m *GetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetResponse.DiscardUnknown(m) } -func (m *GetResponse) Reset() { *m = GetResponse{} } -func (*GetResponse) ProtoMessage() {} -func (*GetResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{8} } +var xxx_messageInfo_GetResponse proto.InternalMessageInfo type ListTasksRequest struct { - Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTasksRequest) Reset() { *m = ListTasksRequest{} } +func (*ListTasksRequest) ProtoMessage() {} +func (*ListTasksRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{9} +} +func (m *ListTasksRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListTasksRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListTasksRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListTasksRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTasksRequest.Merge(m, src) +} +func (m *ListTasksRequest) XXX_Size() int { + return m.Size() +} +func (m *ListTasksRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListTasksRequest.DiscardUnknown(m) } -func (m *ListTasksRequest) Reset() { *m = ListTasksRequest{} } -func (*ListTasksRequest) ProtoMessage() {} -func (*ListTasksRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{9} } +var xxx_messageInfo_ListTasksRequest proto.InternalMessageInfo type ListTasksResponse struct { - Tasks []*containerd_v1_types.Process `protobuf:"bytes,1,rep,name=tasks" json:"tasks,omitempty"` + Tasks []*task.Process `protobuf:"bytes,1,rep,name=tasks,proto3" json:"tasks,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListTasksResponse) Reset() { *m = ListTasksResponse{} } +func (*ListTasksResponse) ProtoMessage() {} +func (*ListTasksResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{10} +} +func (m *ListTasksResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListTasksResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListTasksResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListTasksResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListTasksResponse.Merge(m, src) +} +func (m *ListTasksResponse) XXX_Size() int { + return m.Size() +} +func (m *ListTasksResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListTasksResponse.DiscardUnknown(m) } -func (m *ListTasksResponse) Reset() { *m = ListTasksResponse{} } -func (*ListTasksResponse) ProtoMessage() {} -func (*ListTasksResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{10} } +var xxx_messageInfo_ListTasksResponse proto.InternalMessageInfo type KillRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Signal uint32 `protobuf:"varint,3,opt,name=signal,proto3" json:"signal,omitempty"` - All bool `protobuf:"varint,4,opt,name=all,proto3" json:"all,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Signal uint32 `protobuf:"varint,3,opt,name=signal,proto3" json:"signal,omitempty"` + All bool `protobuf:"varint,4,opt,name=all,proto3" json:"all,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KillRequest) Reset() { *m = KillRequest{} } +func (*KillRequest) ProtoMessage() {} +func (*KillRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{11} +} +func (m *KillRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KillRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KillRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *KillRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_KillRequest.Merge(m, src) +} +func (m *KillRequest) XXX_Size() int { + return m.Size() +} +func (m *KillRequest) XXX_DiscardUnknown() { + xxx_messageInfo_KillRequest.DiscardUnknown(m) } -func (m *KillRequest) Reset() { *m = KillRequest{} } -func (*KillRequest) ProtoMessage() {} -func (*KillRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{11} } +var xxx_messageInfo_KillRequest proto.InternalMessageInfo type ExecProcessRequest struct { ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` @@ -204,136 +536,602 @@ // Spec for starting a process in the target container. // // For runc, this is a process spec, for example. - Spec *google_protobuf1.Any `protobuf:"bytes,6,opt,name=spec" json:"spec,omitempty"` + Spec *types1.Any `protobuf:"bytes,6,opt,name=spec,proto3" json:"spec,omitempty"` // id of the exec process - ExecID string `protobuf:"bytes,7,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ExecID string `protobuf:"bytes,7,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } +func (*ExecProcessRequest) ProtoMessage() {} +func (*ExecProcessRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{12} +} +func (m *ExecProcessRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessRequest.Merge(m, src) +} +func (m *ExecProcessRequest) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessRequest.DiscardUnknown(m) } -func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } -func (*ExecProcessRequest) ProtoMessage() {} -func (*ExecProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{12} } +var xxx_messageInfo_ExecProcessRequest proto.InternalMessageInfo type ExecProcessResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } +func (*ExecProcessResponse) ProtoMessage() {} +func (*ExecProcessResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{13} +} +func (m *ExecProcessResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessResponse.Merge(m, src) +} +func (m *ExecProcessResponse) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessResponse.DiscardUnknown(m) } -func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } -func (*ExecProcessResponse) ProtoMessage() {} -func (*ExecProcessResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{13} } +var xxx_messageInfo_ExecProcessResponse proto.InternalMessageInfo type ResizePtyRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Width uint32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` - Height uint32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Width uint32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` + Height uint32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } +func (*ResizePtyRequest) ProtoMessage() {} +func (*ResizePtyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{14} +} +func (m *ResizePtyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResizePtyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResizePtyRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResizePtyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResizePtyRequest.Merge(m, src) +} +func (m *ResizePtyRequest) XXX_Size() int { + return m.Size() +} +func (m *ResizePtyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResizePtyRequest.DiscardUnknown(m) } -func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } -func (*ResizePtyRequest) ProtoMessage() {} -func (*ResizePtyRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{14} } +var xxx_messageInfo_ResizePtyRequest proto.InternalMessageInfo type CloseIORequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Stdin bool `protobuf:"varint,3,opt,name=stdin,proto3" json:"stdin,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Stdin bool `protobuf:"varint,3,opt,name=stdin,proto3" json:"stdin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } +func (*CloseIORequest) ProtoMessage() {} +func (*CloseIORequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{15} +} +func (m *CloseIORequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CloseIORequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CloseIORequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CloseIORequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CloseIORequest.Merge(m, src) +} +func (m *CloseIORequest) XXX_Size() int { + return m.Size() +} +func (m *CloseIORequest) XXX_DiscardUnknown() { + xxx_messageInfo_CloseIORequest.DiscardUnknown(m) } -func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } -func (*CloseIORequest) ProtoMessage() {} -func (*CloseIORequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{15} } +var xxx_messageInfo_CloseIORequest proto.InternalMessageInfo type PauseTaskRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PauseTaskRequest) Reset() { *m = PauseTaskRequest{} } +func (*PauseTaskRequest) ProtoMessage() {} +func (*PauseTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{16} +} +func (m *PauseTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PauseTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PauseTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PauseTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PauseTaskRequest.Merge(m, src) +} +func (m *PauseTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *PauseTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PauseTaskRequest.DiscardUnknown(m) } -func (m *PauseTaskRequest) Reset() { *m = PauseTaskRequest{} } -func (*PauseTaskRequest) ProtoMessage() {} -func (*PauseTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{16} } +var xxx_messageInfo_PauseTaskRequest proto.InternalMessageInfo type ResumeTaskRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResumeTaskRequest) Reset() { *m = ResumeTaskRequest{} } +func (*ResumeTaskRequest) ProtoMessage() {} +func (*ResumeTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{17} +} +func (m *ResumeTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResumeTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResumeTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResumeTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResumeTaskRequest.Merge(m, src) +} +func (m *ResumeTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *ResumeTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResumeTaskRequest.DiscardUnknown(m) } -func (m *ResumeTaskRequest) Reset() { *m = ResumeTaskRequest{} } -func (*ResumeTaskRequest) ProtoMessage() {} -func (*ResumeTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{17} } +var xxx_messageInfo_ResumeTaskRequest proto.InternalMessageInfo type ListPidsRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListPidsRequest) Reset() { *m = ListPidsRequest{} } +func (*ListPidsRequest) ProtoMessage() {} +func (*ListPidsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{18} +} +func (m *ListPidsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListPidsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListPidsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListPidsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListPidsRequest.Merge(m, src) +} +func (m *ListPidsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListPidsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListPidsRequest.DiscardUnknown(m) } -func (m *ListPidsRequest) Reset() { *m = ListPidsRequest{} } -func (*ListPidsRequest) ProtoMessage() {} -func (*ListPidsRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{18} } +var xxx_messageInfo_ListPidsRequest proto.InternalMessageInfo type ListPidsResponse struct { // Processes includes the process ID and additional process information - Processes []*containerd_v1_types.ProcessInfo `protobuf:"bytes,1,rep,name=processes" json:"processes,omitempty"` + Processes []*task.ProcessInfo `protobuf:"bytes,1,rep,name=processes,proto3" json:"processes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListPidsResponse) Reset() { *m = ListPidsResponse{} } +func (*ListPidsResponse) ProtoMessage() {} +func (*ListPidsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{19} +} +func (m *ListPidsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListPidsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListPidsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListPidsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListPidsResponse.Merge(m, src) +} +func (m *ListPidsResponse) XXX_Size() int { + return m.Size() +} +func (m *ListPidsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListPidsResponse.DiscardUnknown(m) } -func (m *ListPidsResponse) Reset() { *m = ListPidsResponse{} } -func (*ListPidsResponse) ProtoMessage() {} -func (*ListPidsResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{19} } +var xxx_messageInfo_ListPidsResponse proto.InternalMessageInfo type CheckpointTaskRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ParentCheckpoint github_com_opencontainers_go_digest.Digest `protobuf:"bytes,2,opt,name=parent_checkpoint,json=parentCheckpoint,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"parent_checkpoint"` - Options *google_protobuf1.Any `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ParentCheckpoint github_com_opencontainers_go_digest.Digest `protobuf:"bytes,2,opt,name=parent_checkpoint,json=parentCheckpoint,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"parent_checkpoint"` + Options *types1.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } +func (*CheckpointTaskRequest) ProtoMessage() {} +func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{20} +} +func (m *CheckpointTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointTaskRequest.Merge(m, src) +} +func (m *CheckpointTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CheckpointTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointTaskRequest.DiscardUnknown(m) } -func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } -func (*CheckpointTaskRequest) ProtoMessage() {} -func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{20} } +var xxx_messageInfo_CheckpointTaskRequest proto.InternalMessageInfo type CheckpointTaskResponse struct { - Descriptors []*containerd_types2.Descriptor `protobuf:"bytes,1,rep,name=descriptors" json:"descriptors,omitempty"` + Descriptors []*types.Descriptor `protobuf:"bytes,1,rep,name=descriptors,proto3" json:"descriptors,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CheckpointTaskResponse) Reset() { *m = CheckpointTaskResponse{} } +func (*CheckpointTaskResponse) ProtoMessage() {} +func (*CheckpointTaskResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{21} +} +func (m *CheckpointTaskResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointTaskResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointTaskResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointTaskResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointTaskResponse.Merge(m, src) +} +func (m *CheckpointTaskResponse) XXX_Size() int { + return m.Size() +} +func (m *CheckpointTaskResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointTaskResponse.DiscardUnknown(m) } -func (m *CheckpointTaskResponse) Reset() { *m = CheckpointTaskResponse{} } -func (*CheckpointTaskResponse) ProtoMessage() {} -func (*CheckpointTaskResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{21} } +var xxx_messageInfo_CheckpointTaskResponse proto.InternalMessageInfo type UpdateTaskRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - Resources *google_protobuf1.Any `protobuf:"bytes,2,opt,name=resources" json:"resources,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + Resources *types1.Any `protobuf:"bytes,2,opt,name=resources,proto3" json:"resources,omitempty"` + Annotations map[string]string `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } +func (*UpdateTaskRequest) ProtoMessage() {} +func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{22} +} +func (m *UpdateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateTaskRequest.Merge(m, src) +} +func (m *UpdateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateTaskRequest.DiscardUnknown(m) } -func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } -func (*UpdateTaskRequest) ProtoMessage() {} -func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{22} } +var xxx_messageInfo_UpdateTaskRequest proto.InternalMessageInfo type MetricsRequest struct { - Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"` + Filters []string `protobuf:"bytes,1,rep,name=filters,proto3" json:"filters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MetricsRequest) Reset() { *m = MetricsRequest{} } +func (*MetricsRequest) ProtoMessage() {} +func (*MetricsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{23} +} +func (m *MetricsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MetricsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MetricsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MetricsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_MetricsRequest.Merge(m, src) +} +func (m *MetricsRequest) XXX_Size() int { + return m.Size() +} +func (m *MetricsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_MetricsRequest.DiscardUnknown(m) } -func (m *MetricsRequest) Reset() { *m = MetricsRequest{} } -func (*MetricsRequest) ProtoMessage() {} -func (*MetricsRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{23} } +var xxx_messageInfo_MetricsRequest proto.InternalMessageInfo type MetricsResponse struct { - Metrics []*containerd_types1.Metric `protobuf:"bytes,1,rep,name=metrics" json:"metrics,omitempty"` + Metrics []*types.Metric `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MetricsResponse) Reset() { *m = MetricsResponse{} } +func (*MetricsResponse) ProtoMessage() {} +func (*MetricsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{24} +} +func (m *MetricsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MetricsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MetricsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MetricsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MetricsResponse.Merge(m, src) +} +func (m *MetricsResponse) XXX_Size() int { + return m.Size() +} +func (m *MetricsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MetricsResponse.DiscardUnknown(m) } -func (m *MetricsResponse) Reset() { *m = MetricsResponse{} } -func (*MetricsResponse) ProtoMessage() {} -func (*MetricsResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{24} } +var xxx_messageInfo_MetricsResponse proto.InternalMessageInfo type WaitRequest struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitRequest) Reset() { *m = WaitRequest{} } +func (*WaitRequest) ProtoMessage() {} +func (*WaitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{25} +} +func (m *WaitRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitRequest.Merge(m, src) +} +func (m *WaitRequest) XXX_Size() int { + return m.Size() +} +func (m *WaitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WaitRequest.DiscardUnknown(m) } -func (m *WaitRequest) Reset() { *m = WaitRequest{} } -func (*WaitRequest) ProtoMessage() {} -func (*WaitRequest) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{25} } +var xxx_messageInfo_WaitRequest proto.InternalMessageInfo type WaitResponse struct { - ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitResponse) Reset() { *m = WaitResponse{} } +func (*WaitResponse) ProtoMessage() {} +func (*WaitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_310e7127b8a26f14, []int{26} +} +func (m *WaitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitResponse.Merge(m, src) +} +func (m *WaitResponse) XXX_Size() int { + return m.Size() +} +func (m *WaitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_WaitResponse.DiscardUnknown(m) } -func (m *WaitResponse) Reset() { *m = WaitResponse{} } -func (*WaitResponse) ProtoMessage() {} -func (*WaitResponse) Descriptor() ([]byte, []int) { return fileDescriptorTasks, []int{26} } +var xxx_messageInfo_WaitResponse proto.InternalMessageInfo func init() { proto.RegisterType((*CreateTaskRequest)(nil), "containerd.services.tasks.v1.CreateTaskRequest") @@ -359,12 +1157,107 @@ proto.RegisterType((*CheckpointTaskRequest)(nil), "containerd.services.tasks.v1.CheckpointTaskRequest") proto.RegisterType((*CheckpointTaskResponse)(nil), "containerd.services.tasks.v1.CheckpointTaskResponse") proto.RegisterType((*UpdateTaskRequest)(nil), "containerd.services.tasks.v1.UpdateTaskRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.services.tasks.v1.UpdateTaskRequest.AnnotationsEntry") proto.RegisterType((*MetricsRequest)(nil), "containerd.services.tasks.v1.MetricsRequest") proto.RegisterType((*MetricsResponse)(nil), "containerd.services.tasks.v1.MetricsResponse") proto.RegisterType((*WaitRequest)(nil), "containerd.services.tasks.v1.WaitRequest") proto.RegisterType((*WaitResponse)(nil), "containerd.services.tasks.v1.WaitResponse") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/tasks/v1/tasks.proto", fileDescriptor_310e7127b8a26f14) +} + +var fileDescriptor_310e7127b8a26f14 = []byte{ + // 1376 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x6f, 0x1b, 0x45, + 0x14, 0xee, 0xfa, 0xee, 0xe3, 0xa4, 0x4d, 0x96, 0x34, 0x98, 0xa5, 0x8a, 0xc3, 0xf2, 0x62, 0x02, + 0x5d, 0x53, 0x17, 0x55, 0x55, 0x5b, 0x55, 0xe4, 0x46, 0x64, 0x41, 0xd5, 0x74, 0x5b, 0xa0, 0xaa, + 0x84, 0xc2, 0xc6, 0x3b, 0x71, 0x46, 0xb1, 0x77, 0xb6, 0x3b, 0xe3, 0xb4, 0xe6, 0x05, 0x7e, 0x42, + 0x5f, 0x79, 0x81, 0xbf, 0x93, 0x47, 0x1e, 0x11, 0xaa, 0x02, 0xf5, 0xbf, 0xe0, 0x0d, 0xcd, 0x65, + 0xd7, 0x1b, 0x3b, 0xf6, 0x3a, 0x4d, 0xc3, 0x4b, 0x32, 0x33, 0x7b, 0xce, 0x99, 0x33, 0xdf, 0xb9, + 0x7d, 0x09, 0xac, 0xb5, 0x30, 0xdb, 0xef, 0xee, 0x5a, 0x4d, 0xd2, 0xa9, 0x35, 0x89, 0xc7, 0x1c, + 0xec, 0xa1, 0xc0, 0x8d, 0x2f, 0x1d, 0x1f, 0xd7, 0x28, 0x0a, 0x0e, 0x71, 0x13, 0xd1, 0x1a, 0x73, + 0xe8, 0x01, 0xad, 0x1d, 0xde, 0x90, 0x0b, 0xcb, 0x0f, 0x08, 0x23, 0xfa, 0xb5, 0x81, 0xb4, 0x15, + 0x4a, 0x5a, 0x52, 0xe0, 0xf0, 0x86, 0xf1, 0x61, 0x8b, 0x90, 0x56, 0x1b, 0xd5, 0x84, 0xec, 0x6e, + 0x77, 0xaf, 0x86, 0x3a, 0x3e, 0xeb, 0x49, 0x55, 0xe3, 0x83, 0xe1, 0x8f, 0x8e, 0x17, 0x7e, 0x5a, + 0x68, 0x91, 0x16, 0x11, 0xcb, 0x1a, 0x5f, 0xa9, 0xd3, 0x5b, 0x53, 0xf9, 0xcb, 0x7a, 0x3e, 0xa2, + 0xb5, 0x0e, 0xe9, 0x7a, 0x4c, 0xe9, 0xdd, 0x3e, 0x8b, 0x1e, 0x62, 0x01, 0x6e, 0xaa, 0xd7, 0x19, + 0x77, 0xcf, 0xa0, 0xe9, 0x22, 0xda, 0x0c, 0xb0, 0xcf, 0x48, 0xa0, 0x94, 0xef, 0x9c, 0x41, 0x99, + 0x23, 0x26, 0x7e, 0x28, 0xdd, 0xca, 0x30, 0x36, 0x0c, 0x77, 0x10, 0x65, 0x4e, 0xc7, 0x97, 0x02, + 0xe6, 0x51, 0x0a, 0xe6, 0xd7, 0x03, 0xe4, 0x30, 0xf4, 0xc4, 0xa1, 0x07, 0x36, 0x7a, 0xde, 0x45, + 0x94, 0xe9, 0x75, 0x98, 0x89, 0xcc, 0xef, 0x60, 0xb7, 0xac, 0x2d, 0x6b, 0xd5, 0xe2, 0xda, 0x95, + 0xfe, 0x71, 0xa5, 0xb4, 0x1e, 0x9e, 0x37, 0x36, 0xec, 0x52, 0x24, 0xd4, 0x70, 0xf5, 0x1a, 0xe4, + 0x02, 0x42, 0xd8, 0x1e, 0x2d, 0xa7, 0x97, 0xd3, 0xd5, 0x52, 0xfd, 0x7d, 0x2b, 0x16, 0x52, 0xe1, + 0x9d, 0xf5, 0x80, 0x83, 0x69, 0x2b, 0x31, 0x7d, 0x01, 0xb2, 0x94, 0xb9, 0xd8, 0x2b, 0x67, 0xb8, + 0x75, 0x5b, 0x6e, 0xf4, 0x45, 0xc8, 0x51, 0xe6, 0x92, 0x2e, 0x2b, 0x67, 0xc5, 0xb1, 0xda, 0xa9, + 0x73, 0x14, 0x04, 0xe5, 0x5c, 0x74, 0x8e, 0x82, 0x40, 0x37, 0xa0, 0xc0, 0x50, 0xd0, 0xc1, 0x9e, + 0xd3, 0x2e, 0xe7, 0x97, 0xb5, 0x6a, 0xc1, 0x8e, 0xf6, 0xfa, 0x3d, 0x80, 0xe6, 0x3e, 0x6a, 0x1e, + 0xf8, 0x04, 0x7b, 0xac, 0x5c, 0x58, 0xd6, 0xaa, 0xa5, 0xfa, 0xb5, 0x51, 0xb7, 0x36, 0x22, 0xc4, + 0xed, 0x98, 0xbc, 0x6e, 0x41, 0x9e, 0xf8, 0x0c, 0x13, 0x8f, 0x96, 0x8b, 0x42, 0x75, 0xc1, 0x92, + 0x68, 0x5a, 0x21, 0x9a, 0xd6, 0xaa, 0xd7, 0xb3, 0x43, 0x21, 0xf3, 0x19, 0xe8, 0x71, 0x24, 0xa9, + 0x4f, 0x3c, 0x8a, 0xde, 0x0a, 0xca, 0x39, 0x48, 0xfb, 0xd8, 0x2d, 0xa7, 0x96, 0xb5, 0xea, 0xac, + 0xcd, 0x97, 0x66, 0x0b, 0x66, 0x1e, 0x33, 0x27, 0x60, 0xe7, 0x09, 0xd0, 0xc7, 0x90, 0x47, 0x2f, + 0x51, 0x73, 0x47, 0x59, 0x2e, 0xae, 0x41, 0xff, 0xb8, 0x92, 0xdb, 0x7c, 0x89, 0x9a, 0x8d, 0x0d, + 0x3b, 0xc7, 0x3f, 0x35, 0x5c, 0xf3, 0x23, 0x98, 0x55, 0x17, 0x29, 0xff, 0x95, 0x2f, 0xda, 0xc0, + 0x97, 0x2d, 0x98, 0xdf, 0x40, 0x6d, 0x74, 0xee, 0x8c, 0x31, 0x7f, 0xd3, 0xe0, 0xb2, 0xb4, 0x14, + 0xdd, 0xb6, 0x08, 0xa9, 0x48, 0x39, 0xd7, 0x3f, 0xae, 0xa4, 0x1a, 0x1b, 0x76, 0x0a, 0x9f, 0x82, + 0x88, 0x5e, 0x81, 0x12, 0x7a, 0x89, 0xd9, 0x0e, 0x65, 0x0e, 0xeb, 0xf2, 0x9c, 0xe3, 0x5f, 0x80, + 0x1f, 0x3d, 0x16, 0x27, 0xfa, 0x2a, 0x14, 0xf9, 0x0e, 0xb9, 0x3b, 0x0e, 0x13, 0x29, 0x56, 0xaa, + 0x1b, 0x23, 0x01, 0x7c, 0x12, 0x96, 0xc3, 0x5a, 0xe1, 0xe8, 0xb8, 0x72, 0xe9, 0xd5, 0xdf, 0x15, + 0xcd, 0x2e, 0x48, 0xb5, 0x55, 0x66, 0x12, 0x58, 0x90, 0xfe, 0x6d, 0x07, 0xa4, 0x89, 0x28, 0xbd, + 0x70, 0xf4, 0x11, 0xc0, 0x16, 0xba, 0xf8, 0x20, 0x6f, 0x42, 0x49, 0x5c, 0xa3, 0x40, 0xbf, 0x05, + 0x79, 0x5f, 0x3e, 0x50, 0x5c, 0x31, 0x54, 0x23, 0x87, 0x37, 0x54, 0x99, 0x84, 0x20, 0x84, 0xc2, + 0xe6, 0x0a, 0xcc, 0x7d, 0x83, 0x29, 0xe3, 0x69, 0x10, 0x41, 0xb3, 0x08, 0xb9, 0x3d, 0xdc, 0x66, + 0x28, 0x90, 0xde, 0xda, 0x6a, 0xc7, 0x93, 0x26, 0x26, 0x1b, 0xd5, 0x46, 0x56, 0xb4, 0xf8, 0xb2, + 0x26, 0x3a, 0xc6, 0xe4, 0x6b, 0xa5, 0xa8, 0xf9, 0x4a, 0x83, 0xd2, 0xd7, 0xb8, 0xdd, 0xbe, 0x68, + 0x90, 0x44, 0xc3, 0xc1, 0x2d, 0xde, 0x56, 0x64, 0x6e, 0xa9, 0x1d, 0x4f, 0x45, 0xa7, 0xdd, 0x16, + 0x19, 0x55, 0xb0, 0xf9, 0xd2, 0xfc, 0x57, 0x03, 0x9d, 0x2b, 0xbf, 0x83, 0x2c, 0x89, 0x7a, 0x62, + 0xea, 0xf4, 0x9e, 0x98, 0x1e, 0xd3, 0x13, 0x33, 0x63, 0x7b, 0x62, 0x76, 0xa8, 0x27, 0x56, 0x21, + 0x43, 0x7d, 0xd4, 0x14, 0x5d, 0x74, 0x5c, 0x4b, 0x13, 0x12, 0x71, 0x94, 0xf2, 0x63, 0x53, 0xe9, + 0x2a, 0xbc, 0x77, 0xe2, 0xe9, 0x32, 0xb2, 0xe6, 0xaf, 0x1a, 0xcc, 0xd9, 0x88, 0xe2, 0x9f, 0xd0, + 0x36, 0xeb, 0x5d, 0x78, 0xa8, 0x16, 0x20, 0xfb, 0x02, 0xbb, 0x6c, 0x5f, 0x45, 0x4a, 0x6e, 0x38, + 0x3a, 0xfb, 0x08, 0xb7, 0xf6, 0x65, 0xf5, 0xcf, 0xda, 0x6a, 0x67, 0xfe, 0x0c, 0x97, 0xd7, 0xdb, + 0x84, 0xa2, 0xc6, 0xc3, 0xff, 0xc3, 0x31, 0x19, 0xce, 0xb4, 0x88, 0x82, 0xdc, 0x98, 0x5f, 0xc1, + 0xdc, 0xb6, 0xd3, 0xa5, 0xe7, 0xee, 0x9f, 0x5b, 0x30, 0x6f, 0x23, 0xda, 0xed, 0x9c, 0xdb, 0xd0, + 0x26, 0x5c, 0xe1, 0xc5, 0xb9, 0x8d, 0xdd, 0xf3, 0x24, 0xaf, 0x69, 0xcb, 0x7e, 0x20, 0xcd, 0xa8, + 0x12, 0xbf, 0x0f, 0x45, 0xd5, 0x2e, 0x50, 0x58, 0xe6, 0xcb, 0x93, 0xca, 0xbc, 0xe1, 0xed, 0x11, + 0x7b, 0xa0, 0x62, 0xbe, 0xd6, 0xe0, 0xea, 0x7a, 0x34, 0x93, 0xcf, 0xcb, 0x51, 0x76, 0x60, 0xde, + 0x77, 0x02, 0xe4, 0xb1, 0x9d, 0x18, 0x2f, 0x90, 0xe1, 0xab, 0xf3, 0xfe, 0xff, 0xd7, 0x71, 0x65, + 0x25, 0xc6, 0xb6, 0x88, 0x8f, 0xbc, 0x48, 0x9d, 0xd6, 0x5a, 0xe4, 0xba, 0x8b, 0x5b, 0x88, 0x32, + 0x6b, 0x43, 0xfc, 0xb2, 0xe7, 0xa4, 0xb1, 0xf5, 0x53, 0x39, 0x43, 0x7a, 0x1a, 0xce, 0xf0, 0x14, + 0x16, 0x87, 0x5f, 0x17, 0x01, 0x57, 0x1a, 0x30, 0xc1, 0x53, 0x3b, 0xe4, 0x08, 0x79, 0x89, 0x2b, + 0x98, 0xbf, 0xa7, 0x60, 0xfe, 0x5b, 0xdf, 0x7d, 0x07, 0xc4, 0xae, 0x0e, 0xc5, 0x00, 0x51, 0xd2, + 0x0d, 0x9a, 0x88, 0x0a, 0xb0, 0xc6, 0xbd, 0x6a, 0x20, 0xa6, 0xef, 0x42, 0xc9, 0xf1, 0x3c, 0xc2, + 0x9c, 0x10, 0x0b, 0xee, 0xfd, 0x97, 0xd6, 0x24, 0x92, 0x6f, 0x8d, 0x78, 0x6b, 0xad, 0x0e, 0x4c, + 0x6c, 0x7a, 0x2c, 0xe8, 0xd9, 0x71, 0xa3, 0xc6, 0x7d, 0x98, 0x1b, 0x16, 0xe0, 0xcd, 0xf9, 0x00, + 0xf5, 0xd4, 0xec, 0xe1, 0x4b, 0x5e, 0x82, 0x87, 0x4e, 0xbb, 0x8b, 0xc2, 0x8e, 0x2a, 0x36, 0x77, + 0x52, 0xb7, 0x35, 0x73, 0x05, 0x2e, 0x3f, 0x90, 0x2c, 0x3d, 0x44, 0xa7, 0x0c, 0x79, 0x39, 0xae, + 0x24, 0xde, 0x45, 0x3b, 0xdc, 0xf2, 0x0a, 0x89, 0x64, 0xa3, 0xe1, 0x95, 0x57, 0x24, 0x5f, 0x05, + 0xa7, 0x7c, 0x0a, 0xe1, 0x15, 0x02, 0x76, 0x28, 0x68, 0xee, 0x41, 0xe9, 0x7b, 0x07, 0x5f, 0xfc, + 0x80, 0x0f, 0x60, 0x46, 0xde, 0xa3, 0x7c, 0x1d, 0x22, 0x4b, 0xda, 0x64, 0xb2, 0x94, 0x7a, 0x1b, + 0xb2, 0x54, 0x7f, 0x3d, 0x03, 0x59, 0x31, 0xde, 0xf5, 0x03, 0xc8, 0x49, 0x22, 0xac, 0xd7, 0x26, + 0x47, 0x7c, 0xe4, 0x0f, 0x0f, 0xe3, 0xf3, 0xe9, 0x15, 0xd4, 0xd3, 0x7e, 0x84, 0xac, 0x20, 0xac, + 0xfa, 0xca, 0x64, 0xd5, 0x38, 0x7d, 0x36, 0x3e, 0x9d, 0x4a, 0x56, 0xdd, 0xd0, 0x82, 0x9c, 0x64, + 0x81, 0x49, 0xcf, 0x19, 0x61, 0xc5, 0xc6, 0x67, 0xd3, 0x28, 0x44, 0x17, 0x3d, 0x87, 0xd9, 0x13, + 0x74, 0x53, 0xaf, 0x4f, 0xa3, 0x7e, 0x92, 0x75, 0x9c, 0xf1, 0xca, 0x67, 0x90, 0xde, 0x42, 0x4c, + 0xaf, 0x4e, 0x56, 0x1a, 0x70, 0x52, 0xe3, 0x93, 0x29, 0x24, 0x23, 0xdc, 0x32, 0x7c, 0x1c, 0xe8, + 0xd6, 0x64, 0x95, 0x61, 0x0a, 0x69, 0xd4, 0xa6, 0x96, 0x57, 0x17, 0x35, 0x20, 0xc3, 0x19, 0xa1, + 0x9e, 0xe0, 0x5b, 0x8c, 0x35, 0x1a, 0x8b, 0x23, 0xc9, 0xbd, 0xd9, 0xf1, 0x59, 0x4f, 0xdf, 0x86, + 0x0c, 0x2f, 0x25, 0x3d, 0x21, 0x0f, 0x47, 0xd9, 0xde, 0x58, 0x8b, 0x8f, 0xa1, 0x18, 0x11, 0xa1, + 0x24, 0x28, 0x86, 0x19, 0xd3, 0x58, 0xa3, 0x0f, 0x21, 0xaf, 0x28, 0x8c, 0x9e, 0x10, 0xef, 0x93, + 0x4c, 0x67, 0x82, 0xc1, 0xac, 0xa0, 0x24, 0x49, 0x1e, 0x0e, 0xf3, 0x96, 0xb1, 0x06, 0x1f, 0x41, + 0x4e, 0x72, 0x93, 0xa4, 0xa2, 0x19, 0x61, 0x30, 0x63, 0x4d, 0x62, 0x28, 0x84, 0xf4, 0x42, 0xbf, + 0x9e, 0x9c, 0x23, 0x31, 0x36, 0x63, 0x58, 0xd3, 0x8a, 0xab, 0x8c, 0x7a, 0x01, 0x10, 0x1b, 0xea, + 0x37, 0x13, 0x20, 0x3e, 0x8d, 0x9e, 0x18, 0x5f, 0x9c, 0x4d, 0x49, 0x5d, 0xfc, 0x08, 0x72, 0x72, + 0x0c, 0x26, 0xc1, 0x36, 0x32, 0x2c, 0xc7, 0xc2, 0xb6, 0x07, 0x79, 0x35, 0xba, 0x92, 0x72, 0xe5, + 0xe4, 0x34, 0x34, 0xae, 0x4f, 0x29, 0xad, 0x5c, 0xff, 0x01, 0x32, 0x7c, 0xe6, 0x24, 0x55, 0x61, + 0x6c, 0xfe, 0x19, 0x2b, 0xd3, 0x88, 0x4a, 0xf3, 0x6b, 0xdf, 0x1d, 0xbd, 0x59, 0xba, 0xf4, 0xe7, + 0x9b, 0xa5, 0x4b, 0xbf, 0xf4, 0x97, 0xb4, 0xa3, 0xfe, 0x92, 0xf6, 0x47, 0x7f, 0x49, 0xfb, 0xa7, + 0xbf, 0xa4, 0x3d, 0xbb, 0xf7, 0x76, 0xff, 0x7e, 0xbc, 0x2b, 0x16, 0x4f, 0x53, 0xbb, 0x39, 0x01, + 0xd8, 0xcd, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x55, 0xbf, 0x54, 0xc7, 0x14, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -373,8 +1266,9 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Tasks service - +// TasksClient is the client API for Tasks service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type TasksClient interface { // Create a task. Create(ctx context.Context, in *CreateTaskRequest, opts ...grpc.CallOption) (*CreateTaskResponse, error) @@ -386,15 +1280,15 @@ Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) List(ctx context.Context, in *ListTasksRequest, opts ...grpc.CallOption) (*ListTasksResponse, error) // Kill a task or process. - Kill(ctx context.Context, in *KillRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) - Exec(ctx context.Context, in *ExecProcessRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) - ResizePty(ctx context.Context, in *ResizePtyRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) - CloseIO(ctx context.Context, in *CloseIORequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) - Pause(ctx context.Context, in *PauseTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) - Resume(ctx context.Context, in *ResumeTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) + Kill(ctx context.Context, in *KillRequest, opts ...grpc.CallOption) (*types1.Empty, error) + Exec(ctx context.Context, in *ExecProcessRequest, opts ...grpc.CallOption) (*types1.Empty, error) + ResizePty(ctx context.Context, in *ResizePtyRequest, opts ...grpc.CallOption) (*types1.Empty, error) + CloseIO(ctx context.Context, in *CloseIORequest, opts ...grpc.CallOption) (*types1.Empty, error) + Pause(ctx context.Context, in *PauseTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) + Resume(ctx context.Context, in *ResumeTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) ListPids(ctx context.Context, in *ListPidsRequest, opts ...grpc.CallOption) (*ListPidsResponse, error) Checkpoint(ctx context.Context, in *CheckpointTaskRequest, opts ...grpc.CallOption) (*CheckpointTaskResponse, error) - Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) + Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) Metrics(ctx context.Context, in *MetricsRequest, opts ...grpc.CallOption) (*MetricsResponse, error) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*WaitResponse, error) } @@ -409,7 +1303,7 @@ func (c *tasksClient) Create(ctx context.Context, in *CreateTaskRequest, opts ...grpc.CallOption) (*CreateTaskResponse, error) { out := new(CreateTaskResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Create", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Create", in, out, opts...) if err != nil { return nil, err } @@ -418,7 +1312,7 @@ func (c *tasksClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) { out := new(StartResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Start", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Start", in, out, opts...) if err != nil { return nil, err } @@ -427,7 +1321,7 @@ func (c *tasksClient) Delete(ctx context.Context, in *DeleteTaskRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { out := new(DeleteResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Delete", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Delete", in, out, opts...) if err != nil { return nil, err } @@ -436,7 +1330,7 @@ func (c *tasksClient) DeleteProcess(ctx context.Context, in *DeleteProcessRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { out := new(DeleteResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/DeleteProcess", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/DeleteProcess", in, out, opts...) if err != nil { return nil, err } @@ -445,7 +1339,7 @@ func (c *tasksClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { out := new(GetResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Get", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Get", in, out, opts...) if err != nil { return nil, err } @@ -454,61 +1348,61 @@ func (c *tasksClient) List(ctx context.Context, in *ListTasksRequest, opts ...grpc.CallOption) (*ListTasksResponse, error) { out := new(ListTasksResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/List", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/List", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) Kill(ctx context.Context, in *KillRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Kill", in, out, c.cc, opts...) +func (c *tasksClient) Kill(ctx context.Context, in *KillRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Kill", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) Exec(ctx context.Context, in *ExecProcessRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Exec", in, out, c.cc, opts...) +func (c *tasksClient) Exec(ctx context.Context, in *ExecProcessRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Exec", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) ResizePty(ctx context.Context, in *ResizePtyRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/ResizePty", in, out, c.cc, opts...) +func (c *tasksClient) ResizePty(ctx context.Context, in *ResizePtyRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/ResizePty", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) CloseIO(ctx context.Context, in *CloseIORequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/CloseIO", in, out, c.cc, opts...) +func (c *tasksClient) CloseIO(ctx context.Context, in *CloseIORequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/CloseIO", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) Pause(ctx context.Context, in *PauseTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Pause", in, out, c.cc, opts...) +func (c *tasksClient) Pause(ctx context.Context, in *PauseTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Pause", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) Resume(ctx context.Context, in *ResumeTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Resume", in, out, c.cc, opts...) +func (c *tasksClient) Resume(ctx context.Context, in *ResumeTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Resume", in, out, opts...) if err != nil { return nil, err } @@ -517,7 +1411,7 @@ func (c *tasksClient) ListPids(ctx context.Context, in *ListPidsRequest, opts ...grpc.CallOption) (*ListPidsResponse, error) { out := new(ListPidsResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/ListPids", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/ListPids", in, out, opts...) if err != nil { return nil, err } @@ -526,16 +1420,16 @@ func (c *tasksClient) Checkpoint(ctx context.Context, in *CheckpointTaskRequest, opts ...grpc.CallOption) (*CheckpointTaskResponse, error) { out := new(CheckpointTaskResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Checkpoint", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Checkpoint", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tasksClient) Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*google_protobuf.Empty, error) { - out := new(google_protobuf.Empty) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Update", in, out, c.cc, opts...) +func (c *tasksClient) Update(ctx context.Context, in *UpdateTaskRequest, opts ...grpc.CallOption) (*types1.Empty, error) { + out := new(types1.Empty) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Update", in, out, opts...) if err != nil { return nil, err } @@ -544,7 +1438,7 @@ func (c *tasksClient) Metrics(ctx context.Context, in *MetricsRequest, opts ...grpc.CallOption) (*MetricsResponse, error) { out := new(MetricsResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Metrics", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Metrics", in, out, opts...) if err != nil { return nil, err } @@ -553,15 +1447,14 @@ func (c *tasksClient) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*WaitResponse, error) { out := new(WaitResponse) - err := grpc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Wait", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.tasks.v1.Tasks/Wait", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Tasks service - +// TasksServer is the server API for Tasks service. type TasksServer interface { // Create a task. Create(context.Context, *CreateTaskRequest) (*CreateTaskResponse, error) @@ -573,19 +1466,75 @@ Get(context.Context, *GetRequest) (*GetResponse, error) List(context.Context, *ListTasksRequest) (*ListTasksResponse, error) // Kill a task or process. - Kill(context.Context, *KillRequest) (*google_protobuf.Empty, error) - Exec(context.Context, *ExecProcessRequest) (*google_protobuf.Empty, error) - ResizePty(context.Context, *ResizePtyRequest) (*google_protobuf.Empty, error) - CloseIO(context.Context, *CloseIORequest) (*google_protobuf.Empty, error) - Pause(context.Context, *PauseTaskRequest) (*google_protobuf.Empty, error) - Resume(context.Context, *ResumeTaskRequest) (*google_protobuf.Empty, error) + Kill(context.Context, *KillRequest) (*types1.Empty, error) + Exec(context.Context, *ExecProcessRequest) (*types1.Empty, error) + ResizePty(context.Context, *ResizePtyRequest) (*types1.Empty, error) + CloseIO(context.Context, *CloseIORequest) (*types1.Empty, error) + Pause(context.Context, *PauseTaskRequest) (*types1.Empty, error) + Resume(context.Context, *ResumeTaskRequest) (*types1.Empty, error) ListPids(context.Context, *ListPidsRequest) (*ListPidsResponse, error) Checkpoint(context.Context, *CheckpointTaskRequest) (*CheckpointTaskResponse, error) - Update(context.Context, *UpdateTaskRequest) (*google_protobuf.Empty, error) + Update(context.Context, *UpdateTaskRequest) (*types1.Empty, error) Metrics(context.Context, *MetricsRequest) (*MetricsResponse, error) Wait(context.Context, *WaitRequest) (*WaitResponse, error) } +// UnimplementedTasksServer can be embedded to have forward compatible implementations. +type UnimplementedTasksServer struct { +} + +func (*UnimplementedTasksServer) Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") +} +func (*UnimplementedTasksServer) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Start not implemented") +} +func (*UnimplementedTasksServer) Delete(ctx context.Context, req *DeleteTaskRequest) (*DeleteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") +} +func (*UnimplementedTasksServer) DeleteProcess(ctx context.Context, req *DeleteProcessRequest) (*DeleteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteProcess not implemented") +} +func (*UnimplementedTasksServer) Get(ctx context.Context, req *GetRequest) (*GetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") +} +func (*UnimplementedTasksServer) List(ctx context.Context, req *ListTasksRequest) (*ListTasksResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} +func (*UnimplementedTasksServer) Kill(ctx context.Context, req *KillRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Kill not implemented") +} +func (*UnimplementedTasksServer) Exec(ctx context.Context, req *ExecProcessRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Exec not implemented") +} +func (*UnimplementedTasksServer) ResizePty(ctx context.Context, req *ResizePtyRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResizePty not implemented") +} +func (*UnimplementedTasksServer) CloseIO(ctx context.Context, req *CloseIORequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method CloseIO not implemented") +} +func (*UnimplementedTasksServer) Pause(ctx context.Context, req *PauseTaskRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Pause not implemented") +} +func (*UnimplementedTasksServer) Resume(ctx context.Context, req *ResumeTaskRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Resume not implemented") +} +func (*UnimplementedTasksServer) ListPids(ctx context.Context, req *ListPidsRequest) (*ListPidsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPids not implemented") +} +func (*UnimplementedTasksServer) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*CheckpointTaskResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Checkpoint not implemented") +} +func (*UnimplementedTasksServer) Update(ctx context.Context, req *UpdateTaskRequest) (*types1.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} +func (*UnimplementedTasksServer) Metrics(ctx context.Context, req *MetricsRequest) (*MetricsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Metrics not implemented") +} +func (*UnimplementedTasksServer) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Wait not implemented") +} + func RegisterTasksServer(s *grpc.Server, srv TasksServer) { s.RegisterService(&_Tasks_serviceDesc, srv) } @@ -976,7 +1925,7 @@ func (m *CreateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -984,83 +1933,102 @@ } func (m *CreateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Rootfs) > 0 { - for _, msg := range m.Rootfs { - dAtA[i] = 0x1a - i++ - i = encodeVarintTasks(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + if m.Options != nil { + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x4a } - if len(m.Stdin) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) - } - if len(m.Stderr) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if m.Checkpoint != nil { + { + size, err := m.Checkpoint.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 } if m.Terminal { - dAtA[i] = 0x38 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x38 } - if m.Checkpoint != nil { - dAtA[i] = 0x42 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Checkpoint.Size())) - n1, err := m.Checkpoint.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x32 } - if m.Options != nil { - dAtA[i] = 0x4a - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Options.Size())) - n2, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x2a } - return i, nil -} - -func (m *CreateTaskResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x22 + } + if len(m.Rootfs) > 0 { + for iNdEx := len(m.Rootfs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rootfs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CreateTaskResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1068,28 +2036,38 @@ } func (m *CreateTaskResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Pid != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintTasks(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x10 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1097,29 +2075,40 @@ } func (m *StartRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1127,22 +2116,31 @@ } func (m *StartResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Pid != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintTasks(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1150,23 +2148,33 @@ } func (m *DeleteTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1174,41 +2182,51 @@ } func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintTasks(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x22 + if m.ExitStatus != 0 { + i = encodeVarintTasks(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x18 } if m.Pid != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintTasks(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x10 } - if m.ExitStatus != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.ExitStatus)) - } - dAtA[i] = 0x22 - i++ - i = encodeVarintTasks(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n3, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - i += n3 - return i, nil + return len(dAtA) - i, nil } func (m *DeleteProcessRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1216,29 +2234,40 @@ } func (m *DeleteProcessRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteProcessRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1246,29 +2275,40 @@ } func (m *GetRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *GetResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1276,27 +2316,38 @@ } func (m *GetResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Process != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Process.Size())) - n4, err := m.Process.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Process.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n4 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListTasksRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1304,23 +2355,33 @@ } func (m *ListTasksRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListTasksRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filter) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.Filter) + copy(dAtA[i:], m.Filter) i = encodeVarintTasks(dAtA, i, uint64(len(m.Filter))) - i += copy(dAtA[i:], m.Filter) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListTasksResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1328,29 +2389,40 @@ } func (m *ListTasksResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListTasksResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Tasks) > 0 { - for _, msg := range m.Tasks { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Tasks) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tasks[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *KillRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1358,44 +2430,55 @@ } func (m *KillRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KillRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) - } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) - } - if m.Signal != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Signal)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.All { - dAtA[i] = 0x20 - i++ + i-- if m.All { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 + } + if m.Signal != 0 { + i = encodeVarintTasks(dAtA, i, uint64(m.Signal)) + i-- + dAtA[i] = 0x18 } - return i, nil + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ExecProcessRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1403,67 +2486,83 @@ } func (m *ExecProcessRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) - } - if len(m.Stdin) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Stdout) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x3a } - if len(m.Stderr) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if m.Spec != nil { + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 } if m.Terminal { - dAtA[i] = 0x28 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x28 } - if m.Spec != nil { - dAtA[i] = 0x32 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Spec.Size())) - n5, err := m.Spec.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n5 + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x22 } - if len(m.ExecID) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x1a } - return i, nil + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ExecProcessResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1471,17 +2570,26 @@ } func (m *ExecProcessResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - return i, nil + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + return len(dAtA) - i, nil } func (m *ResizePtyRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1489,39 +2597,50 @@ } func (m *ResizePtyRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResizePtyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if m.Height != 0 { + i = encodeVarintTasks(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x20 } if m.Width != 0 { - dAtA[i] = 0x18 - i++ i = encodeVarintTasks(dAtA, i, uint64(m.Width)) + i-- + dAtA[i] = 0x18 } - if m.Height != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Height)) + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CloseIORequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1529,39 +2648,50 @@ } func (m *CloseIORequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CloseIORequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) - } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Stdin { - dAtA[i] = 0x18 - i++ + i-- if m.Stdin { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 } - return i, nil + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *PauseTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1569,23 +2699,33 @@ } func (m *PauseTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PauseTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ResumeTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1593,23 +2733,33 @@ } func (m *ResumeTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResumeTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListPidsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1617,23 +2767,33 @@ } func (m *ListPidsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListPidsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListPidsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1641,29 +2801,40 @@ } func (m *ListPidsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListPidsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Processes) > 0 { - for _, msg := range m.Processes { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Processes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Processes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1671,39 +2842,52 @@ } func (m *CheckpointTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Options != nil { + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } if len(m.ParentCheckpoint) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ParentCheckpoint) + copy(dAtA[i:], m.ParentCheckpoint) i = encodeVarintTasks(dAtA, i, uint64(len(m.ParentCheckpoint))) - i += copy(dAtA[i:], m.ParentCheckpoint) + i-- + dAtA[i] = 0x12 } - if m.Options != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Options.Size())) - n6, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n6 + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointTaskResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1711,29 +2895,40 @@ } func (m *CheckpointTaskResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointTaskResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Descriptors) > 0 { - for _, msg := range m.Descriptors { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Descriptors) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Descriptors[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *UpdateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1741,33 +2936,64 @@ } func (m *UpdateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Annotations) > 0 { + for k := range m.Annotations { + v := m.Annotations[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintTasks(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintTasks(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintTasks(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } } if m.Resources != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(m.Resources.Size())) - n7, err := m.Resources.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Resources.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n7 + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *MetricsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1775,32 +3001,35 @@ } func (m *MetricsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MetricsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Filters) > 0 { - for _, s := range m.Filters { + for iNdEx := len(m.Filters) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Filters[iNdEx]) + copy(dAtA[i:], m.Filters[iNdEx]) + i = encodeVarintTasks(dAtA, i, uint64(len(m.Filters[iNdEx]))) + i-- dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) } } - return i, nil + return len(dAtA) - i, nil } func (m *MetricsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1808,29 +3037,40 @@ } func (m *MetricsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MetricsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Metrics) > 0 { - for _, msg := range m.Metrics { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Metrics) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Metrics[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTasks(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *WaitRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1838,29 +3078,40 @@ } func (m *WaitRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintTasks(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTasks(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *WaitResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1868,36 +3119,50 @@ } func (m *WaitResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err8 != nil { + return 0, err8 + } + i -= n8 + i = encodeVarintTasks(dAtA, i, uint64(n8)) + i-- + dAtA[i] = 0x12 if m.ExitStatus != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintTasks(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x8 } - dAtA[i] = 0x12 - i++ - i = encodeVarintTasks(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n8, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n8 - return i, nil + return len(dAtA) - i, nil } func encodeVarintTasks(dAtA []byte, offset int, v uint64) int { + offset -= sovTasks(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *CreateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -1933,10 +3198,16 @@ l = m.Options.Size() n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateTaskResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -1946,10 +3217,16 @@ if m.Pid != 0 { n += 1 + sovTasks(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -1960,29 +3237,47 @@ if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { n += 1 + sovTasks(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1995,12 +3290,18 @@ if m.ExitStatus != 0 { n += 1 + sovTasks(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovTasks(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteProcessRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2011,10 +3312,16 @@ if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2025,30 +3332,48 @@ if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *GetResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Process != nil { l = m.Process.Size() n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListTasksRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Filter) if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListTasksResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Tasks) > 0 { @@ -2057,10 +3382,16 @@ n += 1 + l + sovTasks(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *KillRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2077,10 +3408,16 @@ if m.All { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2110,16 +3447,28 @@ if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ResizePtyRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2136,10 +3485,16 @@ if m.Height != 0 { n += 1 + sovTasks(uint64(m.Height)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CloseIORequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2153,40 +3508,64 @@ if m.Stdin { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PauseTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ResumeTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListPidsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListPidsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Processes) > 0 { @@ -2195,10 +3574,16 @@ n += 1 + l + sovTasks(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2213,10 +3598,16 @@ l = m.Options.Size() n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointTaskResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Descriptors) > 0 { @@ -2225,10 +3616,16 @@ n += 1 + l + sovTasks(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2239,10 +3636,24 @@ l = m.Resources.Size() n += 1 + l + sovTasks(uint64(l)) } + if len(m.Annotations) > 0 { + for k, v := range m.Annotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovTasks(uint64(len(k))) + 1 + len(v) + sovTasks(uint64(len(v))) + n += mapEntrySize + 1 + sovTasks(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *MetricsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Filters) > 0 { @@ -2251,10 +3662,16 @@ n += 1 + l + sovTasks(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *MetricsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Metrics) > 0 { @@ -2263,10 +3680,16 @@ n += 1 + l + sovTasks(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -2277,29 +3700,31 @@ if l > 0 { n += 1 + l + sovTasks(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ExitStatus != 0 { n += 1 + sovTasks(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovTasks(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovTasks(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozTasks(x uint64) (n int) { return sovTasks(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -2308,15 +3733,21 @@ if this == nil { return "nil" } + repeatedStringForRootfs := "[]*Mount{" + for _, f := range this.Rootfs { + repeatedStringForRootfs += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForRootfs += "}" s := strings.Join([]string{`&CreateTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, - `Rootfs:` + strings.Replace(fmt.Sprintf("%v", this.Rootfs), "Mount", "containerd_types.Mount", 1) + `,`, + `Rootfs:` + repeatedStringForRootfs + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, - `Checkpoint:` + strings.Replace(fmt.Sprintf("%v", this.Checkpoint), "Descriptor", "containerd_types2.Descriptor", 1) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf1.Any", 1) + `,`, + `Checkpoint:` + strings.Replace(fmt.Sprintf("%v", this.Checkpoint), "Descriptor", "types.Descriptor", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2328,6 +3759,7 @@ s := strings.Join([]string{`&CreateTaskResponse{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2339,6 +3771,7 @@ s := strings.Join([]string{`&StartRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2349,6 +3782,7 @@ } s := strings.Join([]string{`&StartResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2359,6 +3793,7 @@ } s := strings.Join([]string{`&DeleteTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2371,7 +3806,8 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2383,6 +3819,7 @@ s := strings.Join([]string{`&DeleteProcessRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2394,6 +3831,7 @@ s := strings.Join([]string{`&GetRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2403,7 +3841,8 @@ return "nil" } s := strings.Join([]string{`&GetResponse{`, - `Process:` + strings.Replace(fmt.Sprintf("%v", this.Process), "Process", "containerd_v1_types.Process", 1) + `,`, + `Process:` + strings.Replace(fmt.Sprintf("%v", this.Process), "Process", "task.Process", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2414,6 +3853,7 @@ } s := strings.Join([]string{`&ListTasksRequest{`, `Filter:` + fmt.Sprintf("%v", this.Filter) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2422,8 +3862,14 @@ if this == nil { return "nil" } + repeatedStringForTasks := "[]*Process{" + for _, f := range this.Tasks { + repeatedStringForTasks += strings.Replace(fmt.Sprintf("%v", f), "Process", "task.Process", 1) + "," + } + repeatedStringForTasks += "}" s := strings.Join([]string{`&ListTasksResponse{`, - `Tasks:` + strings.Replace(fmt.Sprintf("%v", this.Tasks), "Process", "containerd_v1_types.Process", 1) + `,`, + `Tasks:` + repeatedStringForTasks + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2437,6 +3883,7 @@ `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Signal:` + fmt.Sprintf("%v", this.Signal) + `,`, `All:` + fmt.Sprintf("%v", this.All) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2451,8 +3898,9 @@ `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, - `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf1.Any", 1) + `,`, + `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "types1.Any", 1) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2462,6 +3910,7 @@ return "nil" } s := strings.Join([]string{`&ExecProcessResponse{`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2475,6 +3924,7 @@ `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Width:` + fmt.Sprintf("%v", this.Width) + `,`, `Height:` + fmt.Sprintf("%v", this.Height) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2487,6 +3937,7 @@ `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2497,6 +3948,7 @@ } s := strings.Join([]string{`&PauseTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2507,6 +3959,7 @@ } s := strings.Join([]string{`&ResumeTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2517,6 +3970,7 @@ } s := strings.Join([]string{`&ListPidsRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2525,8 +3979,14 @@ if this == nil { return "nil" } + repeatedStringForProcesses := "[]*ProcessInfo{" + for _, f := range this.Processes { + repeatedStringForProcesses += strings.Replace(fmt.Sprintf("%v", f), "ProcessInfo", "task.ProcessInfo", 1) + "," + } + repeatedStringForProcesses += "}" s := strings.Join([]string{`&ListPidsResponse{`, - `Processes:` + strings.Replace(fmt.Sprintf("%v", this.Processes), "ProcessInfo", "containerd_v1_types.ProcessInfo", 1) + `,`, + `Processes:` + repeatedStringForProcesses + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2538,7 +3998,8 @@ s := strings.Join([]string{`&CheckpointTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ParentCheckpoint:` + fmt.Sprintf("%v", this.ParentCheckpoint) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf1.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2547,8 +4008,14 @@ if this == nil { return "nil" } + repeatedStringForDescriptors := "[]*Descriptor{" + for _, f := range this.Descriptors { + repeatedStringForDescriptors += strings.Replace(fmt.Sprintf("%v", f), "Descriptor", "types.Descriptor", 1) + "," + } + repeatedStringForDescriptors += "}" s := strings.Join([]string{`&CheckpointTaskResponse{`, - `Descriptors:` + strings.Replace(fmt.Sprintf("%v", this.Descriptors), "Descriptor", "containerd_types2.Descriptor", 1) + `,`, + `Descriptors:` + repeatedStringForDescriptors + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2557,9 +4024,21 @@ if this == nil { return "nil" } + keysForAnnotations := make([]string, 0, len(this.Annotations)) + for k, _ := range this.Annotations { + keysForAnnotations = append(keysForAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + mapStringForAnnotations := "map[string]string{" + for _, k := range keysForAnnotations { + mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k]) + } + mapStringForAnnotations += "}" s := strings.Join([]string{`&UpdateTaskRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, - `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "google_protobuf1.Any", 1) + `,`, + `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "types1.Any", 1) + `,`, + `Annotations:` + mapStringForAnnotations + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2570,6 +4049,7 @@ } s := strings.Join([]string{`&MetricsRequest{`, `Filters:` + fmt.Sprintf("%v", this.Filters) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2578,8 +4058,14 @@ if this == nil { return "nil" } + repeatedStringForMetrics := "[]*Metric{" + for _, f := range this.Metrics { + repeatedStringForMetrics += strings.Replace(fmt.Sprintf("%v", f), "Metric", "types.Metric", 1) + "," + } + repeatedStringForMetrics += "}" s := strings.Join([]string{`&MetricsResponse{`, - `Metrics:` + strings.Replace(fmt.Sprintf("%v", this.Metrics), "Metric", "containerd_types1.Metric", 1) + `,`, + `Metrics:` + repeatedStringForMetrics + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2591,6 +4077,7 @@ s := strings.Join([]string{`&WaitRequest{`, `ContainerID:` + fmt.Sprintf("%v", this.ContainerID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2601,7 +4088,8 @@ } s := strings.Join([]string{`&WaitResponse{`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2629,7 +4117,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2657,7 +4145,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2667,6 +4155,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2686,7 +4177,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2695,10 +4186,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Rootfs = append(m.Rootfs, &containerd_types.Mount{}) + m.Rootfs = append(m.Rootfs, &types.Mount{}) if err := m.Rootfs[len(m.Rootfs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2717,7 +4211,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2727,6 +4221,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2746,7 +4243,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2756,6 +4253,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2775,7 +4275,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2785,6 +4285,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2804,7 +4307,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2824,7 +4327,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2833,11 +4336,14 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Checkpoint == nil { - m.Checkpoint = &containerd_types2.Descriptor{} + m.Checkpoint = &types.Descriptor{} } if err := m.Checkpoint.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2857,7 +4363,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2866,11 +4372,14 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf1.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2882,12 +4391,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2912,7 +4422,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2940,7 +4450,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2950,6 +4460,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2969,7 +4482,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2980,12 +4493,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3010,7 +4524,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3038,7 +4552,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3048,6 +4562,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3067,7 +4584,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3077,6 +4594,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3088,12 +4608,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3118,7 +4639,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3146,7 +4667,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3157,12 +4678,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3187,7 +4709,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3215,7 +4737,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3225,6 +4747,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3236,12 +4761,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3266,7 +4792,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3294,7 +4820,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3304,6 +4830,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3323,7 +4852,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3342,7 +4871,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3361,7 +4890,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3370,10 +4899,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3383,12 +4915,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3413,7 +4946,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3441,7 +4974,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3451,6 +4984,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3470,7 +5006,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3480,6 +5016,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3491,12 +5030,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3521,7 +5061,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3549,7 +5089,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3559,6 +5099,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3578,7 +5121,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3588,6 +5131,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3599,12 +5145,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3629,7 +5176,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3657,7 +5204,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3666,11 +5213,14 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Process == nil { - m.Process = &containerd_v1_types.Process{} + m.Process = &task.Process{} } if err := m.Process.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3682,12 +5232,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3712,7 +5263,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3740,7 +5291,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3750,6 +5301,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3761,12 +5315,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3791,7 +5346,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3819,7 +5374,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3828,10 +5383,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Tasks = append(m.Tasks, &containerd_v1_types.Process{}) + m.Tasks = append(m.Tasks, &task.Process{}) if err := m.Tasks[len(m.Tasks)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -3842,12 +5400,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3872,7 +5431,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3900,7 +5459,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3910,6 +5469,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3929,7 +5491,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3939,6 +5501,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3958,7 +5523,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Signal |= (uint32(b) & 0x7F) << shift + m.Signal |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3977,7 +5542,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3989,12 +5554,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4019,7 +5585,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4047,7 +5613,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4057,6 +5623,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4076,7 +5645,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4086,6 +5655,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4105,7 +5677,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4115,6 +5687,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4134,7 +5709,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4144,6 +5719,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4163,7 +5741,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4183,7 +5761,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4192,11 +5770,14 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Spec == nil { - m.Spec = &google_protobuf1.Any{} + m.Spec = &types1.Any{} } if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -4216,7 +5797,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4226,6 +5807,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4237,12 +5821,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4267,7 +5852,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4287,12 +5872,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4317,7 +5903,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4345,7 +5931,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4355,6 +5941,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4374,7 +5963,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4384,6 +5973,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4403,7 +5995,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Width |= (uint32(b) & 0x7F) << shift + m.Width |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4422,7 +6014,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Height |= (uint32(b) & 0x7F) << shift + m.Height |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4433,12 +6025,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4463,7 +6056,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4491,7 +6084,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4501,6 +6094,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4520,7 +6116,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4530,6 +6126,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4549,7 +6148,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4561,12 +6160,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4591,7 +6191,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4619,7 +6219,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4629,6 +6229,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4640,12 +6243,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4670,7 +6274,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4698,7 +6302,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4708,6 +6312,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4719,12 +6326,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4749,7 +6357,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4777,7 +6385,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4787,6 +6395,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4798,12 +6409,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4828,7 +6440,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4856,7 +6468,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4865,10 +6477,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Processes = append(m.Processes, &containerd_v1_types.ProcessInfo{}) + m.Processes = append(m.Processes, &task.ProcessInfo{}) if err := m.Processes[len(m.Processes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4879,12 +6494,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4909,7 +6525,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4937,7 +6553,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4947,6 +6563,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4966,7 +6585,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4976,6 +6595,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4995,7 +6617,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5004,11 +6626,14 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf1.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -5020,12 +6645,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5050,7 +6676,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5078,7 +6704,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5087,10 +6713,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Descriptors = append(m.Descriptors, &containerd_types2.Descriptor{}) + m.Descriptors = append(m.Descriptors, &types.Descriptor{}) if err := m.Descriptors[len(m.Descriptors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -5101,12 +6730,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5131,7 +6761,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5159,7 +6789,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5169,6 +6799,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5188,7 +6821,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5197,28 +6830,159 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Resources == nil { - m.Resources = &google_protobuf1.Any{} + m.Resources = &types1.Any{} } if err := m.Resources.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTasks + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTasks + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Annotations == nil { + m.Annotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTasks + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTasks + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthTasks + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthTasks + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTasks + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthTasks + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthTasks + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipTasks(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTasks + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Annotations[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTasks(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5243,7 +7007,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5271,7 +7035,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5281,6 +7045,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5292,12 +7059,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5322,7 +7090,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5350,7 +7118,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5359,10 +7127,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Metrics = append(m.Metrics, &containerd_types1.Metric{}) + m.Metrics = append(m.Metrics, &types.Metric{}) if err := m.Metrics[len(m.Metrics)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -5373,12 +7144,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5403,7 +7175,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5431,7 +7203,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5441,6 +7213,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5460,7 +7235,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5470,6 +7245,9 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5481,12 +7259,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5511,7 +7290,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5539,7 +7318,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -5558,7 +7337,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5567,10 +7346,13 @@ return ErrInvalidLengthTasks } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTasks + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -5580,12 +7362,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTasks } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5598,6 +7381,7 @@ func skipTasks(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -5629,10 +7413,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -5649,144 +7431,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthTasks } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTasks - } - 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 := skipTasks(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTasks + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthTasks + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthTasks = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTasks = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthTasks = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTasks = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTasks = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/tasks/v1/tasks.proto", fileDescriptorTasks) -} - -var fileDescriptorTasks = []byte{ - // 1318 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x6f, 0x1b, 0x45, - 0x1c, 0xef, 0xfa, 0xed, 0xbf, 0x93, 0x36, 0x59, 0xd2, 0x60, 0x96, 0x2a, 0x0e, 0xcb, 0xc5, 0x04, - 0xba, 0x4b, 0x5d, 0x54, 0x21, 0x5a, 0x21, 0x35, 0x0f, 0x22, 0x0b, 0xaa, 0xa6, 0xdb, 0x02, 0x55, - 0x25, 0x14, 0xb6, 0xbb, 0x13, 0x67, 0x14, 0x7b, 0x67, 0xbb, 0x33, 0x4e, 0x1b, 0x38, 0xc0, 0x47, - 0xe8, 0x95, 0x0b, 0x9f, 0x27, 0x47, 0x8e, 0x08, 0x55, 0x81, 0xfa, 0x5b, 0x70, 0x43, 0xf3, 0xd8, - 0xcd, 0xc6, 0x8e, 0xbd, 0x4e, 0xd3, 0x70, 0x69, 0x67, 0x66, 0xff, 0xaf, 0xf9, 0xcd, 0xff, 0xf1, - 0x73, 0x60, 0xb5, 0x83, 0xd9, 0x6e, 0xff, 0xa9, 0xe5, 0x91, 0x9e, 0xed, 0x91, 0x80, 0xb9, 0x38, - 0x40, 0x91, 0x9f, 0x5e, 0xba, 0x21, 0xb6, 0x29, 0x8a, 0xf6, 0xb1, 0x87, 0xa8, 0xcd, 0x5c, 0xba, - 0x47, 0xed, 0xfd, 0x1b, 0x72, 0x61, 0x85, 0x11, 0x61, 0x44, 0xbf, 0x76, 0x2c, 0x6d, 0xc5, 0x92, - 0x96, 0x14, 0xd8, 0xbf, 0x61, 0xbc, 0xdf, 0x21, 0xa4, 0xd3, 0x45, 0xb6, 0x90, 0x7d, 0xda, 0xdf, - 0xb1, 0x51, 0x2f, 0x64, 0x07, 0x52, 0xd5, 0x78, 0x6f, 0xf8, 0xa3, 0x1b, 0xc4, 0x9f, 0x16, 0x3a, - 0xa4, 0x43, 0xc4, 0xd2, 0xe6, 0x2b, 0x75, 0x7a, 0x6b, 0xaa, 0x78, 0xd9, 0x41, 0x88, 0xa8, 0xdd, - 0x23, 0xfd, 0x80, 0x29, 0xbd, 0xcf, 0xcf, 0xa2, 0x87, 0x58, 0x84, 0x3d, 0x75, 0x3b, 0xe3, 0xf6, - 0x19, 0x34, 0x7d, 0x44, 0xbd, 0x08, 0x87, 0x8c, 0x44, 0x4a, 0xf9, 0x8b, 0x33, 0x28, 0x73, 0xc4, - 0xc4, 0x3f, 0x4a, 0xb7, 0x31, 0x8c, 0x0d, 0xc3, 0x3d, 0x44, 0x99, 0xdb, 0x0b, 0xa5, 0x80, 0x79, - 0x98, 0x83, 0xf9, 0xb5, 0x08, 0xb9, 0x0c, 0x3d, 0x72, 0xe9, 0x9e, 0x83, 0x9e, 0xf5, 0x11, 0x65, - 0x7a, 0x0b, 0x66, 0x12, 0xf3, 0xdb, 0xd8, 0xaf, 0x6b, 0xcb, 0x5a, 0xb3, 0xba, 0x7a, 0x65, 0x70, - 0xd4, 0xa8, 0xad, 0xc5, 0xe7, 0xed, 0x75, 0xa7, 0x96, 0x08, 0xb5, 0x7d, 0xdd, 0x86, 0x52, 0x44, - 0x08, 0xdb, 0xa1, 0xf5, 0xfc, 0x72, 0xbe, 0x59, 0x6b, 0xbd, 0x6b, 0xa5, 0x9e, 0x54, 0x44, 0x67, - 0xdd, 0xe3, 0x60, 0x3a, 0x4a, 0x4c, 0x5f, 0x80, 0x22, 0x65, 0x3e, 0x0e, 0xea, 0x05, 0x6e, 0xdd, - 0x91, 0x1b, 0x7d, 0x11, 0x4a, 0x94, 0xf9, 0xa4, 0xcf, 0xea, 0x45, 0x71, 0xac, 0x76, 0xea, 0x1c, - 0x45, 0x51, 0xbd, 0x94, 0x9c, 0xa3, 0x28, 0xd2, 0x0d, 0xa8, 0x30, 0x14, 0xf5, 0x70, 0xe0, 0x76, - 0xeb, 0xe5, 0x65, 0xad, 0x59, 0x71, 0x92, 0xbd, 0x7e, 0x07, 0xc0, 0xdb, 0x45, 0xde, 0x5e, 0x48, - 0x70, 0xc0, 0xea, 0x95, 0x65, 0xad, 0x59, 0x6b, 0x5d, 0x1b, 0x0d, 0x6b, 0x3d, 0x41, 0xdc, 0x49, - 0xc9, 0xeb, 0x16, 0x94, 0x49, 0xc8, 0x30, 0x09, 0x68, 0xbd, 0x2a, 0x54, 0x17, 0x2c, 0x89, 0xa6, - 0x15, 0xa3, 0x69, 0xdd, 0x0d, 0x0e, 0x9c, 0x58, 0xc8, 0x7c, 0x02, 0x7a, 0x1a, 0x49, 0x1a, 0x92, - 0x80, 0xa2, 0x37, 0x82, 0x72, 0x0e, 0xf2, 0x21, 0xf6, 0xeb, 0xb9, 0x65, 0xad, 0x39, 0xeb, 0xf0, - 0xa5, 0xd9, 0x81, 0x99, 0x87, 0xcc, 0x8d, 0xd8, 0x79, 0x1e, 0xe8, 0x43, 0x28, 0xa3, 0x17, 0xc8, - 0xdb, 0x56, 0x96, 0xab, 0xab, 0x30, 0x38, 0x6a, 0x94, 0x36, 0x5e, 0x20, 0xaf, 0xbd, 0xee, 0x94, - 0xf8, 0xa7, 0xb6, 0x6f, 0x7e, 0x00, 0xb3, 0xca, 0x91, 0x8a, 0x5f, 0xc5, 0xa2, 0x1d, 0xc7, 0xb2, - 0x09, 0xf3, 0xeb, 0xa8, 0x8b, 0xce, 0x9d, 0x31, 0xe6, 0xef, 0x1a, 0x5c, 0x96, 0x96, 0x12, 0x6f, - 0x8b, 0x90, 0x4b, 0x94, 0x4b, 0x83, 0xa3, 0x46, 0xae, 0xbd, 0xee, 0xe4, 0xf0, 0x29, 0x88, 0xe8, - 0x0d, 0xa8, 0xa1, 0x17, 0x98, 0x6d, 0x53, 0xe6, 0xb2, 0x3e, 0xcf, 0x39, 0xfe, 0x05, 0xf8, 0xd1, - 0x43, 0x71, 0xa2, 0xdf, 0x85, 0x2a, 0xdf, 0x21, 0x7f, 0xdb, 0x65, 0x22, 0xc5, 0x6a, 0x2d, 0x63, - 0xe4, 0x01, 0x1f, 0xc5, 0xe5, 0xb0, 0x5a, 0x39, 0x3c, 0x6a, 0x5c, 0x7a, 0xf9, 0x77, 0x43, 0x73, - 0x2a, 0x52, 0xed, 0x2e, 0x33, 0x09, 0x2c, 0xc8, 0xf8, 0xb6, 0x22, 0xe2, 0x21, 0x4a, 0x2f, 0x1c, - 0x7d, 0x04, 0xb0, 0x89, 0x2e, 0xfe, 0x91, 0x37, 0xa0, 0x26, 0xdc, 0x28, 0xd0, 0x6f, 0x41, 0x39, - 0x94, 0x17, 0x14, 0x2e, 0x86, 0x6a, 0x64, 0xff, 0x86, 0x2a, 0x93, 0x18, 0x84, 0x58, 0xd8, 0x5c, - 0x81, 0xb9, 0x6f, 0x30, 0x65, 0x3c, 0x0d, 0x12, 0x68, 0x16, 0xa1, 0xb4, 0x83, 0xbb, 0x0c, 0x45, - 0x32, 0x5a, 0x47, 0xed, 0x78, 0xd2, 0xa4, 0x64, 0x93, 0xda, 0x28, 0x8a, 0x16, 0x5f, 0xd7, 0x44, - 0xc7, 0x98, 0xec, 0x56, 0x8a, 0x9a, 0x2f, 0x35, 0xa8, 0x7d, 0x8d, 0xbb, 0xdd, 0x8b, 0x06, 0x49, - 0x34, 0x1c, 0xdc, 0xe1, 0x6d, 0x45, 0xe6, 0x96, 0xda, 0xf1, 0x54, 0x74, 0xbb, 0x5d, 0x91, 0x51, - 0x15, 0x87, 0x2f, 0xcd, 0x7f, 0x35, 0xd0, 0xb9, 0xf2, 0x5b, 0xc8, 0x92, 0xa4, 0x27, 0xe6, 0x4e, - 0xef, 0x89, 0xf9, 0x31, 0x3d, 0xb1, 0x30, 0xb6, 0x27, 0x16, 0x87, 0x7a, 0x62, 0x13, 0x0a, 0x34, - 0x44, 0x9e, 0xe8, 0xa2, 0xe3, 0x5a, 0x9a, 0x90, 0x48, 0xa3, 0x54, 0x1e, 0x9b, 0x4a, 0x57, 0xe1, - 0x9d, 0x13, 0x57, 0x97, 0x2f, 0x6b, 0xfe, 0xa6, 0xc1, 0x9c, 0x83, 0x28, 0xfe, 0x09, 0x6d, 0xb1, - 0x83, 0x0b, 0x7f, 0xaa, 0x05, 0x28, 0x3e, 0xc7, 0x3e, 0xdb, 0x55, 0x2f, 0x25, 0x37, 0x1c, 0x9d, - 0x5d, 0x84, 0x3b, 0xbb, 0xb2, 0xfa, 0x67, 0x1d, 0xb5, 0x33, 0x7f, 0x81, 0xcb, 0x6b, 0x5d, 0x42, - 0x51, 0xfb, 0xfe, 0xff, 0x11, 0x98, 0x7c, 0xce, 0xbc, 0x78, 0x05, 0xb9, 0x31, 0xbf, 0x82, 0xb9, - 0x2d, 0xb7, 0x4f, 0xcf, 0xdd, 0x3f, 0x37, 0x61, 0xde, 0x41, 0xb4, 0xdf, 0x3b, 0xb7, 0xa1, 0x0d, - 0xb8, 0xc2, 0x8b, 0x73, 0x0b, 0xfb, 0xe7, 0x49, 0x5e, 0xd3, 0x91, 0xfd, 0x40, 0x9a, 0x51, 0x25, - 0xfe, 0x25, 0x54, 0x55, 0xbb, 0x40, 0x71, 0x99, 0x2f, 0x4f, 0x2a, 0xf3, 0x76, 0xb0, 0x43, 0x9c, - 0x63, 0x15, 0xf3, 0x95, 0x06, 0x57, 0xd7, 0x92, 0x99, 0x7c, 0x5e, 0x8e, 0xb2, 0x0d, 0xf3, 0xa1, - 0x1b, 0xa1, 0x80, 0x6d, 0xa7, 0x78, 0x81, 0x7c, 0xbe, 0x16, 0xef, 0xff, 0x7f, 0x1d, 0x35, 0x56, - 0x52, 0x6c, 0x8b, 0x84, 0x28, 0x48, 0xd4, 0xa9, 0xdd, 0x21, 0xd7, 0x7d, 0xdc, 0x41, 0x94, 0x59, - 0xeb, 0xe2, 0x3f, 0x67, 0x4e, 0x1a, 0x5b, 0x3b, 0x95, 0x33, 0xe4, 0xa7, 0xe1, 0x0c, 0x8f, 0x61, - 0x71, 0xf8, 0x76, 0x09, 0x70, 0xb5, 0x63, 0x26, 0x78, 0x6a, 0x87, 0x1c, 0x21, 0x2f, 0x69, 0x05, - 0xf3, 0x67, 0x98, 0xff, 0x36, 0xf4, 0xdf, 0x02, 0xaf, 0x6b, 0x41, 0x35, 0x42, 0x94, 0xf4, 0x23, - 0x0f, 0x51, 0x81, 0xd5, 0xb8, 0x4b, 0x1d, 0x8b, 0x99, 0x2b, 0x70, 0xf9, 0x9e, 0x24, 0xc0, 0xb1, - 0xe7, 0x3a, 0x94, 0xe5, 0x24, 0x90, 0x57, 0xa9, 0x3a, 0xf1, 0x96, 0x27, 0x5f, 0x22, 0x9b, 0xcc, - 0x85, 0xb2, 0xe2, 0xcf, 0xea, 0xde, 0xf5, 0x53, 0xb8, 0xa4, 0x10, 0x70, 0x62, 0x41, 0x73, 0x07, - 0x6a, 0xdf, 0xbb, 0xf8, 0xe2, 0x67, 0x67, 0x04, 0x33, 0xd2, 0x8f, 0x8a, 0x75, 0x88, 0x87, 0x68, - 0x93, 0x79, 0x48, 0xee, 0x4d, 0x78, 0x48, 0xeb, 0xd5, 0x0c, 0x14, 0xc5, 0xe4, 0xd4, 0xf7, 0xa0, - 0x24, 0x39, 0xa6, 0x6e, 0x5b, 0x93, 0x7e, 0x31, 0x59, 0x23, 0x9c, 0xde, 0xf8, 0x74, 0x7a, 0x05, - 0x75, 0xb5, 0x1f, 0xa1, 0x28, 0xb8, 0xa0, 0xbe, 0x32, 0x59, 0x35, 0xcd, 0x4c, 0x8d, 0x8f, 0xa7, - 0x92, 0x55, 0x1e, 0x3a, 0x50, 0x92, 0x04, 0x2b, 0xeb, 0x3a, 0x23, 0x84, 0xd3, 0xf8, 0x64, 0x1a, - 0x85, 0xc4, 0xd1, 0x33, 0x98, 0x3d, 0xc1, 0xe4, 0xf4, 0xd6, 0x34, 0xea, 0x27, 0x07, 0xfa, 0x19, - 0x5d, 0x3e, 0x81, 0xfc, 0x26, 0x62, 0x7a, 0x73, 0xb2, 0xd2, 0x31, 0xdd, 0x33, 0x3e, 0x9a, 0x42, - 0x32, 0xc1, 0xad, 0xc0, 0x3b, 0xad, 0x6e, 0x4d, 0x56, 0x19, 0x66, 0x67, 0x86, 0x3d, 0xb5, 0xbc, - 0x72, 0xd4, 0x86, 0x02, 0x27, 0x5b, 0x7a, 0x46, 0x6c, 0x29, 0x42, 0x66, 0x2c, 0x8e, 0x24, 0xf7, - 0x06, 0xff, 0xb1, 0xae, 0x6f, 0x41, 0x81, 0x97, 0x92, 0x9e, 0x91, 0x87, 0xa3, 0x44, 0x6a, 0xac, - 0xc5, 0x87, 0x50, 0x4d, 0x38, 0x46, 0x16, 0x14, 0xc3, 0x64, 0x64, 0xac, 0xd1, 0xfb, 0x50, 0x56, - 0xec, 0x40, 0xcf, 0x78, 0xef, 0x93, 0x24, 0x62, 0x82, 0xc1, 0xa2, 0x98, 0xf6, 0x59, 0x11, 0x0e, - 0x53, 0x82, 0xb1, 0x06, 0x1f, 0x40, 0x49, 0x8e, 0xfd, 0xac, 0xa2, 0x19, 0x21, 0x07, 0x63, 0x4d, - 0x62, 0xa8, 0xc4, 0x93, 0x5b, 0xbf, 0x9e, 0x9d, 0x23, 0x29, 0xa2, 0x60, 0x58, 0xd3, 0x8a, 0xab, - 0x8c, 0x7a, 0x0e, 0x90, 0x9a, 0x97, 0x37, 0x33, 0x20, 0x3e, 0x6d, 0xf2, 0x1b, 0x9f, 0x9d, 0x4d, - 0x49, 0x39, 0x7e, 0x00, 0x25, 0x39, 0x10, 0xb3, 0x60, 0x1b, 0x19, 0x9b, 0x63, 0x61, 0xdb, 0x81, - 0xb2, 0x1a, 0x5d, 0x59, 0xb9, 0x72, 0x72, 0x1a, 0x1a, 0xd7, 0xa7, 0x94, 0x56, 0xa1, 0xff, 0x00, - 0x05, 0x3e, 0x73, 0xb2, 0xaa, 0x30, 0x35, 0xff, 0x8c, 0x95, 0x69, 0x44, 0xa5, 0xf9, 0xd5, 0xef, - 0x0e, 0x5f, 0x2f, 0x5d, 0xfa, 0xf3, 0xf5, 0xd2, 0xa5, 0x5f, 0x07, 0x4b, 0xda, 0xe1, 0x60, 0x49, - 0xfb, 0x63, 0xb0, 0xa4, 0xfd, 0x33, 0x58, 0xd2, 0x9e, 0xdc, 0x79, 0xb3, 0xbf, 0xec, 0xdd, 0x16, - 0x8b, 0xc7, 0xb9, 0xa7, 0x25, 0x01, 0xd8, 0xcd, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x85, 0xa2, - 0x4f, 0xd1, 0x22, 0x14, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/tasks/v1/tasks.proto containerd-1.5.9/api/services/tasks/v1/tasks.proto --- containerd-1.2.6/api/services/tasks/v1/tasks.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/tasks/v1/tasks.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.tasks.v1; @@ -188,6 +204,7 @@ message UpdateTaskRequest { string container_id = 1; google.protobuf.Any resources = 2; + map annotations = 3; } message MetricsRequest { diff -Nru containerd-1.2.6/api/services/ttrpc/events/v1/doc.go containerd-1.5.9/api/services/ttrpc/events/v1/doc.go --- containerd-1.2.6/api/services/ttrpc/events/v1/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/api/services/ttrpc/events/v1/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package events defines the event pushing and subscription service. +package events diff -Nru containerd-1.2.6/api/services/ttrpc/events/v1/events.pb.go containerd-1.5.9/api/services/ttrpc/events/v1/events.pb.go --- containerd-1.2.6/api/services/ttrpc/events/v1/events.pb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/api/services/ttrpc/events/v1/events.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,760 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/ttrpc/events/v1/events.proto + +package events + +import ( + context "context" + fmt "fmt" + github_com_containerd_ttrpc "github.com/containerd/ttrpc" + github_com_containerd_typeurl "github.com/containerd/typeurl" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ForwardRequest struct { + Envelope *Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ForwardRequest) Reset() { *m = ForwardRequest{} } +func (*ForwardRequest) ProtoMessage() {} +func (*ForwardRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_19f98672016720b5, []int{0} +} +func (m *ForwardRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForwardRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForwardRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ForwardRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardRequest.Merge(m, src) +} +func (m *ForwardRequest) XXX_Size() int { + return m.Size() +} +func (m *ForwardRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ForwardRequest proto.InternalMessageInfo + +type Envelope struct { + Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` + Event *types.Any `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Envelope) Reset() { *m = Envelope{} } +func (*Envelope) ProtoMessage() {} +func (*Envelope) Descriptor() ([]byte, []int) { + return fileDescriptor_19f98672016720b5, []int{1} +} +func (m *Envelope) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Envelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Envelope.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Envelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_Envelope.Merge(m, src) +} +func (m *Envelope) XXX_Size() int { + return m.Size() +} +func (m *Envelope) XXX_DiscardUnknown() { + xxx_messageInfo_Envelope.DiscardUnknown(m) +} + +var xxx_messageInfo_Envelope proto.InternalMessageInfo + +func init() { + proto.RegisterType((*ForwardRequest)(nil), "containerd.services.events.ttrpc.v1.ForwardRequest") + proto.RegisterType((*Envelope)(nil), "containerd.services.events.ttrpc.v1.Envelope") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/ttrpc/events/v1/events.proto", fileDescriptor_19f98672016720b5) +} + +var fileDescriptor_19f98672016720b5 = []byte{ + // 396 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0xc1, 0x8e, 0xd3, 0x30, + 0x10, 0x8d, 0x61, 0x77, 0x69, 0x8d, 0xc4, 0xc1, 0xaa, 0x50, 0x08, 0x28, 0x59, 0x2d, 0x97, 0x15, + 0x12, 0xb6, 0x76, 0xf7, 0x06, 0x17, 0xa8, 0x28, 0x12, 0x1c, 0x23, 0x84, 0x2a, 0x90, 0x10, 0x6e, + 0x3a, 0x4d, 0x2d, 0x25, 0xb6, 0x49, 0x9c, 0xa0, 0xde, 0xfa, 0x09, 0x7c, 0x0c, 0x17, 0xfe, 0xa0, + 0x47, 0x8e, 0x9c, 0x80, 0xe6, 0x4b, 0x50, 0x9d, 0xa4, 0x81, 0xf6, 0x40, 0xa5, 0xbd, 0xbd, 0xcc, + 0x7b, 0x6f, 0xde, 0xcc, 0xc4, 0xf8, 0x75, 0x2c, 0xcc, 0xbc, 0x98, 0xd0, 0x48, 0xa5, 0x2c, 0x52, + 0xd2, 0x70, 0x21, 0x21, 0x9b, 0xfe, 0x0d, 0xb9, 0x16, 0x2c, 0x87, 0xac, 0x14, 0x11, 0xe4, 0xcc, + 0x98, 0x4c, 0x47, 0x0c, 0x4a, 0x90, 0x26, 0x67, 0xe5, 0x45, 0x83, 0xa8, 0xce, 0x94, 0x51, 0xe4, + 0x61, 0xe7, 0xa2, 0xad, 0x83, 0x36, 0x0a, 0x6b, 0xa4, 0xe5, 0x85, 0xf7, 0xec, 0xbf, 0x81, 0xb6, + 0xd9, 0xa4, 0x98, 0x31, 0x9d, 0x14, 0xb1, 0x90, 0x6c, 0x26, 0x20, 0x99, 0x6a, 0x6e, 0xe6, 0x75, + 0x8c, 0x37, 0x88, 0x55, 0xac, 0x2c, 0x64, 0x1b, 0xd4, 0x54, 0xef, 0xc5, 0x4a, 0xc5, 0x09, 0x74, + 0x6e, 0x2e, 0x17, 0x0d, 0x75, 0x7f, 0x97, 0x82, 0x54, 0x9b, 0x96, 0x0c, 0x76, 0x49, 0x23, 0x52, + 0xc8, 0x0d, 0x4f, 0x75, 0x2d, 0x38, 0x7b, 0x8f, 0xef, 0xbc, 0x54, 0xd9, 0x67, 0x9e, 0x4d, 0x43, + 0xf8, 0x54, 0x40, 0x6e, 0xc8, 0x2b, 0xdc, 0x03, 0x59, 0x42, 0xa2, 0x34, 0xb8, 0xe8, 0x14, 0x9d, + 0xdf, 0xbe, 0x7c, 0x4c, 0x0f, 0x58, 0x9d, 0x8e, 0x1a, 0x53, 0xb8, 0xb5, 0x9f, 0x7d, 0x45, 0xb8, + 0xd7, 0x96, 0xc9, 0x10, 0xf7, 0xb7, 0xe1, 0x4d, 0x63, 0x8f, 0xd6, 0xe3, 0xd1, 0x76, 0x3c, 0xfa, + 0xa6, 0x55, 0x0c, 0x7b, 0xab, 0x9f, 0x81, 0xf3, 0xe5, 0x57, 0x80, 0xc2, 0xce, 0x46, 0x1e, 0xe0, + 0xbe, 0xe4, 0x29, 0xe4, 0x9a, 0x47, 0xe0, 0xde, 0x38, 0x45, 0xe7, 0xfd, 0xb0, 0x2b, 0x90, 0x01, + 0x3e, 0x36, 0x4a, 0x8b, 0xc8, 0xbd, 0x69, 0x99, 0xfa, 0x83, 0x3c, 0xc2, 0xc7, 0x76, 0x54, 0xf7, + 0xc8, 0x66, 0x0e, 0xf6, 0x32, 0x9f, 0xcb, 0x45, 0x58, 0x4b, 0x9e, 0x1c, 0x2d, 0xbf, 0x05, 0xe8, + 0xf2, 0x23, 0x3e, 0x19, 0xd9, 0xe5, 0xc8, 0x5b, 0x7c, 0xab, 0xb9, 0x0e, 0xb9, 0x3a, 0xe8, 0x08, + 0xff, 0xde, 0xd2, 0xbb, 0xbb, 0x17, 0x36, 0xda, 0xfc, 0x9c, 0xe1, 0x87, 0xd5, 0xda, 0x77, 0x7e, + 0xac, 0x7d, 0x67, 0x59, 0xf9, 0x68, 0x55, 0xf9, 0xe8, 0x7b, 0xe5, 0xa3, 0xdf, 0x95, 0x8f, 0xde, + 0xbd, 0xb8, 0xd6, 0x8b, 0x7d, 0x5a, 0xa3, 0xb1, 0x33, 0x46, 0x93, 0x13, 0x9b, 0x79, 0xf5, 0x27, + 0x00, 0x00, 0xff, 0xff, 0xd4, 0x90, 0xbd, 0x09, 0x04, 0x03, 0x00, 0x00, +} + +// Field returns the value for the given fieldpath as a string, if defined. +// If the value is not defined, the second value will be false. +func (m *Envelope) Field(fieldpath []string) (string, bool) { + if len(fieldpath) == 0 { + return "", false + } + + switch fieldpath[0] { + // unhandled: timestamp + case "namespace": + return string(m.Namespace), len(m.Namespace) > 0 + case "topic": + return string(m.Topic), len(m.Topic) > 0 + case "event": + decoded, err := github_com_containerd_typeurl.UnmarshalAny(m.Event) + if err != nil { + return "", false + } + + adaptor, ok := decoded.(interface{ Field([]string) (string, bool) }) + if !ok { + return "", false + } + return adaptor.Field(fieldpath[1:]) + } + return "", false +} +func (m *ForwardRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ForwardRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForwardRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Envelope != nil { + { + size, err := m.Envelope.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Envelope) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Envelope) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Envelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Event != nil { + { + size, err := m.Event.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.Topic) > 0 { + i -= len(m.Topic) + copy(dAtA[i:], m.Topic) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Topic))) + i-- + dAtA[i] = 0x1a + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x12 + } + n3, err3 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintEvents(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ForwardRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Envelope != nil { + l = m.Envelope.Size() + n += 1 + l + sovEvents(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Envelope) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) + n += 1 + l + sovEvents(uint64(l)) + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.Topic) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if m.Event != nil { + l = m.Event.Size() + n += 1 + l + sovEvents(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *ForwardRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ForwardRequest{`, + `Envelope:` + strings.Replace(this.Envelope.String(), "Envelope", "Envelope", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *Envelope) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Envelope{`, + `Timestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Timestamp), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `Topic:` + fmt.Sprintf("%v", this.Topic) + `,`, + `Event:` + strings.Replace(fmt.Sprintf("%v", this.Event), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func valueToStringEvents(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} + +type EventsService interface { + Forward(ctx context.Context, req *ForwardRequest) (*types.Empty, error) +} + +func RegisterEventsService(srv *github_com_containerd_ttrpc.Server, svc EventsService) { + srv.Register("containerd.services.events.ttrpc.v1.Events", map[string]github_com_containerd_ttrpc.Method{ + "Forward": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ForwardRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Forward(ctx, &req) + }, + }) +} + +type eventsClient struct { + client *github_com_containerd_ttrpc.Client +} + +func NewEventsClient(client *github_com_containerd_ttrpc.Client) EventsService { + return &eventsClient{ + client: client, + } +} + +func (c *eventsClient) Forward(ctx context.Context, req *ForwardRequest) (*types.Empty, error) { + var resp types.Empty + if err := c.client.Call(ctx, "containerd.services.events.ttrpc.v1.Events", "Forward", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} +func (m *ForwardRequest) 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 ErrIntOverflowEvents + } + 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: ForwardRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ForwardRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Envelope", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Envelope == nil { + m.Envelope = &Envelope{} + } + if err := m.Envelope.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Envelope) 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 ErrIntOverflowEvents + } + 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: Envelope: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Envelope: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Topic", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Topic = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Event", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Event == nil { + m.Event = &types.Any{} + } + if err := m.Event.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + 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, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff -Nru containerd-1.2.6/api/services/ttrpc/events/v1/events.proto containerd-1.5.9/api/services/ttrpc/events/v1/events.proto --- containerd-1.2.6/api/services/ttrpc/events/v1/events.proto 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/api/services/ttrpc/events/v1/events.proto 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +syntax = "proto3"; + +package containerd.services.events.ttrpc.v1; + +import weak "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import weak "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/containerd/containerd/api/services/ttrpc/events/v1;events"; + +service Events { + // Forward sends an event that has already been packaged into an envelope + // with a timestamp and namespace. + // + // This is useful if earlier timestamping is required or when forwarding on + // behalf of another component, namespace or publisher. + rpc Forward(ForwardRequest) returns (google.protobuf.Empty); +} + +message ForwardRequest { + Envelope envelope = 1; +} + +message Envelope { + option (containerd.plugin.fieldpath) = true; + google.protobuf.Timestamp timestamp = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + string namespace = 2; + string topic = 3; + google.protobuf.Any event = 4; +} diff -Nru containerd-1.2.6/api/services/version/v1/version.pb.go containerd-1.5.9/api/services/version/v1/version.pb.go --- containerd-1.2.6/api/services/version/v1/version.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/version/v1/version.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,31 +1,22 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/services/version/v1/version.proto -/* - Package version is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/services/version/v1/version.proto - - It has these top-level messages: - VersionResponse -*/ package version -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/types" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import context "golang.org/x/net/context" -import grpc "google.golang.org/grpc" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + context "context" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + types "github.com/gogo/protobuf/types" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -36,21 +27,76 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type VersionResponse struct { - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` - Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VersionResponse) Reset() { *m = VersionResponse{} } +func (*VersionResponse) ProtoMessage() {} +func (*VersionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_128109001e578ffe, []int{0} +} +func (m *VersionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *VersionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_VersionResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *VersionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_VersionResponse.Merge(m, src) +} +func (m *VersionResponse) XXX_Size() int { + return m.Size() +} +func (m *VersionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_VersionResponse.DiscardUnknown(m) } -func (m *VersionResponse) Reset() { *m = VersionResponse{} } -func (*VersionResponse) ProtoMessage() {} -func (*VersionResponse) Descriptor() ([]byte, []int) { return fileDescriptorVersion, []int{0} } +var xxx_messageInfo_VersionResponse proto.InternalMessageInfo func init() { proto.RegisterType((*VersionResponse)(nil), "containerd.services.version.v1.VersionResponse") } +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/services/version/v1/version.proto", fileDescriptor_128109001e578ffe) +} + +var fileDescriptor_128109001e578ffe = []byte{ + // 243 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x4b, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x17, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x16, 0xeb, + 0x97, 0xa5, 0x16, 0x15, 0x67, 0xe6, 0xe7, 0xe9, 0x97, 0x19, 0xc2, 0x98, 0x7a, 0x05, 0x45, 0xf9, + 0x25, 0xf9, 0x42, 0x72, 0x08, 0x1d, 0x7a, 0x30, 0xd5, 0x7a, 0x30, 0x25, 0x65, 0x86, 0x52, 0xd2, + 0xe9, 0xf9, 0xf9, 0xe9, 0x39, 0xa9, 0xfa, 0x60, 0xd5, 0x49, 0xa5, 0x69, 0xfa, 0xa9, 0xb9, 0x05, + 0x25, 0x95, 0x10, 0xcd, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0xa6, 0x3e, 0x88, 0x05, 0x11, + 0x55, 0x72, 0xe7, 0xe2, 0x0f, 0x83, 0x18, 0x10, 0x94, 0x5a, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0x2a, + 0x24, 0xc1, 0xc5, 0x0e, 0x35, 0x53, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x15, 0x92, + 0xe2, 0xe2, 0x28, 0x4a, 0x2d, 0xcb, 0x04, 0x4b, 0x31, 0x81, 0xa5, 0xe0, 0x7c, 0xa3, 0x58, 0x2e, + 0x76, 0xa8, 0x41, 0x42, 0x41, 0x08, 0xa6, 0x98, 0x1e, 0xc4, 0x49, 0x7a, 0x30, 0x27, 0xe9, 0xb9, + 0x82, 0x9c, 0x24, 0xa5, 0xaf, 0x87, 0xdf, 0x2b, 0x7a, 0x68, 0x8e, 0x72, 0x8a, 0x3a, 0xf1, 0x50, + 0x8e, 0xe1, 0xc6, 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, + 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0x63, 0x94, 0x03, 0xb9, 0x81, 0x6b, 0x0d, 0x65, 0x46, 0x30, + 0x26, 0xb1, 0x81, 0x9d, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x95, 0x0d, 0x52, 0x23, 0xa9, + 0x01, 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -59,10 +105,11 @@ // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for Version service - +// VersionClient is the client API for Version service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type VersionClient interface { - Version(ctx context.Context, in *google_protobuf.Empty, opts ...grpc.CallOption) (*VersionResponse, error) + Version(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*VersionResponse, error) } type versionClient struct { @@ -73,19 +120,26 @@ return &versionClient{cc} } -func (c *versionClient) Version(ctx context.Context, in *google_protobuf.Empty, opts ...grpc.CallOption) (*VersionResponse, error) { +func (c *versionClient) Version(ctx context.Context, in *types.Empty, opts ...grpc.CallOption) (*VersionResponse, error) { out := new(VersionResponse) - err := grpc.Invoke(ctx, "/containerd.services.version.v1.Version/Version", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/containerd.services.version.v1.Version/Version", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for Version service - +// VersionServer is the server API for Version service. type VersionServer interface { - Version(context.Context, *google_protobuf.Empty) (*VersionResponse, error) + Version(context.Context, *types.Empty) (*VersionResponse, error) +} + +// UnimplementedVersionServer can be embedded to have forward compatible implementations. +type UnimplementedVersionServer struct { +} + +func (*UnimplementedVersionServer) Version(ctx context.Context, req *types.Empty) (*VersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") } func RegisterVersionServer(s *grpc.Server, srv VersionServer) { @@ -93,7 +147,7 @@ } func _Version_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(google_protobuf.Empty) + in := new(types.Empty) if err := dec(in); err != nil { return nil, err } @@ -105,7 +159,7 @@ FullMethod: "/containerd.services.version.v1.Version/Version", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(VersionServer).Version(ctx, req.(*google_protobuf.Empty)) + return srv.(VersionServer).Version(ctx, req.(*types.Empty)) } return interceptor(ctx, in, info, handler) } @@ -126,7 +180,7 @@ func (m *VersionResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -134,35 +188,51 @@ } func (m *VersionResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Version) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintVersion(dAtA, i, uint64(len(m.Version))) - i += copy(dAtA[i:], m.Version) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.Revision) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Revision) + copy(dAtA[i:], m.Revision) i = encodeVarintVersion(dAtA, i, uint64(len(m.Revision))) - i += copy(dAtA[i:], m.Revision) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintVersion(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func encodeVarintVersion(dAtA []byte, offset int, v uint64) int { + offset -= sovVersion(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *VersionResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Version) @@ -173,18 +243,14 @@ if l > 0 { n += 1 + l + sovVersion(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovVersion(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozVersion(x uint64) (n int) { return sovVersion(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -196,6 +262,7 @@ s := strings.Join([]string{`&VersionResponse{`, `Version:` + fmt.Sprintf("%v", this.Version) + `,`, `Revision:` + fmt.Sprintf("%v", this.Revision) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -223,7 +290,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -251,7 +318,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -261,6 +328,9 @@ return ErrInvalidLengthVersion } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVersion + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -280,7 +350,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -290,6 +360,9 @@ return ErrInvalidLengthVersion } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVersion + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -301,12 +374,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthVersion } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -319,6 +393,7 @@ func skipVersion(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -350,10 +425,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -370,77 +443,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthVersion } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowVersion - } - 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 := skipVersion(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupVersion + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthVersion + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthVersion = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowVersion = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthVersion = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowVersion = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupVersion = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/services/version/v1/version.proto", fileDescriptorVersion) -} - -var fileDescriptorVersion = []byte{ - // 243 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x4b, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x17, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x16, 0xeb, - 0x97, 0xa5, 0x16, 0x15, 0x67, 0xe6, 0xe7, 0xe9, 0x97, 0x19, 0xc2, 0x98, 0x7a, 0x05, 0x45, 0xf9, - 0x25, 0xf9, 0x42, 0x72, 0x08, 0x1d, 0x7a, 0x30, 0xd5, 0x7a, 0x30, 0x25, 0x65, 0x86, 0x52, 0xd2, - 0xe9, 0xf9, 0xf9, 0xe9, 0x39, 0xa9, 0xfa, 0x60, 0xd5, 0x49, 0xa5, 0x69, 0xfa, 0xa9, 0xb9, 0x05, - 0x25, 0x95, 0x10, 0xcd, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0xa6, 0x3e, 0x88, 0x05, 0x11, - 0x55, 0x72, 0xe7, 0xe2, 0x0f, 0x83, 0x18, 0x10, 0x94, 0x5a, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0x2a, - 0x24, 0xc1, 0xc5, 0x0e, 0x35, 0x53, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x15, 0x92, - 0xe2, 0xe2, 0x28, 0x4a, 0x2d, 0xcb, 0x04, 0x4b, 0x31, 0x81, 0xa5, 0xe0, 0x7c, 0xa3, 0x58, 0x2e, - 0x76, 0xa8, 0x41, 0x42, 0x41, 0x08, 0xa6, 0x98, 0x1e, 0xc4, 0x49, 0x7a, 0x30, 0x27, 0xe9, 0xb9, - 0x82, 0x9c, 0x24, 0xa5, 0xaf, 0x87, 0xdf, 0x2b, 0x7a, 0x68, 0x8e, 0x72, 0x8a, 0x3a, 0xf1, 0x50, - 0x8e, 0xe1, 0xc6, 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, - 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0x63, 0x94, 0x03, 0xb9, 0x81, 0x6b, 0x0d, 0x65, 0x46, 0x30, - 0x26, 0xb1, 0x81, 0x9d, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x95, 0x0d, 0x52, 0x23, 0xa9, - 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/services/version/v1/version.proto containerd-1.5.9/api/services/version/v1/version.proto --- containerd-1.2.6/api/services/version/v1/version.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/services/version/v1/version.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.services.version.v1; diff -Nru containerd-1.2.6/api/types/descriptor.pb.go containerd-1.5.9/api/types/descriptor.pb.go --- containerd-1.2.6/api/types/descriptor.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/descriptor.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,35 +1,19 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/types/descriptor.proto -/* - Package types is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/types/descriptor.proto - github.com/containerd/containerd/api/types/metrics.proto - github.com/containerd/containerd/api/types/mount.proto - github.com/containerd/containerd/api/types/platform.proto - - It has these top-level messages: - Descriptor - Metric - Mount - Platform -*/ package types -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_opencontainers_go_digest "github.com/opencontainers/go-digest" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -40,7 +24,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Descriptor describes a blob in a content store. // @@ -48,22 +32,84 @@ // oci descriptor found in a manifest. // See https://godoc.org/github.com/opencontainers/image-spec/specs-go/v1#Descriptor type Descriptor struct { - MediaType string `protobuf:"bytes,1,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"` - Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,2,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` - Size_ int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + MediaType string `protobuf:"bytes,1,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"` + Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,2,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"` + Size_ int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + Annotations map[string]string `protobuf:"bytes,5,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Descriptor) Reset() { *m = Descriptor{} } +func (*Descriptor) ProtoMessage() {} +func (*Descriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_37f958df3707db9e, []int{0} +} +func (m *Descriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Descriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Descriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Descriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_Descriptor.Merge(m, src) +} +func (m *Descriptor) XXX_Size() int { + return m.Size() +} +func (m *Descriptor) XXX_DiscardUnknown() { + xxx_messageInfo_Descriptor.DiscardUnknown(m) } -func (m *Descriptor) Reset() { *m = Descriptor{} } -func (*Descriptor) ProtoMessage() {} -func (*Descriptor) Descriptor() ([]byte, []int) { return fileDescriptorDescriptor, []int{0} } +var xxx_messageInfo_Descriptor proto.InternalMessageInfo func init() { proto.RegisterType((*Descriptor)(nil), "containerd.types.Descriptor") + proto.RegisterMapType((map[string]string)(nil), "containerd.types.Descriptor.AnnotationsEntry") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/types/descriptor.proto", fileDescriptor_37f958df3707db9e) } + +var fileDescriptor_37f958df3707db9e = []byte{ + // 311 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4e, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xa7, 0xa4, 0x16, + 0x27, 0x17, 0x65, 0x16, 0x94, 0xe4, 0x17, 0xe9, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, + 0x94, 0xe9, 0x81, 0x95, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf5, 0x41, 0x2c, 0x88, + 0x3a, 0xa5, 0x39, 0x4c, 0x5c, 0x5c, 0x2e, 0x70, 0xcd, 0x42, 0xb2, 0x5c, 0x5c, 0xb9, 0xa9, 0x29, + 0x99, 0x89, 0xf1, 0x20, 0x3d, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x9c, 0x60, 0x91, 0x90, + 0xca, 0x82, 0x54, 0x21, 0x2f, 0x2e, 0xb6, 0x94, 0xcc, 0xf4, 0xd4, 0xe2, 0x12, 0x09, 0x26, 0x90, + 0x94, 0x93, 0xd1, 0x89, 0x7b, 0xf2, 0x0c, 0xb7, 0xee, 0xc9, 0x6b, 0x21, 0x39, 0x35, 0xbf, 0x20, + 0x35, 0x0f, 0x6e, 0x79, 0xb1, 0x7e, 0x7a, 0xbe, 0x2e, 0x44, 0x8b, 0x9e, 0x0b, 0x98, 0x0a, 0x82, + 0x9a, 0x20, 0x24, 0xc4, 0xc5, 0x52, 0x9c, 0x59, 0x95, 0x2a, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0x1c, + 0x04, 0x66, 0x0b, 0xf9, 0x73, 0x71, 0x27, 0xe6, 0xe5, 0xe5, 0x97, 0x24, 0x96, 0x64, 0xe6, 0xe7, + 0x15, 0x4b, 0xb0, 0x2a, 0x30, 0x6b, 0x70, 0x1b, 0xe9, 0xea, 0xa1, 0xfb, 0x45, 0x0f, 0xe1, 0x62, + 0x3d, 0x47, 0x84, 0x7a, 0xd7, 0xbc, 0x92, 0xa2, 0xca, 0x20, 0x64, 0x13, 0xa4, 0xec, 0xb8, 0x04, + 0xd0, 0x15, 0x08, 0x09, 0x70, 0x31, 0x67, 0xa7, 0x56, 0x42, 0x3d, 0x07, 0x62, 0x0a, 0x89, 0x70, + 0xb1, 0x96, 0x25, 0xe6, 0x94, 0xa6, 0x42, 0x7c, 0x15, 0x04, 0xe1, 0x58, 0x31, 0x59, 0x30, 0x3a, + 0x79, 0x9d, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, 0x23, 0x39, 0xc6, 0x13, 0x8f, + 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x31, 0xca, 0x80, 0xf8, 0xd8, 0xb1, + 0x06, 0x93, 0x11, 0x0c, 0x49, 0x6c, 0xe0, 0x30, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x22, + 0x8a, 0x20, 0x4a, 0xda, 0x01, 0x00, 0x00, +} + func (m *Descriptor) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -71,40 +117,75 @@ } func (m *Descriptor) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Descriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.MediaType) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintDescriptor(dAtA, i, uint64(len(m.MediaType))) - i += copy(dAtA[i:], m.MediaType) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Annotations) > 0 { + for k := range m.Annotations { + v := m.Annotations[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintDescriptor(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintDescriptor(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintDescriptor(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a + } + } + if m.Size_ != 0 { + i = encodeVarintDescriptor(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x18 } if len(m.Digest) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Digest) + copy(dAtA[i:], m.Digest) i = encodeVarintDescriptor(dAtA, i, uint64(len(m.Digest))) - i += copy(dAtA[i:], m.Digest) + i-- + dAtA[i] = 0x12 } - if m.Size_ != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintDescriptor(dAtA, i, uint64(m.Size_)) + if len(m.MediaType) > 0 { + i -= len(m.MediaType) + copy(dAtA[i:], m.MediaType) + i = encodeVarintDescriptor(dAtA, i, uint64(len(m.MediaType))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintDescriptor(dAtA []byte, offset int, v uint64) int { + offset -= sovDescriptor(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Descriptor) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.MediaType) @@ -118,18 +199,22 @@ if m.Size_ != 0 { n += 1 + sovDescriptor(uint64(m.Size_)) } + if len(m.Annotations) > 0 { + for k, v := range m.Annotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovDescriptor(uint64(len(k))) + 1 + len(v) + sovDescriptor(uint64(len(v))) + n += mapEntrySize + 1 + sovDescriptor(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovDescriptor(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozDescriptor(x uint64) (n int) { return sovDescriptor(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -138,10 +223,22 @@ if this == nil { return "nil" } + keysForAnnotations := make([]string, 0, len(this.Annotations)) + for k, _ := range this.Annotations { + keysForAnnotations = append(keysForAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + mapStringForAnnotations := "map[string]string{" + for _, k := range keysForAnnotations { + mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k]) + } + mapStringForAnnotations += "}" s := strings.Join([]string{`&Descriptor{`, `MediaType:` + fmt.Sprintf("%v", this.MediaType) + `,`, `Digest:` + fmt.Sprintf("%v", this.Digest) + `,`, `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, + `Annotations:` + mapStringForAnnotations + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -169,7 +266,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -197,7 +294,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -207,6 +304,9 @@ return ErrInvalidLengthDescriptor } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthDescriptor + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -226,7 +326,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -236,6 +336,9 @@ return ErrInvalidLengthDescriptor } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthDescriptor + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -255,23 +358,151 @@ } b := dAtA[iNdEx] iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift + m.Size_ |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } + if msglen < 0 { + return ErrInvalidLengthDescriptor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDescriptor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Annotations == nil { + m.Annotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthDescriptor + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthDescriptor + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDescriptor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthDescriptor + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthDescriptor + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipDescriptor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDescriptor + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Annotations[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipDescriptor(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthDescriptor } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -284,6 +515,7 @@ func skipDescriptor(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -315,10 +547,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -335,76 +565,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthDescriptor } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowDescriptor - } - 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 := skipDescriptor(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDescriptor + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthDescriptor + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthDescriptor = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowDescriptor = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthDescriptor = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDescriptor = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDescriptor = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/types/descriptor.proto", fileDescriptorDescriptor) -} - -var fileDescriptorDescriptor = []byte{ - // 234 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4e, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xa7, 0xa4, 0x16, - 0x27, 0x17, 0x65, 0x16, 0x94, 0xe4, 0x17, 0xe9, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, - 0x94, 0xe9, 0x81, 0x95, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf5, 0x41, 0x2c, 0x88, - 0x3a, 0xa5, 0x6e, 0x46, 0x2e, 0x2e, 0x17, 0xb8, 0x66, 0x21, 0x59, 0x2e, 0xae, 0xdc, 0xd4, 0x94, - 0xcc, 0xc4, 0x78, 0x90, 0x1e, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x4e, 0xb0, 0x48, 0x48, - 0x65, 0x41, 0xaa, 0x90, 0x17, 0x17, 0x5b, 0x4a, 0x66, 0x7a, 0x6a, 0x71, 0x89, 0x04, 0x13, 0x48, - 0xca, 0xc9, 0xe8, 0xc4, 0x3d, 0x79, 0x86, 0x5b, 0xf7, 0xe4, 0xb5, 0x90, 0x9c, 0x9a, 0x5f, 0x90, - 0x9a, 0x07, 0xb7, 0xbc, 0x58, 0x3f, 0x3d, 0x5f, 0x17, 0xa2, 0x45, 0xcf, 0x05, 0x4c, 0x05, 0x41, - 0x4d, 0x10, 0x12, 0xe2, 0x62, 0x29, 0xce, 0xac, 0x4a, 0x95, 0x60, 0x56, 0x60, 0xd4, 0x60, 0x0e, - 0x02, 0xb3, 0x9d, 0xbc, 0x4e, 0x3c, 0x94, 0x63, 0xb8, 0xf1, 0x50, 0x8e, 0xa1, 0xe1, 0x91, 0x1c, - 0xe3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x18, 0x65, 0x40, - 0x7c, 0x60, 0x58, 0x83, 0xc9, 0x08, 0x86, 0x24, 0x36, 0xb0, 0x17, 0x8d, 0x01, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xea, 0xac, 0x78, 0x9a, 0x49, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/types/descriptor.proto containerd-1.5.9/api/types/descriptor.proto --- containerd-1.2.6/api/types/descriptor.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/descriptor.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.types; @@ -15,4 +31,5 @@ string media_type = 1; string digest = 2 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false]; int64 size = 3; + map annotations = 5; } diff -Nru containerd-1.2.6/api/types/metrics.pb.go containerd-1.5.9/api/types/metrics.pb.go --- containerd-1.2.6/api/types/metrics.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/metrics.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,22 +3,18 @@ package types -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import google_protobuf1 "github.com/gogo/protobuf/types" -import _ "github.com/gogo/protobuf/types" - -import time "time" - -import types1 "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -26,23 +22,86 @@ var _ = math.Inf var _ = time.Kitchen +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + type Metric struct { - Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,stdtime" json:"timestamp"` - ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Data *google_protobuf1.Any `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"` + Timestamp time.Time `protobuf:"bytes,1,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Data *types.Any `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Metric) Reset() { *m = Metric{} } +func (*Metric) ProtoMessage() {} +func (*Metric) Descriptor() ([]byte, []int) { + return fileDescriptor_8d594d87edf6e6bc, []int{0} +} +func (m *Metric) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Metric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Metric.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Metric) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metric.Merge(m, src) +} +func (m *Metric) XXX_Size() int { + return m.Size() +} +func (m *Metric) XXX_DiscardUnknown() { + xxx_messageInfo_Metric.DiscardUnknown(m) } -func (m *Metric) Reset() { *m = Metric{} } -func (*Metric) ProtoMessage() {} -func (*Metric) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{0} } +var xxx_messageInfo_Metric proto.InternalMessageInfo func init() { proto.RegisterType((*Metric)(nil), "containerd.types.Metric") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/types/metrics.proto", fileDescriptor_8d594d87edf6e6bc) +} + +var fileDescriptor_8d594d87edf6e6bc = []byte{ + // 258 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x48, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xe7, 0xa6, 0x96, + 0x14, 0x65, 0x26, 0x17, 0xeb, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0xd4, 0xe8, 0x81, + 0xe5, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x94, 0x64, + 0x7a, 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x3e, 0x98, 0x97, 0x54, 0x9a, 0xa6, 0x9f, 0x98, 0x57, 0x09, + 0x95, 0x92, 0x47, 0x97, 0x2a, 0xc9, 0xcc, 0x4d, 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0x80, 0x28, 0x50, + 0xea, 0x63, 0xe4, 0x62, 0xf3, 0x05, 0xdb, 0x2a, 0xe4, 0xc4, 0xc5, 0x09, 0x97, 0x95, 0x60, 0x54, + 0x60, 0xd4, 0xe0, 0x36, 0x92, 0xd2, 0x83, 0xe8, 0xd7, 0x83, 0xe9, 0xd7, 0x0b, 0x81, 0xa9, 0x70, + 0xe2, 0x38, 0x71, 0x4f, 0x9e, 0x61, 0xc2, 0x7d, 0x79, 0xc6, 0x20, 0x84, 0x36, 0x21, 0x31, 0x2e, + 0xa6, 0xcc, 0x14, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0x3c, + 0x5d, 0x82, 0x98, 0x32, 0x53, 0x84, 0x34, 0xb8, 0x58, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, + 0xc6, 0x8a, 0x60, 0x18, 0xeb, 0x98, 0x57, 0x19, 0x04, 0x56, 0xe1, 0xe4, 0x75, 0xe2, 0xa1, 0x1c, + 0xc3, 0x8d, 0x87, 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, + 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x28, 0x03, 0xe2, 0x03, 0xd2, 0x1a, 0x4c, 0x46, 0x30, 0x24, + 0xb1, 0x81, 0x6d, 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xde, 0x0d, 0x02, 0xfe, 0x85, 0x01, + 0x00, 0x00, +} + func (m *Metric) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -50,50 +109,67 @@ } func (m *Metric) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Metric) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(types1.SizeOfStdTime(m.Timestamp))) - n1, err := types1.StdTimeMarshalTo(m.Timestamp, dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - if len(m.ID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Data != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Data.Size())) - n2, err := m.Data.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Data.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0x1a + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0x12 } - return i, nil + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintMetrics(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int { + offset -= sovMetrics(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Metric) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l - l = types1.SizeOfStdTime(m.Timestamp) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp) n += 1 + l + sovMetrics(uint64(l)) l = len(m.ID) if l > 0 { @@ -103,18 +179,14 @@ l = m.Data.Size() n += 1 + l + sovMetrics(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovMetrics(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozMetrics(x uint64) (n int) { return sovMetrics(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -124,9 +196,10 @@ return "nil" } s := strings.Join([]string{`&Metric{`, - `Timestamp:` + strings.Replace(strings.Replace(this.Timestamp.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`, + `Timestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Timestamp), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `Data:` + strings.Replace(fmt.Sprintf("%v", this.Data), "Any", "google_protobuf1.Any", 1) + `,`, + `Data:` + strings.Replace(fmt.Sprintf("%v", this.Data), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -154,7 +227,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -182,7 +255,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -191,10 +264,13 @@ return ErrInvalidLengthMetrics } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types1.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timestamp, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -212,7 +288,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -222,6 +298,9 @@ return ErrInvalidLengthMetrics } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -241,7 +320,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -250,11 +329,14 @@ return ErrInvalidLengthMetrics } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Data == nil { - m.Data = &google_protobuf1.Any{} + m.Data = &types.Any{} } if err := m.Data.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -266,12 +348,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMetrics } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -284,6 +367,7 @@ func skipMetrics(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -315,10 +399,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -335,78 +417,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthMetrics } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMetrics - } - 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 := skipMetrics(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMetrics + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthMetrics + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMetrics = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/types/metrics.proto", fileDescriptorMetrics) -} - -var fileDescriptorMetrics = []byte{ - // 258 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x48, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xe7, 0xa6, 0x96, - 0x14, 0x65, 0x26, 0x17, 0xeb, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0xd4, 0xe8, 0x81, - 0xe5, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x94, 0x64, - 0x7a, 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x3e, 0x98, 0x97, 0x54, 0x9a, 0xa6, 0x9f, 0x98, 0x57, 0x09, - 0x95, 0x92, 0x47, 0x97, 0x2a, 0xc9, 0xcc, 0x4d, 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0x80, 0x28, 0x50, - 0xea, 0x63, 0xe4, 0x62, 0xf3, 0x05, 0xdb, 0x2a, 0xe4, 0xc4, 0xc5, 0x09, 0x97, 0x95, 0x60, 0x54, - 0x60, 0xd4, 0xe0, 0x36, 0x92, 0xd2, 0x83, 0xe8, 0xd7, 0x83, 0xe9, 0xd7, 0x0b, 0x81, 0xa9, 0x70, - 0xe2, 0x38, 0x71, 0x4f, 0x9e, 0x61, 0xc2, 0x7d, 0x79, 0xc6, 0x20, 0x84, 0x36, 0x21, 0x31, 0x2e, - 0xa6, 0xcc, 0x14, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0x3c, - 0x5d, 0x82, 0x98, 0x32, 0x53, 0x84, 0x34, 0xb8, 0x58, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, - 0xc6, 0x8a, 0x60, 0x18, 0xeb, 0x98, 0x57, 0x19, 0x04, 0x56, 0xe1, 0xe4, 0x75, 0xe2, 0xa1, 0x1c, - 0xc3, 0x8d, 0x87, 0x72, 0x0c, 0x0d, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, - 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x28, 0x03, 0xe2, 0x03, 0xd2, 0x1a, 0x4c, 0x46, 0x30, 0x24, - 0xb1, 0x81, 0x6d, 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xde, 0x0d, 0x02, 0xfe, 0x85, 0x01, - 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/types/metrics.proto containerd-1.5.9/api/types/metrics.proto --- containerd-1.2.6/api/types/metrics.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/metrics.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.types; diff -Nru containerd-1.2.6/api/types/mount.pb.go containerd-1.5.9/api/types/mount.pb.go --- containerd-1.2.6/api/types/mount.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/mount.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,22 +3,27 @@ package types -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + // Mount describes mounts for a container. // // This type is the lingua franca of ContainerD. All services provide mounts @@ -35,20 +40,73 @@ // Target path in container Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"` // Options specifies zero or more fstab style mount options. - Options []string `protobuf:"bytes,4,rep,name=options" json:"options,omitempty"` + Options []string `protobuf:"bytes,4,rep,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Mount) Reset() { *m = Mount{} } +func (*Mount) ProtoMessage() {} +func (*Mount) Descriptor() ([]byte, []int) { + return fileDescriptor_920196890d4a7b9f, []int{0} +} +func (m *Mount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Mount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Mount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Mount) XXX_Merge(src proto.Message) { + xxx_messageInfo_Mount.Merge(m, src) +} +func (m *Mount) XXX_Size() int { + return m.Size() +} +func (m *Mount) XXX_DiscardUnknown() { + xxx_messageInfo_Mount.DiscardUnknown(m) } -func (m *Mount) Reset() { *m = Mount{} } -func (*Mount) ProtoMessage() {} -func (*Mount) Descriptor() ([]byte, []int) { return fileDescriptorMount, []int{0} } +var xxx_messageInfo_Mount proto.InternalMessageInfo func init() { proto.RegisterType((*Mount)(nil), "containerd.types.Mount") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/types/mount.proto", fileDescriptor_920196890d4a7b9f) +} + +var fileDescriptor_920196890d4a7b9f = []byte{ + // 202 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4b, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xe7, 0xe6, 0x97, + 0xe6, 0x95, 0xe8, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0x54, 0xe8, 0x81, 0x65, 0xa5, + 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x52, 0x2a, 0x17, 0xab, + 0x2f, 0x48, 0x9b, 0x90, 0x10, 0x17, 0x0b, 0x48, 0x9d, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, + 0x98, 0x2d, 0x24, 0xc6, 0xc5, 0x56, 0x9c, 0x5f, 0x5a, 0x94, 0x9c, 0x2a, 0xc1, 0x04, 0x16, 0x85, + 0xf2, 0x40, 0xe2, 0x25, 0x89, 0x45, 0xe9, 0xa9, 0x25, 0x12, 0xcc, 0x10, 0x71, 0x08, 0x4f, 0x48, + 0x82, 0x8b, 0x3d, 0xbf, 0xa0, 0x24, 0x33, 0x3f, 0xaf, 0x58, 0x82, 0x45, 0x81, 0x59, 0x83, 0x33, + 0x08, 0xc6, 0x75, 0xf2, 0x3a, 0xf1, 0x50, 0x8e, 0xe1, 0xc6, 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, + 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0x63, 0x94, 0x01, + 0xf1, 0x1e, 0xb4, 0x06, 0x93, 0x11, 0x0c, 0x49, 0x6c, 0x60, 0xb7, 0x1b, 0x03, 0x02, 0x00, 0x00, + 0xff, 0xff, 0x82, 0x1c, 0x02, 0x18, 0x1d, 0x01, 0x00, 0x00, +} + func (m *Mount) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -56,56 +114,67 @@ } func (m *Mount) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Mount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Type) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintMount(dAtA, i, uint64(len(m.Type))) - i += copy(dAtA[i:], m.Type) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Source) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintMount(dAtA, i, uint64(len(m.Source))) - i += copy(dAtA[i:], m.Source) + if len(m.Options) > 0 { + for iNdEx := len(m.Options) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Options[iNdEx]) + copy(dAtA[i:], m.Options[iNdEx]) + i = encodeVarintMount(dAtA, i, uint64(len(m.Options[iNdEx]))) + i-- + dAtA[i] = 0x22 + } } if len(m.Target) > 0 { - dAtA[i] = 0x1a - i++ + i -= len(m.Target) + copy(dAtA[i:], m.Target) i = encodeVarintMount(dAtA, i, uint64(len(m.Target))) - i += copy(dAtA[i:], m.Target) + i-- + dAtA[i] = 0x1a } - if len(m.Options) > 0 { - for _, s := range m.Options { - dAtA[i] = 0x22 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } + if len(m.Source) > 0 { + i -= len(m.Source) + copy(dAtA[i:], m.Source) + i = encodeVarintMount(dAtA, i, uint64(len(m.Source))) + i-- + dAtA[i] = 0x12 } - return i, nil + if len(m.Type) > 0 { + i -= len(m.Type) + copy(dAtA[i:], m.Type) + i = encodeVarintMount(dAtA, i, uint64(len(m.Type))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func encodeVarintMount(dAtA []byte, offset int, v uint64) int { + offset -= sovMount(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Mount) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Type) @@ -126,18 +195,14 @@ n += 1 + l + sovMount(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovMount(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozMount(x uint64) (n int) { return sovMount(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -151,6 +216,7 @@ `Source:` + fmt.Sprintf("%v", this.Source) + `,`, `Target:` + fmt.Sprintf("%v", this.Target) + `,`, `Options:` + fmt.Sprintf("%v", this.Options) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -178,7 +244,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -206,7 +272,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -216,6 +282,9 @@ return ErrInvalidLengthMount } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMount + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -235,7 +304,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -245,6 +314,9 @@ return ErrInvalidLengthMount } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMount + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -264,7 +336,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -274,6 +346,9 @@ return ErrInvalidLengthMount } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMount + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -293,7 +368,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -303,6 +378,9 @@ return ErrInvalidLengthMount } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMount + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -314,12 +392,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthMount } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -332,6 +411,7 @@ func skipMount(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -363,10 +443,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -383,74 +461,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthMount } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMount - } - 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 := skipMount(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMount + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthMount + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthMount = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowMount = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthMount = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMount = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMount = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/types/mount.proto", fileDescriptorMount) -} - -var fileDescriptorMount = []byte{ - // 202 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4b, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0xe7, 0xe6, 0x97, - 0xe6, 0x95, 0xe8, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0x54, 0xe8, 0x81, 0x65, 0xa5, - 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x92, 0xfa, 0x20, 0x16, 0x44, 0x9d, 0x52, 0x2a, 0x17, 0xab, - 0x2f, 0x48, 0x9b, 0x90, 0x10, 0x17, 0x0b, 0x48, 0x9d, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, - 0x98, 0x2d, 0x24, 0xc6, 0xc5, 0x56, 0x9c, 0x5f, 0x5a, 0x94, 0x9c, 0x2a, 0xc1, 0x04, 0x16, 0x85, - 0xf2, 0x40, 0xe2, 0x25, 0x89, 0x45, 0xe9, 0xa9, 0x25, 0x12, 0xcc, 0x10, 0x71, 0x08, 0x4f, 0x48, - 0x82, 0x8b, 0x3d, 0xbf, 0xa0, 0x24, 0x33, 0x3f, 0xaf, 0x58, 0x82, 0x45, 0x81, 0x59, 0x83, 0x33, - 0x08, 0xc6, 0x75, 0xf2, 0x3a, 0xf1, 0x50, 0x8e, 0xe1, 0xc6, 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, - 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0x63, 0x94, 0x01, - 0xf1, 0x1e, 0xb4, 0x06, 0x93, 0x11, 0x0c, 0x49, 0x6c, 0x60, 0xb7, 0x1b, 0x03, 0x02, 0x00, 0x00, - 0xff, 0xff, 0x82, 0x1c, 0x02, 0x18, 0x1d, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/types/mount.proto containerd-1.5.9/api/types/mount.proto --- containerd-1.2.6/api/types/mount.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/mount.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.types; diff -Nru containerd-1.2.6/api/types/platform.pb.go containerd-1.5.9/api/types/platform.pb.go --- containerd-1.2.6/api/types/platform.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/platform.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -3,41 +3,99 @@ package types -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + // Platform follows the structure of the OCI platform specification, from // descriptors. type Platform struct { - OS string `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"` - Architecture string `protobuf:"bytes,2,opt,name=architecture,proto3" json:"architecture,omitempty"` - Variant string `protobuf:"bytes,3,opt,name=variant,proto3" json:"variant,omitempty"` + OS string `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"` + Architecture string `protobuf:"bytes,2,opt,name=architecture,proto3" json:"architecture,omitempty"` + Variant string `protobuf:"bytes,3,opt,name=variant,proto3" json:"variant,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Platform) Reset() { *m = Platform{} } +func (*Platform) ProtoMessage() {} +func (*Platform) Descriptor() ([]byte, []int) { + return fileDescriptor_24ba7a4b83e2367e, []int{0} +} +func (m *Platform) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Platform) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Platform.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Platform) XXX_Merge(src proto.Message) { + xxx_messageInfo_Platform.Merge(m, src) +} +func (m *Platform) XXX_Size() int { + return m.Size() +} +func (m *Platform) XXX_DiscardUnknown() { + xxx_messageInfo_Platform.DiscardUnknown(m) } -func (m *Platform) Reset() { *m = Platform{} } -func (*Platform) ProtoMessage() {} -func (*Platform) Descriptor() ([]byte, []int) { return fileDescriptorPlatform, []int{0} } +var xxx_messageInfo_Platform proto.InternalMessageInfo func init() { proto.RegisterType((*Platform)(nil), "containerd.types.Platform") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/types/platform.proto", fileDescriptor_24ba7a4b83e2367e) +} + +var fileDescriptor_24ba7a4b83e2367e = []byte{ + // 205 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4c, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0x17, 0xe4, 0x24, + 0x96, 0xa4, 0xe5, 0x17, 0xe5, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0x14, 0xe9, + 0x81, 0x15, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf5, 0x41, 0x2c, 0x88, 0x3a, 0xa5, + 0x04, 0x2e, 0x8e, 0x00, 0xa8, 0x4e, 0x21, 0x31, 0x2e, 0xa6, 0xfc, 0x62, 0x09, 0x46, 0x05, 0x46, + 0x0d, 0x4e, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0xfc, 0x83, 0x83, 0x98, 0xf2, 0x8b, 0x85, 0x94, + 0xb8, 0x78, 0x12, 0x8b, 0x92, 0x33, 0x32, 0x4b, 0x52, 0x93, 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x98, + 0x40, 0x2a, 0x82, 0x50, 0xc4, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x12, 0x8b, 0x32, 0x13, 0xf3, 0x4a, + 0x24, 0x98, 0xc1, 0xd2, 0x30, 0xae, 0x93, 0xd7, 0x89, 0x87, 0x72, 0x0c, 0x37, 0x1e, 0xca, 0x31, + 0x34, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, + 0x18, 0xa3, 0x0c, 0x88, 0xf7, 0x9e, 0x35, 0x98, 0x8c, 0x60, 0x48, 0x62, 0x03, 0x3b, 0xdb, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0x05, 0xaa, 0xda, 0xa1, 0x1b, 0x01, 0x00, 0x00, +} + func (m *Platform) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -45,41 +103,58 @@ } func (m *Platform) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Platform) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.OS) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintPlatform(dAtA, i, uint64(len(m.OS))) - i += copy(dAtA[i:], m.OS) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Variant) > 0 { + i -= len(m.Variant) + copy(dAtA[i:], m.Variant) + i = encodeVarintPlatform(dAtA, i, uint64(len(m.Variant))) + i-- + dAtA[i] = 0x1a } if len(m.Architecture) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Architecture) + copy(dAtA[i:], m.Architecture) i = encodeVarintPlatform(dAtA, i, uint64(len(m.Architecture))) - i += copy(dAtA[i:], m.Architecture) + i-- + dAtA[i] = 0x12 } - if len(m.Variant) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintPlatform(dAtA, i, uint64(len(m.Variant))) - i += copy(dAtA[i:], m.Variant) + if len(m.OS) > 0 { + i -= len(m.OS) + copy(dAtA[i:], m.OS) + i = encodeVarintPlatform(dAtA, i, uint64(len(m.OS))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintPlatform(dAtA []byte, offset int, v uint64) int { + offset -= sovPlatform(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Platform) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.OS) @@ -94,18 +169,14 @@ if l > 0 { n += 1 + l + sovPlatform(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovPlatform(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozPlatform(x uint64) (n int) { return sovPlatform(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -118,6 +189,7 @@ `OS:` + fmt.Sprintf("%v", this.OS) + `,`, `Architecture:` + fmt.Sprintf("%v", this.Architecture) + `,`, `Variant:` + fmt.Sprintf("%v", this.Variant) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -145,7 +217,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -173,7 +245,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -183,6 +255,9 @@ return ErrInvalidLengthPlatform } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlatform + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -202,7 +277,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -212,6 +287,9 @@ return ErrInvalidLengthPlatform } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlatform + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -231,7 +309,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -241,6 +319,9 @@ return ErrInvalidLengthPlatform } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlatform + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -252,12 +333,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthPlatform } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -270,6 +352,7 @@ func skipPlatform(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -301,10 +384,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -321,74 +402,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthPlatform } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPlatform - } - 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 := skipPlatform(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPlatform + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthPlatform + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthPlatform = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowPlatform = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthPlatform = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPlatform = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPlatform = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/types/platform.proto", fileDescriptorPlatform) -} - -var fileDescriptorPlatform = []byte{ - // 205 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4c, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, - 0x4a, 0x41, 0x66, 0x26, 0x16, 0x64, 0xea, 0x97, 0x54, 0x16, 0xa4, 0x16, 0xeb, 0x17, 0xe4, 0x24, - 0x96, 0xa4, 0xe5, 0x17, 0xe5, 0xea, 0x15, 0x14, 0xe5, 0x97, 0xe4, 0x0b, 0x09, 0x20, 0x14, 0xe9, - 0x81, 0x15, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x25, 0xf5, 0x41, 0x2c, 0x88, 0x3a, 0xa5, - 0x04, 0x2e, 0x8e, 0x00, 0xa8, 0x4e, 0x21, 0x31, 0x2e, 0xa6, 0xfc, 0x62, 0x09, 0x46, 0x05, 0x46, - 0x0d, 0x4e, 0x27, 0xb6, 0x47, 0xf7, 0xe4, 0x99, 0xfc, 0x83, 0x83, 0x98, 0xf2, 0x8b, 0x85, 0x94, - 0xb8, 0x78, 0x12, 0x8b, 0x92, 0x33, 0x32, 0x4b, 0x52, 0x93, 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x98, - 0x40, 0x2a, 0x82, 0x50, 0xc4, 0x84, 0x24, 0xb8, 0xd8, 0xcb, 0x12, 0x8b, 0x32, 0x13, 0xf3, 0x4a, - 0x24, 0x98, 0xc1, 0xd2, 0x30, 0xae, 0x93, 0xd7, 0x89, 0x87, 0x72, 0x0c, 0x37, 0x1e, 0xca, 0x31, - 0x34, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, - 0x18, 0xa3, 0x0c, 0x88, 0xf7, 0x9e, 0x35, 0x98, 0x8c, 0x60, 0x48, 0x62, 0x03, 0x3b, 0xdb, 0x18, - 0x10, 0x00, 0x00, 0xff, 0xff, 0x05, 0xaa, 0xda, 0xa1, 0x1b, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/api/types/platform.proto containerd-1.5.9/api/types/platform.proto --- containerd-1.2.6/api/types/platform.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/platform.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.types; diff -Nru containerd-1.2.6/api/types/task/task.pb.go containerd-1.5.9/api/types/task/task.pb.go --- containerd-1.2.6/api/types/task/task.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/task/task.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,34 +1,20 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/api/types/task/task.proto -/* - Package task is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/api/types/task/task.proto - - It has these top-level messages: - Process - ProcessInfo -*/ package task -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import _ "github.com/gogo/protobuf/types" -import google_protobuf2 "github.com/gogo/protobuf/types" - -import time "time" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -40,7 +26,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Status int32 @@ -61,6 +47,7 @@ 4: "PAUSED", 5: "PAUSING", } + var Status_value = map[string]int32{ "UNKNOWN": 0, "CREATED": 1, @@ -73,24 +60,58 @@ func (x Status) String() string { return proto.EnumName(Status_name, int32(x)) } -func (Status) EnumDescriptor() ([]byte, []int) { return fileDescriptorTask, []int{0} } + +func (Status) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_391ef18c8ab0dc16, []int{0} +} type Process struct { - ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` - ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` - Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` - Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` - Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` - ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ContainerID string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + Status Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` + ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Process) Reset() { *m = Process{} } +func (*Process) ProtoMessage() {} +func (*Process) Descriptor() ([]byte, []int) { + return fileDescriptor_391ef18c8ab0dc16, []int{0} +} +func (m *Process) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Process) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Process.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Process) XXX_Merge(src proto.Message) { + xxx_messageInfo_Process.Merge(m, src) +} +func (m *Process) XXX_Size() int { + return m.Size() +} +func (m *Process) XXX_DiscardUnknown() { + xxx_messageInfo_Process.DiscardUnknown(m) } -func (m *Process) Reset() { *m = Process{} } -func (*Process) ProtoMessage() {} -func (*Process) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{0} } +var xxx_messageInfo_Process proto.InternalMessageInfo type ProcessInfo struct { // PID is the process ID. @@ -98,22 +119,97 @@ // Info contains additional process information. // // Info varies by platform. - Info *google_protobuf2.Any `protobuf:"bytes,2,opt,name=info" json:"info,omitempty"` + Info *types.Any `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ProcessInfo) Reset() { *m = ProcessInfo{} } +func (*ProcessInfo) ProtoMessage() {} +func (*ProcessInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_391ef18c8ab0dc16, []int{1} +} +func (m *ProcessInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProcessInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProcessInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProcessInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProcessInfo.Merge(m, src) +} +func (m *ProcessInfo) XXX_Size() int { + return m.Size() +} +func (m *ProcessInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ProcessInfo.DiscardUnknown(m) } -func (m *ProcessInfo) Reset() { *m = ProcessInfo{} } -func (*ProcessInfo) ProtoMessage() {} -func (*ProcessInfo) Descriptor() ([]byte, []int) { return fileDescriptorTask, []int{1} } +var xxx_messageInfo_ProcessInfo proto.InternalMessageInfo func init() { + proto.RegisterEnum("containerd.v1.types.Status", Status_name, Status_value) proto.RegisterType((*Process)(nil), "containerd.v1.types.Process") proto.RegisterType((*ProcessInfo)(nil), "containerd.v1.types.ProcessInfo") - proto.RegisterEnum("containerd.v1.types.Status", Status_name, Status_value) } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/api/types/task/task.proto", fileDescriptor_391ef18c8ab0dc16) +} + +var fileDescriptor_391ef18c8ab0dc16 = []byte{ + // 545 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x3f, 0x6f, 0xd3, 0x40, + 0x18, 0xc6, 0x7d, 0x6e, 0xeb, 0xa6, 0xe7, 0xb6, 0x18, 0x13, 0x55, 0xc6, 0x20, 0xdb, 0xea, 0x64, + 0x31, 0xd8, 0x22, 0xdd, 0xd8, 0xf2, 0x4f, 0xc8, 0x42, 0x72, 0x23, 0x27, 0x11, 0x6c, 0x91, 0x13, + 0x5f, 0xcc, 0xa9, 0xcd, 0x9d, 0x65, 0x9f, 0x81, 0x6c, 0x8c, 0xa8, 0x13, 0x5f, 0xa0, 0x13, 0x7c, + 0x0a, 0x3e, 0x41, 0x46, 0x26, 0xc4, 0x14, 0xa8, 0x3f, 0x09, 0x3a, 0xdb, 0x49, 0x23, 0x60, 0x39, + 0xbd, 0xef, 0xf3, 0x7b, 0xee, 0xbd, 0xf7, 0x1e, 0xf8, 0x22, 0xc6, 0xec, 0x6d, 0x3e, 0x75, 0x66, + 0x74, 0xe1, 0xce, 0x28, 0x61, 0x21, 0x26, 0x28, 0x8d, 0x76, 0xcb, 0x30, 0xc1, 0x2e, 0x5b, 0x26, + 0x28, 0x73, 0x59, 0x98, 0x5d, 0x95, 0x87, 0x93, 0xa4, 0x94, 0x51, 0xf5, 0xd1, 0xbd, 0xcb, 0x79, + 0xf7, 0xdc, 0x29, 0x4d, 0x7a, 0x33, 0xa6, 0x31, 0x2d, 0xb9, 0xcb, 0xab, 0xca, 0xaa, 0x9b, 0x31, + 0xa5, 0xf1, 0x35, 0x72, 0xcb, 0x6e, 0x9a, 0xcf, 0x5d, 0x86, 0x17, 0x28, 0x63, 0xe1, 0x22, 0xa9, + 0x0d, 0x8f, 0xff, 0x36, 0x84, 0x64, 0x59, 0xa1, 0xf3, 0x42, 0x84, 0x87, 0x83, 0x94, 0xce, 0x50, + 0x96, 0xa9, 0x2d, 0x78, 0xbc, 0x7d, 0x74, 0x82, 0x23, 0x0d, 0x58, 0xc0, 0x3e, 0xea, 0x3c, 0x28, + 0xd6, 0xa6, 0xdc, 0xdd, 0xe8, 0x5e, 0x2f, 0x90, 0xb7, 0x26, 0x2f, 0x52, 0xcf, 0xa0, 0x88, 0x23, + 0x4d, 0x2c, 0x9d, 0x52, 0xb1, 0x36, 0x45, 0xaf, 0x17, 0x88, 0x38, 0x52, 0x15, 0xb8, 0x97, 0xe0, + 0x48, 0xdb, 0xb3, 0x80, 0x7d, 0x12, 0xf0, 0x52, 0xbd, 0x80, 0x52, 0xc6, 0x42, 0x96, 0x67, 0xda, + 0xbe, 0x05, 0xec, 0xd3, 0xd6, 0x13, 0xe7, 0x3f, 0x3f, 0x74, 0x86, 0xa5, 0x25, 0xa8, 0xad, 0x6a, + 0x13, 0x1e, 0x64, 0x2c, 0xc2, 0x44, 0x3b, 0xe0, 0x2f, 0x04, 0x55, 0xa3, 0x9e, 0xf1, 0x51, 0x11, + 0xcd, 0x99, 0x26, 0x95, 0x72, 0xdd, 0xd5, 0x3a, 0x4a, 0x53, 0xed, 0x70, 0xab, 0xa3, 0x34, 0x55, + 0x75, 0xd8, 0x60, 0x28, 0x5d, 0x60, 0x12, 0x5e, 0x6b, 0x0d, 0x0b, 0xd8, 0x8d, 0x60, 0xdb, 0xab, + 0x26, 0x94, 0xd1, 0x07, 0xcc, 0x26, 0xf5, 0x6e, 0x47, 0xe5, 0xc2, 0x90, 0x4b, 0xd5, 0x2a, 0x6a, + 0x1b, 0x1e, 0xf1, 0x0e, 0x45, 0x93, 0x90, 0x69, 0xd0, 0x02, 0xb6, 0xdc, 0xd2, 0x9d, 0x2a, 0x50, + 0x67, 0x13, 0xa8, 0x33, 0xda, 0x24, 0xde, 0x69, 0xac, 0xd6, 0xa6, 0xf0, 0xf9, 0x97, 0x09, 0x82, + 0x46, 0x75, 0xad, 0xcd, 0xce, 0x3d, 0x28, 0xd7, 0x19, 0x7b, 0x64, 0x4e, 0x37, 0xd9, 0x80, 0xfb, + 0x6c, 0x6c, 0xb8, 0x8f, 0xc9, 0x9c, 0x96, 0x39, 0xca, 0xad, 0xe6, 0x3f, 0xe3, 0xdb, 0x64, 0x19, + 0x94, 0x8e, 0x67, 0x3f, 0x00, 0x94, 0xea, 0xc5, 0x0c, 0x78, 0x38, 0xf6, 0x5f, 0xf9, 0x97, 0xaf, + 0x7d, 0x45, 0xd0, 0x1f, 0xde, 0xdc, 0x5a, 0x27, 0x15, 0x18, 0x93, 0x2b, 0x42, 0xdf, 0x13, 0xce, + 0xbb, 0x41, 0xbf, 0x3d, 0xea, 0xf7, 0x14, 0xb0, 0xcb, 0xbb, 0x29, 0x0a, 0x19, 0x8a, 0x38, 0x0f, + 0xc6, 0xbe, 0xef, 0xf9, 0x2f, 0x15, 0x71, 0x97, 0x07, 0x39, 0x21, 0x98, 0xc4, 0x9c, 0x0f, 0x47, + 0x97, 0x83, 0x41, 0xbf, 0xa7, 0xec, 0xed, 0xf2, 0x21, 0xa3, 0x49, 0x82, 0x22, 0xf5, 0x29, 0x94, + 0x06, 0xed, 0xf1, 0xb0, 0xdf, 0x53, 0xf6, 0x75, 0xe5, 0xe6, 0xd6, 0x3a, 0xae, 0xf0, 0x20, 0xcc, + 0xb3, 0x6a, 0x3a, 0xa7, 0x7c, 0xfa, 0xc1, 0xee, 0x6d, 0x8e, 0x31, 0x89, 0xf5, 0xd3, 0x4f, 0x5f, + 0x0c, 0xe1, 0xdb, 0x57, 0xa3, 0xfe, 0x4d, 0x47, 0x5b, 0xdd, 0x19, 0xc2, 0xcf, 0x3b, 0x43, 0xf8, + 0x58, 0x18, 0x60, 0x55, 0x18, 0xe0, 0x7b, 0x61, 0x80, 0xdf, 0x85, 0x01, 0xde, 0x08, 0x53, 0xa9, + 0x0c, 0xe2, 0xe2, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x32, 0xd2, 0x86, 0x50, 0x03, 0x00, + 0x00, +} + func (m *Process) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -121,80 +217,94 @@ } func (m *Process) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Process) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ContainerID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) - i += copy(dAtA[i:], m.ContainerID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintTask(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x52 + if m.ExitStatus != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x48 } - if len(m.ID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.Terminal { + i-- + if m.Terminal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 } - if m.Pid != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x3a } - if m.Status != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Status)) + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x32 } if len(m.Stdin) > 0 { - dAtA[i] = 0x2a - i++ + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) i = encodeVarintTask(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + i-- + dAtA[i] = 0x2a } - if len(m.Stderr) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintTask(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if m.Status != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x20 } - if m.Terminal { - dAtA[i] = 0x40 - i++ - if m.Terminal { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i++ + if m.Pid != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x18 } - if m.ExitStatus != 0 { - dAtA[i] = 0x48 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.ExitStatus)) + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0x12 } - dAtA[i] = 0x52 - i++ - i = encodeVarintTask(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n1, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.ContainerID) > 0 { + i -= len(m.ContainerID) + copy(dAtA[i:], m.ContainerID) + i = encodeVarintTask(dAtA, i, uint64(len(m.ContainerID))) + i-- + dAtA[i] = 0xa } - i += n1 - return i, nil + return len(dAtA) - i, nil } func (m *ProcessInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -202,38 +312,54 @@ } func (m *ProcessInfo) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProcessInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Pid != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Info != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintTask(dAtA, i, uint64(m.Info.Size())) - n2, err := m.Info.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTask(dAtA, i, uint64(size)) } - i += n2 + i-- + dAtA[i] = 0x12 } - return i, nil + if m.Pid != 0 { + i = encodeVarintTask(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil } func encodeVarintTask(dAtA []byte, offset int, v uint64) int { + offset -= sovTask(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Process) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ContainerID) @@ -268,12 +394,18 @@ if m.ExitStatus != 0 { n += 1 + sovTask(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovTask(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ProcessInfo) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { @@ -283,18 +415,14 @@ l = m.Info.Size() n += 1 + l + sovTask(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovTask(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozTask(x uint64) (n int) { return sovTask(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -313,7 +441,8 @@ `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -324,7 +453,8 @@ } s := strings.Join([]string{`&ProcessInfo{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, - `Info:` + strings.Replace(fmt.Sprintf("%v", this.Info), "Any", "google_protobuf2.Any", 1) + `,`, + `Info:` + strings.Replace(fmt.Sprintf("%v", this.Info), "Any", "types.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -352,7 +482,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -380,7 +510,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -390,6 +520,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -409,7 +542,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -419,6 +552,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -438,7 +574,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -457,7 +593,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Status |= (Status(b) & 0x7F) << shift + m.Status |= Status(b&0x7F) << shift if b < 0x80 { break } @@ -476,7 +612,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -486,6 +622,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -505,7 +644,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -515,6 +654,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -534,7 +676,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -544,6 +686,9 @@ return ErrInvalidLengthTask } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -563,7 +708,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -583,7 +728,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -602,7 +747,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -611,10 +756,13 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -624,12 +772,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -654,7 +803,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -682,7 +831,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -701,7 +850,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -710,11 +859,14 @@ return ErrInvalidLengthTask } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTask + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Info == nil { - m.Info = &google_protobuf2.Any{} + m.Info = &types.Any{} } if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -726,12 +878,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTask } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -744,6 +897,7 @@ func skipTask(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -775,10 +929,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -795,96 +947,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthTask } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowTask - } - 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 := skipTask(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTask + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthTask + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthTask = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowTask = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthTask = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTask = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTask = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/api/types/task/task.proto", fileDescriptorTask) -} - -var fileDescriptorTask = []byte{ - // 545 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x3f, 0x6f, 0xd3, 0x40, - 0x18, 0xc6, 0x7d, 0x6e, 0xeb, 0xa6, 0xe7, 0xb6, 0x18, 0x13, 0x55, 0xc6, 0x20, 0xdb, 0xea, 0x64, - 0x31, 0xd8, 0x22, 0xdd, 0xd8, 0xf2, 0x4f, 0xc8, 0x42, 0x72, 0x23, 0x27, 0x11, 0x6c, 0x91, 0x13, - 0x5f, 0xcc, 0xa9, 0xcd, 0x9d, 0x65, 0x9f, 0x81, 0x6c, 0x8c, 0xa8, 0x13, 0x5f, 0xa0, 0x13, 0x7c, - 0x0a, 0x3e, 0x41, 0x46, 0x26, 0xc4, 0x14, 0xa8, 0x3f, 0x09, 0x3a, 0xdb, 0x49, 0x23, 0x60, 0x39, - 0xbd, 0xef, 0xf3, 0x7b, 0xee, 0xbd, 0xf7, 0x1e, 0xf8, 0x22, 0xc6, 0xec, 0x6d, 0x3e, 0x75, 0x66, - 0x74, 0xe1, 0xce, 0x28, 0x61, 0x21, 0x26, 0x28, 0x8d, 0x76, 0xcb, 0x30, 0xc1, 0x2e, 0x5b, 0x26, - 0x28, 0x73, 0x59, 0x98, 0x5d, 0x95, 0x87, 0x93, 0xa4, 0x94, 0x51, 0xf5, 0xd1, 0xbd, 0xcb, 0x79, - 0xf7, 0xdc, 0x29, 0x4d, 0x7a, 0x33, 0xa6, 0x31, 0x2d, 0xb9, 0xcb, 0xab, 0xca, 0xaa, 0x9b, 0x31, - 0xa5, 0xf1, 0x35, 0x72, 0xcb, 0x6e, 0x9a, 0xcf, 0x5d, 0x86, 0x17, 0x28, 0x63, 0xe1, 0x22, 0xa9, - 0x0d, 0x8f, 0xff, 0x36, 0x84, 0x64, 0x59, 0xa1, 0xf3, 0x42, 0x84, 0x87, 0x83, 0x94, 0xce, 0x50, - 0x96, 0xa9, 0x2d, 0x78, 0xbc, 0x7d, 0x74, 0x82, 0x23, 0x0d, 0x58, 0xc0, 0x3e, 0xea, 0x3c, 0x28, - 0xd6, 0xa6, 0xdc, 0xdd, 0xe8, 0x5e, 0x2f, 0x90, 0xb7, 0x26, 0x2f, 0x52, 0xcf, 0xa0, 0x88, 0x23, - 0x4d, 0x2c, 0x9d, 0x52, 0xb1, 0x36, 0x45, 0xaf, 0x17, 0x88, 0x38, 0x52, 0x15, 0xb8, 0x97, 0xe0, - 0x48, 0xdb, 0xb3, 0x80, 0x7d, 0x12, 0xf0, 0x52, 0xbd, 0x80, 0x52, 0xc6, 0x42, 0x96, 0x67, 0xda, - 0xbe, 0x05, 0xec, 0xd3, 0xd6, 0x13, 0xe7, 0x3f, 0x3f, 0x74, 0x86, 0xa5, 0x25, 0xa8, 0xad, 0x6a, - 0x13, 0x1e, 0x64, 0x2c, 0xc2, 0x44, 0x3b, 0xe0, 0x2f, 0x04, 0x55, 0xa3, 0x9e, 0xf1, 0x51, 0x11, - 0xcd, 0x99, 0x26, 0x95, 0x72, 0xdd, 0xd5, 0x3a, 0x4a, 0x53, 0xed, 0x70, 0xab, 0xa3, 0x34, 0x55, - 0x75, 0xd8, 0x60, 0x28, 0x5d, 0x60, 0x12, 0x5e, 0x6b, 0x0d, 0x0b, 0xd8, 0x8d, 0x60, 0xdb, 0xab, - 0x26, 0x94, 0xd1, 0x07, 0xcc, 0x26, 0xf5, 0x6e, 0x47, 0xe5, 0xc2, 0x90, 0x4b, 0xd5, 0x2a, 0x6a, - 0x1b, 0x1e, 0xf1, 0x0e, 0x45, 0x93, 0x90, 0x69, 0xd0, 0x02, 0xb6, 0xdc, 0xd2, 0x9d, 0x2a, 0x50, - 0x67, 0x13, 0xa8, 0x33, 0xda, 0x24, 0xde, 0x69, 0xac, 0xd6, 0xa6, 0xf0, 0xf9, 0x97, 0x09, 0x82, - 0x46, 0x75, 0xad, 0xcd, 0xce, 0x3d, 0x28, 0xd7, 0x19, 0x7b, 0x64, 0x4e, 0x37, 0xd9, 0x80, 0xfb, - 0x6c, 0x6c, 0xb8, 0x8f, 0xc9, 0x9c, 0x96, 0x39, 0xca, 0xad, 0xe6, 0x3f, 0xe3, 0xdb, 0x64, 0x19, - 0x94, 0x8e, 0x67, 0x3f, 0x00, 0x94, 0xea, 0xc5, 0x0c, 0x78, 0x38, 0xf6, 0x5f, 0xf9, 0x97, 0xaf, - 0x7d, 0x45, 0xd0, 0x1f, 0xde, 0xdc, 0x5a, 0x27, 0x15, 0x18, 0x93, 0x2b, 0x42, 0xdf, 0x13, 0xce, - 0xbb, 0x41, 0xbf, 0x3d, 0xea, 0xf7, 0x14, 0xb0, 0xcb, 0xbb, 0x29, 0x0a, 0x19, 0x8a, 0x38, 0x0f, - 0xc6, 0xbe, 0xef, 0xf9, 0x2f, 0x15, 0x71, 0x97, 0x07, 0x39, 0x21, 0x98, 0xc4, 0x9c, 0x0f, 0x47, - 0x97, 0x83, 0x41, 0xbf, 0xa7, 0xec, 0xed, 0xf2, 0x21, 0xa3, 0x49, 0x82, 0x22, 0xf5, 0x29, 0x94, - 0x06, 0xed, 0xf1, 0xb0, 0xdf, 0x53, 0xf6, 0x75, 0xe5, 0xe6, 0xd6, 0x3a, 0xae, 0xf0, 0x20, 0xcc, - 0xb3, 0x6a, 0x3a, 0xa7, 0x7c, 0xfa, 0xc1, 0xee, 0x6d, 0x8e, 0x31, 0x89, 0xf5, 0xd3, 0x4f, 0x5f, - 0x0c, 0xe1, 0xdb, 0x57, 0xa3, 0xfe, 0x4d, 0x47, 0x5b, 0xdd, 0x19, 0xc2, 0xcf, 0x3b, 0x43, 0xf8, - 0x58, 0x18, 0x60, 0x55, 0x18, 0xe0, 0x7b, 0x61, 0x80, 0xdf, 0x85, 0x01, 0xde, 0x08, 0x53, 0xa9, - 0x0c, 0xe2, 0xe2, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x32, 0xd2, 0x86, 0x50, 0x03, 0x00, - 0x00, -} diff -Nru containerd-1.2.6/api/types/task/task.proto containerd-1.5.9/api/types/task/task.proto --- containerd-1.2.6/api/types/task/task.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/api/types/task/task.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.v1.types; diff -Nru containerd-1.2.6/.appveyor.yml containerd-1.5.9/.appveyor.yml --- containerd-1.2.6/.appveyor.yml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.appveyor.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -version: "{build}" - -image: Visual Studio 2017 - -clone_folder: c:\gopath\src\github.com\containerd\containerd - -branches: - only: - - master - - release/1.2 - -environment: - GOPATH: C:\gopath - CGO_ENABLED: 1 - matrix: - - GO_VERSION: 1.11 - -before_build: - - choco install -y mingw --version 5.3.0 - # Install Go - - rd C:\Go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go%GO_VERSION%.windows-amd64.zip - - 7z x go%GO_VERSION%.windows-amd64.zip -oC:\ >nul - - go version - - choco install codecov - # Print host version. TODO: Remove this when containerd has a way to get host version - - ps: $psversiontable - -build_script: - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/bin:$PATH; - script/setup/install-dev-tools; - mingw32-make.exe check" - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:$PATH ; mingw32-make.exe build binaries" - -test_script: - # TODO: need an equivalent of TRAVIS_COMMIT_RANGE - # - GIT_CHECK_EXCLUDE="./vendor" TRAVIS_COMMIT_RANGE="${TRAVIS_COMMIT_RANGE/.../..}" C:\MinGW\bin\mingw32-make.exe dco - - bash.exe -lc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe coverage root-coverage" - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH ; mingw32-make.exe integration" - # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 - - bash.exe -elc "export PATH=/c/tools/mingw64/bin:/c/gopath/src/github.com/containerd/containerd/bin:$PATH; TESTFLAGS_PARALLEL=1 mingw32-make.exe integration" - -on_success: - codecov --flag windows -f coverage.txt diff -Nru containerd-1.2.6/archive/compression/compression.go containerd-1.5.9/archive/compression/compression.go --- containerd-1.2.6/archive/compression/compression.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/compression/compression.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,6 +29,7 @@ "sync" "github.com/containerd/containerd/log" + "github.com/klauspost/compress/zstd" ) type ( @@ -41,6 +42,8 @@ Uncompressed Compression = iota // Gzip is gzip compression algorithm. Gzip + // Zstd is zstd compression algorithm. + Zstd ) const disablePigzEnv = "CONTAINERD_DISABLE_PIGZ" @@ -126,6 +129,7 @@ func DetectCompression(source []byte) Compression { for compression, m := range map[Compression][]byte{ Gzip: {0x1F, 0x8B, 0x08}, + Zstd: {0x28, 0xb5, 0x2f, 0xfd}, } { if len(source) < len(m) { // Len too short @@ -174,19 +178,34 @@ return gzReader.Close() }, }, nil + case Zstd: + zstdReader, err := zstd.NewReader(buf) + if err != nil { + return nil, err + } + return &readCloserWrapper{ + Reader: zstdReader, + compression: compression, + closer: func() error { + zstdReader.Close() + return nil + }, + }, nil default: return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension()) } } -// CompressStream compresseses the dest with specified compression algorithm. +// CompressStream compresses the dest with specified compression algorithm. func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { switch compression { case Uncompressed: return &writeCloserWrapper{dest, nil}, nil case Gzip: return gzip.NewWriter(dest), nil + case Zstd: + return zstd.NewWriter(dest) default: return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension()) } @@ -197,6 +216,8 @@ switch *compression { case Gzip: return "gz" + case Zstd: + return "zst" } return "" } diff -Nru containerd-1.2.6/archive/strconv.go containerd-1.5.9/archive/strconv.go --- containerd-1.2.6/archive/strconv.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/strconv.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package archive - -import ( - "strconv" - "strings" - "time" - - "archive/tar" -) - -// Forked from https://github.com/golang/go/blob/master/src/archive/tar/strconv.go -// as archive/tar doesn't support CreationTime, but does handle PAX time parsing, -// and there's no need to re-invent the wheel. - -// parsePAXTime takes a string of the form %d.%d as described in the PAX -// specification. Note that this implementation allows for negative timestamps, -// which is allowed for by the PAX specification, but not always portable. -func parsePAXTime(s string) (time.Time, error) { - const maxNanoSecondDigits = 9 - - // Split string into seconds and sub-seconds parts. - ss, sn := s, "" - if pos := strings.IndexByte(s, '.'); pos >= 0 { - ss, sn = s[:pos], s[pos+1:] - } - - // Parse the seconds. - secs, err := strconv.ParseInt(ss, 10, 64) - if err != nil { - return time.Time{}, tar.ErrHeader - } - if len(sn) == 0 { - return time.Unix(secs, 0), nil // No sub-second values - } - - // Parse the nanoseconds. - if strings.Trim(sn, "0123456789") != "" { - return time.Time{}, tar.ErrHeader - } - if len(sn) < maxNanoSecondDigits { - sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad - } else { - sn = sn[:maxNanoSecondDigits] // Right truncate - } - nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed - if len(ss) > 0 && ss[0] == '-' { - return time.Unix(secs, -nsecs), nil // Negative correction - } - return time.Unix(secs, nsecs), nil -} diff -Nru containerd-1.2.6/archive/tar_freebsd.go containerd-1.5.9/archive/tar_freebsd.go --- containerd-1.2.6/archive/tar_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/archive/tar_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// mknod wraps unix.Mknod. FreeBSD's unix.Mknod signature is different from +// other Unix and Unix-like operating systems. +func mknod(path string, mode uint32, dev uint64) error { + return unix.Mknod(path, mode, dev) +} + +// lsetxattrCreate wraps unix.Lsetxattr with FreeBSD-specific flags and errors +func lsetxattrCreate(link string, attr string, data []byte) error { + err := unix.Lsetxattr(link, attr, data, 0) + if err == unix.ENOTSUP || err == unix.EEXIST { + return nil + } + return err +} + +func lchmod(path string, mode os.FileMode) error { + err := unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), unix.AT_SYMLINK_NOFOLLOW) + if err != nil { + err = &os.PathError{Op: "lchmod", Path: path, Err: err} + } + return err +} diff -Nru containerd-1.2.6/archive/tar.go containerd-1.5.9/archive/tar.go --- containerd-1.2.6/archive/tar.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,9 +19,7 @@ import ( "archive/tar" "context" - "fmt" "io" - "io/ioutil" "os" "path/filepath" "runtime" @@ -65,13 +63,34 @@ } // WriteDiff writes a tar stream of the computed difference between the -// provided directories. +// provided paths. // // Produces a tar using OCI style file markers for deletions. Deleted // files will be prepended with the prefix ".wh.". This style is // based off AUFS whiteouts. // See https://github.com/opencontainers/image-spec/blob/master/layer.md -func WriteDiff(ctx context.Context, w io.Writer, a, b string) error { +func WriteDiff(ctx context.Context, w io.Writer, a, b string, opts ...WriteDiffOpt) error { + var options WriteDiffOptions + for _, opt := range opts { + if err := opt(&options); err != nil { + return errors.Wrap(err, "failed to apply option") + } + } + if options.writeDiffFunc == nil { + options.writeDiffFunc = writeDiffNaive + } + + return options.writeDiffFunc(ctx, w, a, b, options) +} + +// writeDiffNaive writes a tar stream of the computed difference between the +// provided directories on disk. +// +// Produces a tar using OCI style file markers for deletions. Deleted +// files will be prepended with the prefix ".wh.". This style is +// based off AUFS whiteouts. +// See https://github.com/opencontainers/image-spec/blob/master/layer.md +func writeDiffNaive(ctx context.Context, w io.Writer, a, b string, _ WriteDiffOptions) error { cw := newChangeWriter(w, b) err := fs.Changes(ctx, a, b, cw.HandleChange) if err != nil { @@ -91,11 +110,6 @@ // archives. whiteoutMetaPrefix = whiteoutPrefix + whiteoutPrefix - // whiteoutLinkDir is a directory AUFS uses for storing hardlink links to other - // layers. Normally these should not go into exported archives and all changed - // hardlinks should be copied to the top layer. - whiteoutLinkDir = whiteoutMetaPrefix + "plnk" - // whiteoutOpaqueDir file means directory has been made opaque - meaning // readdir calls to this directory do not follow to lower layers. whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq" @@ -117,25 +131,69 @@ if options.Filter == nil { options.Filter = all } + if options.applyFunc == nil { + options.applyFunc = applyNaive + } - return apply(ctx, root, tar.NewReader(r), options) + return options.applyFunc(ctx, root, r, options) } -// applyNaive applies a tar stream of an OCI style diff tar. +// applyNaive applies a tar stream of an OCI style diff tar to a directory +// applying each file as either a whole file or whiteout. // See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets -func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { +func applyNaive(ctx context.Context, root string, r io.Reader, options ApplyOptions) (size int64, err error) { var ( dirs []*tar.Header + tr = tar.NewReader(r) + // Used for handling opaque directory markers which // may occur out of order unpackedPaths = make(map[string]struct{}) - // Used for aufs plink directory - aufsTempdir = "" - aufsHardlinks = make(map[string]*tar.Header) + convertWhiteout = options.ConvertWhiteout ) + if convertWhiteout == nil { + // handle whiteouts by removing the target files + convertWhiteout = func(hdr *tar.Header, path string) (bool, error) { + base := filepath.Base(path) + dir := filepath.Dir(path) + if base == whiteoutOpaqueDir { + _, err := os.Lstat(dir) + if err != nil { + return false, err + } + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + if os.IsNotExist(err) { + err = nil // parent was deleted + } + return err + } + if path == dir { + return nil + } + if _, exists := unpackedPaths[path]; !exists { + err := os.RemoveAll(path) + return err + } + return nil + }) + return false, err + } + + if strings.HasPrefix(base, whiteoutPrefix) { + originalBase := base[len(whiteoutPrefix):] + originalPath := filepath.Join(dir, originalBase) + + return false, os.RemoveAll(originalPath) + } + + return true, nil + } + } + // Iterate through the files in the archive. for { select { @@ -193,85 +251,21 @@ if base == "" { parentPath = filepath.Dir(path) } - if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) { - err = mkdirAll(parentPath, 0755) - if err != nil { - return 0, err - } + if err := mkparent(ctx, parentPath, root, options.Parents); err != nil { + return 0, err } } - // Skip AUFS metadata dirs - if strings.HasPrefix(hdr.Name, whiteoutMetaPrefix) { - // Regular files inside /.wh..wh.plnk can be used as hardlink targets - // We don't want this directory, but we need the files in them so that - // such hardlinks can be resolved. - if strings.HasPrefix(hdr.Name, whiteoutLinkDir) && hdr.Typeflag == tar.TypeReg { - basename := filepath.Base(hdr.Name) - aufsHardlinks[basename] = hdr - if aufsTempdir == "" { - if aufsTempdir, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "dockerplnk"); err != nil { - return 0, err - } - defer os.RemoveAll(aufsTempdir) - } - p, err := fs.RootPath(aufsTempdir, basename) - if err != nil { - return 0, err - } - if err := createTarFile(ctx, p, root, hdr, tr); err != nil { - return 0, err - } - } - - if hdr.Name != whiteoutOpaqueDir { - continue - } + // Naive whiteout convert function which handles whiteout files by + // removing the target files. + if err := validateWhiteout(path); err != nil { + return 0, err } - - if strings.HasPrefix(base, whiteoutPrefix) { - dir := filepath.Dir(path) - if base == whiteoutOpaqueDir { - _, err := os.Lstat(dir) - if err != nil { - return 0, err - } - err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if err != nil { - if os.IsNotExist(err) { - err = nil // parent was deleted - } - return err - } - if path == dir { - return nil - } - if _, exists := unpackedPaths[path]; !exists { - err := os.RemoveAll(path) - return err - } - return nil - }) - if err != nil { - return 0, err - } - continue - } - - originalBase := base[len(whiteoutPrefix):] - originalPath := filepath.Join(dir, originalBase) - - // Ensure originalPath is under dir - if dir[len(dir)-1] != filepath.Separator { - dir += string(filepath.Separator) - } - if !strings.HasPrefix(originalPath, dir) { - return 0, errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base) - } - - if err := os.RemoveAll(originalPath); err != nil { - return 0, err - } + writeFile, err := convertWhiteout(hdr, path) + if err != nil { + return 0, errors.Wrapf(err, "failed to convert whiteout file %q", hdr.Name) + } + if !writeFile { continue } // If path exits we almost always just want to remove and replace it. @@ -289,26 +283,6 @@ srcData := io.Reader(tr) srcHdr := hdr - // Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so - // we manually retarget these into the temporary files we extracted them into - if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), whiteoutLinkDir) { - linkBasename := filepath.Base(hdr.Linkname) - srcHdr = aufsHardlinks[linkBasename] - if srcHdr == nil { - return 0, fmt.Errorf("invalid aufs hardlink") - } - p, err := fs.RootPath(aufsTempdir, linkBasename) - if err != nil { - return 0, err - } - tmpFile, err := os.Open(p) - if err != nil { - return 0, err - } - defer tmpFile.Close() - srcData = tmpFile - } - if err := createTarFile(ctx, path, root, srcHdr, srcData); err != nil { return 0, err } @@ -410,7 +384,7 @@ if strings.HasPrefix(key, paxSchilyXattr) { key = key[len(paxSchilyXattr):] if err := setxattr(path, key, value); err != nil { - if errors.Cause(err) == syscall.ENOTSUP { + if errors.Is(err, syscall.ENOTSUP) { log.G(ctx).WithError(err).Warnf("ignored xattr %s in archive", key) continue } @@ -419,15 +393,74 @@ } } - // There is no LChmod, so ignore mode for symlink. Also, this - // must happen after chown, as that can modify the file mode - if err := handleLChmod(hdr, path, hdrInfo); err != nil { + // call lchmod after lchown since lchown can modify the file mode + if err := lchmod(path, hdrInfo.Mode()); err != nil { return err } return chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)) } +func mkparent(ctx context.Context, path, root string, parents []string) error { + if dir, err := os.Lstat(path); err == nil { + if dir.IsDir() { + return nil + } + return &os.PathError{ + Op: "mkparent", + Path: path, + Err: syscall.ENOTDIR, + } + } else if !os.IsNotExist(err) { + return err + } + + i := len(path) + for i > len(root) && !os.IsPathSeparator(path[i-1]) { + i-- + } + + if i > len(root)+1 { + if err := mkparent(ctx, path[:i-1], root, parents); err != nil { + return err + } + } + + if err := mkdir(path, 0755); err != nil { + // Check that still doesn't exist + dir, err1 := os.Lstat(path) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + + for _, p := range parents { + ppath, err := fs.RootPath(p, path[len(root):]) + if err != nil { + return err + } + + dir, err := os.Lstat(ppath) + if err == nil { + if !dir.IsDir() { + // Replaced, do not copy attributes + break + } + if err := copyDirInfo(dir, path); err != nil { + return err + } + return copyUpXAttrs(path, ppath) + } else if !os.IsNotExist(err) { + return err + } + } + + log.G(ctx).Debugf("parent directory %q not found: default permissions(0755) used", path) + + return nil +} + type changeWriter struct { tw *tar.Writer source string @@ -493,6 +526,12 @@ hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) + // truncate timestamp for compatibility. without PAX stdlib rounds timestamps instead + hdr.Format = tar.FormatPAX + hdr.ModTime = hdr.ModTime.Truncate(time.Second) + hdr.AccessTime = time.Time{} + hdr.ChangeTime = time.Time{} + name := p if strings.HasPrefix(name, string(filepath.Separator)) { name, err = filepath.Rel(string(filepath.Separator), name) @@ -598,6 +637,9 @@ } func (cw *changeWriter) includeParents(hdr *tar.Header) error { + if cw.addedDirs == nil { + return nil + } name := strings.TrimRight(hdr.Name, "/") fname := filepath.Join(cw.source, name) parent := filepath.Dir(name) @@ -684,3 +726,26 @@ } return targetPath, nil } + +func validateWhiteout(path string) error { + base := filepath.Base(path) + dir := filepath.Dir(path) + + if base == whiteoutOpaqueDir { + return nil + } + + if strings.HasPrefix(base, whiteoutPrefix) { + originalBase := base[len(whiteoutPrefix):] + originalPath := filepath.Join(dir, originalBase) + + // Ensure originalPath is under dir + if dir[len(dir)-1] != filepath.Separator { + dir += string(filepath.Separator) + } + if !strings.HasPrefix(originalPath, dir) { + return errors.Wrapf(errInvalidArchive, "invalid whiteout name: %v", base) + } + } + return nil +} diff -Nru containerd-1.2.6/archive/tar_linux_test.go containerd-1.5.9/archive/tar_linux_test.go --- containerd-1.2.6/archive/tar_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/archive/tar_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,183 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "testing" + + "github.com/containerd/containerd/log/logtest" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/snapshots/overlay/overlayutils" + "github.com/containerd/continuity/fs" + "github.com/containerd/continuity/fs/fstest" + "github.com/pkg/errors" +) + +func TestOverlayApply(t *testing.T) { + testutil.RequiresRoot(t) + + base, err := ioutil.TempDir("", "test-ovl-diff-apply-") + if err != nil { + t.Fatalf("unable to create temp dir: %+v", err) + } + defer os.RemoveAll(base) + + if err := overlayutils.Supported(base); err != nil { + t.Skipf("skipping because overlay is not supported %v", err) + } + fstest.FSSuite(t, overlayDiffApplier{ + tmp: base, + diff: WriteDiff, + t: t, + }) +} + +func TestOverlayApplyNoParents(t *testing.T) { + testutil.RequiresRoot(t) + + base, err := ioutil.TempDir("", "test-ovl-diff-apply-") + if err != nil { + t.Fatalf("unable to create temp dir: %+v", err) + } + defer os.RemoveAll(base) + + if err := overlayutils.Supported(base); err != nil { + t.Skipf("skipping because overlay is not supported %v", err) + } + fstest.FSSuite(t, overlayDiffApplier{ + tmp: base, + diff: func(ctx context.Context, w io.Writer, a, b string, _ ...WriteDiffOpt) error { + cw := newChangeWriter(w, b) + cw.addedDirs = nil + err := fs.Changes(ctx, a, b, cw.HandleChange) + if err != nil { + return errors.Wrap(err, "failed to create diff tar stream") + } + return cw.Close() + }, + t: t, + }) +} + +type overlayDiffApplier struct { + tmp string + diff func(context.Context, io.Writer, string, string, ...WriteDiffOpt) error + t *testing.T +} + +type overlayContext struct { + merged string + lowers []string + mounted bool +} + +type contextKey struct{} + +func (d overlayDiffApplier) TestContext(ctx context.Context) (context.Context, func(), error) { + merged, err := ioutil.TempDir(d.tmp, "merged") + if err != nil { + return ctx, nil, errors.Wrap(err, "failed to make merged dir") + } + + oc := &overlayContext{ + merged: merged, + } + + ctx = logtest.WithT(ctx, d.t) + + return context.WithValue(ctx, contextKey{}, oc), func() { + if oc.mounted { + mount.Unmount(oc.merged, 0) + } + }, nil +} + +func (d overlayDiffApplier) Apply(ctx context.Context, a fstest.Applier) (string, func(), error) { + oc := ctx.Value(contextKey{}).(*overlayContext) + + applyCopy, err := ioutil.TempDir(d.tmp, "apply-copy-") + if err != nil { + return "", nil, errors.Wrap(err, "failed to create temp dir") + } + defer os.RemoveAll(applyCopy) + + base := oc.merged + if len(oc.lowers) == 1 { + base = oc.lowers[0] + } + + if err = fs.CopyDir(applyCopy, base); err != nil { + return "", nil, errors.Wrap(err, "failed to copy base") + } + + if err := a.Apply(applyCopy); err != nil { + return "", nil, errors.Wrap(err, "failed to apply changes to copy of base") + } + + buf := bytes.NewBuffer(nil) + + if err := d.diff(ctx, buf, base, applyCopy); err != nil { + return "", nil, errors.Wrap(err, "failed to create diff") + } + + if oc.mounted { + if err := mount.Unmount(oc.merged, 0); err != nil { + return "", nil, errors.Wrap(err, "failed to unmount") + } + oc.mounted = false + } + + next, err := ioutil.TempDir(d.tmp, "lower-") + if err != nil { + return "", nil, errors.Wrap(err, "failed to create temp dir") + } + + if _, err = Apply(ctx, next, buf, WithConvertWhiteout(OverlayConvertWhiteout), WithParents(oc.lowers)); err != nil { + return "", nil, errors.Wrap(err, "failed to apply tar stream") + } + + oc.lowers = append([]string{next}, oc.lowers...) + + if len(oc.lowers) == 1 { + return oc.lowers[0], nil, nil + } + + m := mount.Mount{ + Type: "overlay", + Source: "overlay", + Options: []string{ + fmt.Sprintf("lowerdir=%s", strings.Join(oc.lowers, ":")), + }, + } + + if err := m.Mount(oc.merged); err != nil { + return "", nil, errors.Wrapf(err, "failed to mount: %v", m) + } + oc.mounted = true + + return oc.merged, nil, nil +} diff -Nru containerd-1.2.6/archive/tar_mostunix.go containerd-1.5.9/archive/tar_mostunix.go --- containerd-1.2.6/archive/tar_mostunix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/archive/tar_mostunix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +// +build !windows,!freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// mknod wraps Unix.Mknod and casts dev to int +func mknod(path string, mode uint32, dev uint64) error { + return unix.Mknod(path, mode, int(dev)) +} + +// lsetxattrCreate wraps unix.Lsetxattr, passes the unix.XATTR_CREATE flag on +// supported operating systems,and ignores appropriate errors +func lsetxattrCreate(link string, attr string, data []byte) error { + err := unix.Lsetxattr(link, attr, data, unix.XATTR_CREATE) + if err == unix.ENOTSUP || err == unix.ENODATA || err == unix.EEXIST { + return nil + } + return err +} + +// lchmod checks for symlink and changes the mode if not a symlink +func lchmod(path string, mode os.FileMode) error { + fi, err := os.Lstat(path) + if err != nil { + return err + } + + if fi.Mode()&os.ModeSymlink == 0 { + if err := os.Chmod(path, mode); err != nil { + return err + } + } + return nil +} diff -Nru containerd-1.2.6/archive/tar_opts.go containerd-1.5.9/archive/tar_opts.go --- containerd-1.2.6/archive/tar_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,7 +16,20 @@ package archive -import "archive/tar" +import ( + "archive/tar" + "context" + "io" +) + +// ApplyOptions provides additional options for an Apply operation +type ApplyOptions struct { + Filter Filter // Filter tar headers + ConvertWhiteout ConvertWhiteout // Convert whiteout files + Parents []string // Parent directories to handle inherited attributes without CoW + + applyFunc func(context.Context, string, io.Reader, ApplyOptions) (int64, error) +} // ApplyOpt allows setting mutable archive apply properties on creation type ApplyOpt func(options *ApplyOptions) error @@ -24,6 +37,9 @@ // Filter specific files from the archive type Filter func(*tar.Header) (bool, error) +// ConvertWhiteout converts whiteout files from the archive +type ConvertWhiteout func(*tar.Header, string) (bool, error) + // all allows all files func all(_ *tar.Header) (bool, error) { return true, nil @@ -36,3 +52,34 @@ return nil } } + +// WithConvertWhiteout uses the convert function to convert the whiteout files. +func WithConvertWhiteout(c ConvertWhiteout) ApplyOpt { + return func(options *ApplyOptions) error { + options.ConvertWhiteout = c + return nil + } +} + +// WithParents provides parent directories for resolving inherited attributes +// directory from the filesystem. +// Inherited attributes are searched from first to last, making the first +// element in the list the most immediate parent directory. +// NOTE: When applying to a filesystem which supports CoW, file attributes +// should be inherited by the filesystem. +func WithParents(p []string) ApplyOpt { + return func(options *ApplyOptions) error { + options.Parents = p + return nil + } +} + +// WriteDiffOptions provides additional options for a WriteDiff operation +type WriteDiffOptions struct { + ParentLayers []string // Windows needs the full list of parent layers + + writeDiffFunc func(context.Context, io.Writer, string, string, WriteDiffOptions) error +} + +// WriteDiffOpt allows setting mutable archive write properties on creation +type WriteDiffOpt func(options *WriteDiffOptions) error diff -Nru containerd-1.2.6/archive/tar_opts_linux.go containerd-1.5.9/archive/tar_opts_linux.go --- containerd-1.2.6/archive/tar_opts_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/archive/tar_opts_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,59 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "archive/tar" + "os" + "path/filepath" + "strings" + + "golang.org/x/sys/unix" +) + +// AufsConvertWhiteout converts whiteout files for aufs. +func AufsConvertWhiteout(_ *tar.Header, _ string) (bool, error) { + return true, nil +} + +// OverlayConvertWhiteout converts whiteout files for overlay. +func OverlayConvertWhiteout(hdr *tar.Header, path string) (bool, error) { + base := filepath.Base(path) + dir := filepath.Dir(path) + + // if a directory is marked as opaque, we need to translate that to overlay + if base == whiteoutOpaqueDir { + // don't write the file itself + return false, unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0) + } + + // if a file was deleted and we are using overlay, we need to create a character device + if strings.HasPrefix(base, whiteoutPrefix) { + originalBase := base[len(whiteoutPrefix):] + originalPath := filepath.Join(dir, originalBase) + + if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil { + return false, err + } + // don't write the file itself + return false, os.Chown(originalPath, hdr.Uid, hdr.Gid) + } + + return true, nil +} diff -Nru containerd-1.2.6/archive/tar_opts_unix.go containerd-1.5.9/archive/tar_opts_unix.go --- containerd-1.2.6/archive/tar_opts_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_opts_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package archive - -// ApplyOptions provides additional options for an Apply operation -type ApplyOptions struct { - Filter Filter // Filter tar headers -} diff -Nru containerd-1.2.6/archive/tar_opts_windows.go containerd-1.5.9/archive/tar_opts_windows.go --- containerd-1.2.6/archive/tar_opts_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_opts_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,20 +18,17 @@ package archive -// ApplyOptions provides additional options for an Apply operation -type ApplyOptions struct { - ParentLayerPaths []string // Parent layer paths used for Windows layer apply - IsWindowsContainerLayer bool // True if the tar stream to be applied is a Windows Container Layer - Filter Filter // Filter tar headers -} +import ( + "context" + "io" -// WithParentLayers adds parent layers to the apply process this is required -// for all Windows layers except the base layer. -func WithParentLayers(parentPaths []string) ApplyOpt { - return func(options *ApplyOptions) error { - options.ParentLayerPaths = parentPaths - return nil - } + "github.com/Microsoft/hcsshim/pkg/ociwclayer" +) + +// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows layer +// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets +func applyWindowsLayer(ctx context.Context, root string, r io.Reader, options ApplyOptions) (size int64, err error) { + return ociwclayer.ImportLayerFromTar(ctx, r, root, options.Parents) } // AsWindowsContainerLayer indicates that the tar stream to apply is that of @@ -39,7 +36,37 @@ // SeRestorePrivilege. func AsWindowsContainerLayer() ApplyOpt { return func(options *ApplyOptions) error { - options.IsWindowsContainerLayer = true + options.applyFunc = applyWindowsLayer + return nil + } +} + +// writeDiffWindowsLayers writes a tar stream of the computed difference between the +// provided Windows layers +// +// Produces a tar using OCI style file markers for deletions. Deleted +// files will be prepended with the prefix ".wh.". This style is +// based off AUFS whiteouts. +// See https://github.com/opencontainers/image-spec/blob/master/layer.md +func writeDiffWindowsLayers(ctx context.Context, w io.Writer, _, layer string, options WriteDiffOptions) error { + return ociwclayer.ExportLayerToTar(ctx, w, layer, options.ParentLayers) +} + +// AsWindowsContainerLayerPair indicates that the paths to diff are a pair of +// Windows Container Layers. The caller must be holding SeBackupPrivilege. +func AsWindowsContainerLayerPair() WriteDiffOpt { + return func(options *WriteDiffOptions) error { + options.writeDiffFunc = writeDiffWindowsLayers + return nil + } +} + +// WithParentLayers provides the Windows Container Layers that are the parents +// of the target (right-hand, "upper") layer, if any. The source (left-hand, "lower") +// layer passed to WriteDiff should be "" in this case. +func WithParentLayers(p []string) WriteDiffOpt { + return func(options *WriteDiffOptions) error { + options.ParentLayers = p return nil } } diff -Nru containerd-1.2.6/archive/tartest/tar.go containerd-1.5.9/archive/tartest/tar.go --- containerd-1.2.6/archive/tartest/tar.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tartest/tar.go 2022-01-05 17:30:58.000000000 +0000 @@ -49,7 +49,7 @@ } // TarFromWriterTo is used to create a tar stream from a tar record -// creator. This can be used to manifacture more specific tar records +// creator. This can be used to manufacture more specific tar records // which allow testing specific tar cases which may be encountered // by the untar process. func TarFromWriterTo(wt WriterToTar) io.ReadCloser { diff -Nru containerd-1.2.6/archive/tar_test.go containerd-1.5.9/archive/tar_test.go --- containerd-1.2.6/archive/tar_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!darwin /* Copyright The containerd Authors. @@ -243,6 +243,11 @@ return nil } errFileDiff := errors.New("files differ") + td, err := ioutil.TempDir("", "test-breakouts-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(td) isSymlinkFile := func(f string) func(string) error { return func(root string) error { @@ -317,7 +322,7 @@ if err == nil { return errors.New("files are the same, expected diff") } - if errors.Cause(err) != errFileDiff { + if !errors.Is(err, errFileDiff) { return err } return nil @@ -744,6 +749,36 @@ // resolution ends up just removing etc validator: fileNotExists("etc/passwd"), }, + { + + name: "HardlinkSymlinkChmod", + w: func() tartest.WriterToTar { + p := filepath.Join(td, "perm400") + if err := ioutil.WriteFile(p, []byte("..."), 0400); err != nil { + t.Fatal(err) + } + ep := filepath.Join(td, "also-exists-outside-root") + if err := ioutil.WriteFile(ep, []byte("..."), 0640); err != nil { + t.Fatal(err) + } + + return tartest.TarAll( + tc.Symlink(p, ep), + tc.Link(ep, "sketchylink"), + ) + }(), + validator: func(string) error { + p := filepath.Join(td, "perm400") + fi, err := os.Lstat(p) + if err != nil { + return err + } + if perm := fi.Mode() & os.ModePerm; perm != 0400 { + return errors.Errorf("%s perm changed from 0400 to %04o", p, perm) + } + return nil + }, + }, } for _, bo := range breakouts { @@ -932,7 +967,7 @@ if _, err := Apply(context.Background(), td, tr); err != nil { if applyErr == nil { t.Fatalf("Failed to apply tar: %v", err) - } else if errors.Cause(err) != applyErr { + } else if !errors.Is(err, applyErr) { t.Fatalf("Unexpected apply error: %v, expected %v", err, applyErr) } return diff -Nru containerd-1.2.6/archive/tar_unix.go containerd-1.5.9/archive/tar_unix.go --- containerd-1.2.6/archive/tar_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,13 +20,13 @@ import ( "archive/tar" - "context" "os" - "sync" + "strings" "syscall" + "github.com/containerd/containerd/pkg/userns" + "github.com/containerd/continuity/fs" "github.com/containerd/continuity/sysx" - "github.com/opencontainers/runc/libcontainer/system" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -74,10 +74,6 @@ return f, err } -func mkdirAll(path string, perm os.FileMode) error { - return os.MkdirAll(path, perm) -} - func mkdir(path string, perm os.FileMode) error { if err := os.Mkdir(path, perm); err != nil { return err @@ -87,21 +83,11 @@ return os.Chmod(path, perm) } -var ( - inUserNS bool - nsOnce sync.Once -) - -func setInUserNS() { - inUserNS = system.RunningInUserNS() -} - func skipFile(hdr *tar.Header) bool { switch hdr.Typeflag { case tar.TypeBlock, tar.TypeChar: // cannot create a device if running in user namespace - nsOnce.Do(setInUserNS) - return inUserNS + return userns.RunningInUserNS() default: return false } @@ -122,22 +108,7 @@ mode |= unix.S_IFIFO } - return unix.Mknod(path, mode, int(unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))) -} - -func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { - if hdr.Typeflag == tar.TypeLink { - if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { - if err := os.Chmod(path, hdrInfo.Mode()); err != nil { - return err - } - } - } else if hdr.Typeflag != tar.TypeSymlink { - if err := os.Chmod(path, hdrInfo.Mode()); err != nil { - return err - } - } - return nil + return mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor))) } func getxattr(path, attr string) ([]byte, error) { @@ -149,11 +120,71 @@ } func setxattr(path, key, value string) error { - return sysx.LSetxattr(path, key, []byte(value), 0) + // Do not set trusted attributes + if strings.HasPrefix(key, "trusted.") { + return errors.Wrap(unix.ENOTSUP, "admin attributes from archive not supported") + } + return unix.Lsetxattr(path, key, []byte(value), 0) +} + +func copyDirInfo(fi os.FileInfo, path string) error { + st := fi.Sys().(*syscall.Stat_t) + if err := os.Lchown(path, int(st.Uid), int(st.Gid)); err != nil { + if os.IsPermission(err) { + // Normally if uid/gid are the same this would be a no-op, but some + // filesystems may still return EPERM... for instance NFS does this. + // In such a case, this is not an error. + if dstStat, err2 := os.Lstat(path); err2 == nil { + st2 := dstStat.Sys().(*syscall.Stat_t) + if st.Uid == st2.Uid && st.Gid == st2.Gid { + err = nil + } + } + } + if err != nil { + return errors.Wrapf(err, "failed to chown %s", path) + } + } + + if err := os.Chmod(path, fi.Mode()); err != nil { + return errors.Wrapf(err, "failed to chmod %s", path) + } + + timespec := []unix.Timespec{ + unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatAtime(st))), + unix.NsecToTimespec(syscall.TimespecToNsec(fs.StatMtime(st))), + } + if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { + return errors.Wrapf(err, "failed to utime %s", path) + } + + return nil } -// apply applies a tar stream of an OCI style diff tar. -// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets -func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { - return applyNaive(ctx, root, tr, options) +func copyUpXAttrs(dst, src string) error { + xattrKeys, err := sysx.LListxattr(src) + if err != nil { + if err == unix.ENOTSUP || err == sysx.ENODATA { + return nil + } + return errors.Wrapf(err, "failed to list xattrs on %s", src) + } + for _, xattr := range xattrKeys { + // Do not copy up trusted attributes + if strings.HasPrefix(xattr, "trusted.") { + continue + } + data, err := sysx.LGetxattr(src, xattr) + if err != nil { + if err == unix.ENOTSUP || err == sysx.ENODATA { + continue + } + return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + } + if err := lsetxattrCreate(dst, xattr, data); err != nil { + return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + } + } + + return nil } diff -Nru containerd-1.2.6/archive/tar_windows.go containerd-1.5.9/archive/tar_windows.go --- containerd-1.2.6/archive/tar_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/tar_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,49 +20,12 @@ import ( "archive/tar" - "bufio" - "context" - "encoding/base64" - "errors" "fmt" - "io" "os" - "path" - "path/filepath" - "strconv" "strings" - "syscall" - "github.com/Microsoft/go-winio" - "github.com/Microsoft/hcsshim" "github.com/containerd/containerd/sys" -) - -const ( - // MSWINDOWS pax vendor extensions - hdrMSWindowsPrefix = "MSWINDOWS." - - hdrFileAttributes = hdrMSWindowsPrefix + "fileattr" - hdrSecurityDescriptor = hdrMSWindowsPrefix + "sd" - hdrRawSecurityDescriptor = hdrMSWindowsPrefix + "rawsd" - hdrMountPoint = hdrMSWindowsPrefix + "mountpoint" - hdrEaPrefix = hdrMSWindowsPrefix + "xattr." - - // LIBARCHIVE pax vendor extensions - hdrLibArchivePrefix = "LIBARCHIVE." - - hdrCreateTime = hdrLibArchivePrefix + "creationtime" -) - -var ( - // mutatedFiles is a list of files that are mutated by the import process - // and must be backed up and restored. - mutatedFiles = map[string]string{ - "UtilityVM/Files/EFI/Microsoft/Boot/BCD": "bcd.bak", - "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG": "bcd.log.bak", - "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak", - "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak", - } + "github.com/pkg/errors" ) // tarName returns platform-specific filepath @@ -107,10 +70,6 @@ return sys.OpenFileSequential(name, flag, perm) } -func mkdirAll(path string, perm os.FileMode) error { - return sys.MkdirAll(path, perm) -} - func mkdir(path string, perm os.FileMode) error { return os.Mkdir(path, perm) } @@ -139,7 +98,7 @@ return nil } -func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { +func lchmod(path string, mode os.FileMode) error { return nil } @@ -153,293 +112,13 @@ return errors.New("xattrs not supported on Windows") } -// apply applies a tar stream of an OCI style diff tar of a Windows layer. -// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets -func apply(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { - if options.IsWindowsContainerLayer { - return applyWindowsLayer(ctx, root, tr, options) - } - return applyNaive(ctx, root, tr, options) -} - -// applyWindowsLayer applies a tar stream of an OCI style diff tar of a Windows layer. -// See https://github.com/opencontainers/image-spec/blob/master/layer.md#applying-changesets -func applyWindowsLayer(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) { - home, id := filepath.Split(root) - info := hcsshim.DriverInfo{ - HomeDir: home, - } - - w, err := hcsshim.NewLayerWriter(info, id, options.ParentLayerPaths) - if err != nil { - return 0, err - } - defer func() { - if err2 := w.Close(); err2 != nil { - // This error should not be discarded as a failure here - // could result in an invalid layer on disk - if err == nil { - err = err2 - } - } - }() - - buf := bufio.NewWriter(nil) - hdr, nextErr := tr.Next() - // Iterate through the files in the archive. - for { - select { - case <-ctx.Done(): - return 0, ctx.Err() - default: - } - - if nextErr == io.EOF { - // end of tar archive - break - } - if nextErr != nil { - return 0, nextErr - } - - // Note: path is used instead of filepath to prevent OS specific handling - // of the tar path - base := path.Base(hdr.Name) - if strings.HasPrefix(base, whiteoutPrefix) { - dir := path.Dir(hdr.Name) - originalBase := base[len(whiteoutPrefix):] - originalPath := path.Join(dir, originalBase) - if err := w.Remove(filepath.FromSlash(originalPath)); err != nil { - return 0, err - } - hdr, nextErr = tr.Next() - } else if hdr.Typeflag == tar.TypeLink { - err := w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname)) - if err != nil { - return 0, err - } - hdr, nextErr = tr.Next() - } else { - name, fileSize, fileInfo, err := fileInfoFromHeader(hdr) - if err != nil { - return 0, err - } - if err := w.Add(filepath.FromSlash(name), fileInfo); err != nil { - return 0, err - } - size += fileSize - hdr, nextErr = tarToBackupStreamWithMutatedFiles(buf, w, tr, hdr, root) - } - } - - return -} - -// fileInfoFromHeader retrieves basic Win32 file information from a tar header, using the additional metadata written by -// WriteTarFileFromBackupStream. -func fileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *winio.FileBasicInfo, err error) { - name = hdr.Name - if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { - size = hdr.Size +func copyDirInfo(fi os.FileInfo, path string) error { + if err := os.Chmod(path, fi.Mode()); err != nil { + return errors.Wrapf(err, "failed to chmod %s", path) } - fileInfo = &winio.FileBasicInfo{ - LastAccessTime: syscall.NsecToFiletime(hdr.AccessTime.UnixNano()), - LastWriteTime: syscall.NsecToFiletime(hdr.ModTime.UnixNano()), - ChangeTime: syscall.NsecToFiletime(hdr.ChangeTime.UnixNano()), - - // Default CreationTime to ModTime, updated below if MSWINDOWS.createtime exists - CreationTime: syscall.NsecToFiletime(hdr.ModTime.UnixNano()), - } - if attrStr, ok := hdr.PAXRecords[hdrFileAttributes]; ok { - attr, err := strconv.ParseUint(attrStr, 10, 32) - if err != nil { - return "", 0, nil, err - } - fileInfo.FileAttributes = uint32(attr) - } else { - if hdr.Typeflag == tar.TypeDir { - fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY - } - } - if createStr, ok := hdr.PAXRecords[hdrCreateTime]; ok { - createTime, err := parsePAXTime(createStr) - if err != nil { - return "", 0, nil, err - } - fileInfo.CreationTime = syscall.NsecToFiletime(createTime.UnixNano()) - } - return + return nil } -// tarToBackupStreamWithMutatedFiles reads data from a tar stream and -// writes it to a backup stream, and also saves any files that will be mutated -// by the import layer process to a backup location. -func tarToBackupStreamWithMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) { - var ( - bcdBackup *os.File - bcdBackupWriter *winio.BackupFileWriter - ) - if backupPath, ok := mutatedFiles[hdr.Name]; ok { - bcdBackup, err = os.Create(filepath.Join(root, backupPath)) - if err != nil { - return nil, err - } - defer func() { - cerr := bcdBackup.Close() - if err == nil { - err = cerr - } - }() - - bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false) - defer func() { - cerr := bcdBackupWriter.Close() - if err == nil { - err = cerr - } - }() - - buf.Reset(io.MultiWriter(w, bcdBackupWriter)) - } else { - buf.Reset(w) - } - - defer func() { - ferr := buf.Flush() - if err == nil { - err = ferr - } - }() - - return writeBackupStreamFromTarFile(buf, t, hdr) -} - -// writeBackupStreamFromTarFile writes a Win32 backup stream from the current tar file. Since this function may process multiple -// tar file entries in order to collect all the alternate data streams for the file, it returns the next -// tar file that was not processed, or io.EOF is there are no more. -func writeBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) { - bw := winio.NewBackupStreamWriter(w) - var sd []byte - var err error - // Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written - // by this library will have raw binary for the security descriptor. - if sddl, ok := hdr.PAXRecords[hdrSecurityDescriptor]; ok { - sd, err = winio.SddlToSecurityDescriptor(sddl) - if err != nil { - return nil, err - } - } - if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok { - sd, err = base64.StdEncoding.DecodeString(sdraw) - if err != nil { - return nil, err - } - } - if len(sd) != 0 { - bhdr := winio.BackupHeader{ - Id: winio.BackupSecurity, - Size: int64(len(sd)), - } - err := bw.WriteHeader(&bhdr) - if err != nil { - return nil, err - } - _, err = bw.Write(sd) - if err != nil { - return nil, err - } - } - var eas []winio.ExtendedAttribute - for k, v := range hdr.PAXRecords { - if !strings.HasPrefix(k, hdrEaPrefix) { - continue - } - data, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return nil, err - } - eas = append(eas, winio.ExtendedAttribute{ - Name: k[len(hdrEaPrefix):], - Value: data, - }) - } - if len(eas) != 0 { - eadata, err := winio.EncodeExtendedAttributes(eas) - if err != nil { - return nil, err - } - bhdr := winio.BackupHeader{ - Id: winio.BackupEaData, - Size: int64(len(eadata)), - } - err = bw.WriteHeader(&bhdr) - if err != nil { - return nil, err - } - _, err = bw.Write(eadata) - if err != nil { - return nil, err - } - } - if hdr.Typeflag == tar.TypeSymlink { - _, isMountPoint := hdr.PAXRecords[hdrMountPoint] - rp := winio.ReparsePoint{ - Target: filepath.FromSlash(hdr.Linkname), - IsMountPoint: isMountPoint, - } - reparse := winio.EncodeReparsePoint(&rp) - bhdr := winio.BackupHeader{ - Id: winio.BackupReparseData, - Size: int64(len(reparse)), - } - err := bw.WriteHeader(&bhdr) - if err != nil { - return nil, err - } - _, err = bw.Write(reparse) - if err != nil { - return nil, err - } - } - - buf := bufPool.Get().(*[]byte) - defer bufPool.Put(buf) - - if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { - bhdr := winio.BackupHeader{ - Id: winio.BackupData, - Size: hdr.Size, - } - err := bw.WriteHeader(&bhdr) - if err != nil { - return nil, err - } - _, err = io.CopyBuffer(bw, t, *buf) - if err != nil { - return nil, err - } - } - // Copy all the alternate data streams and return the next non-ADS header. - for { - ahdr, err := t.Next() - if err != nil { - return nil, err - } - if ahdr.Typeflag != tar.TypeReg || !strings.HasPrefix(ahdr.Name, hdr.Name+":") { - return ahdr, nil - } - bhdr := winio.BackupHeader{ - Id: winio.BackupAlternateData, - Size: ahdr.Size, - Name: ahdr.Name[len(hdr.Name):] + ":$DATA", - } - err = bw.WriteHeader(&bhdr) - if err != nil { - return nil, err - } - _, err = io.CopyBuffer(bw, t, *buf) - if err != nil { - return nil, err - } - } +func copyUpXAttrs(dst, src string) error { + return nil } diff -Nru containerd-1.2.6/archive/time_darwin.go containerd-1.5.9/archive/time_darwin.go --- containerd-1.2.6/archive/time_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/time_darwin.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package archive - -import ( - "time" - - "github.com/pkg/errors" -) - -// as at MacOS 10.12 there is apparently no way to set timestamps -// with nanosecond precision. We could fall back to utimes/lutimes -// and lose the precision as a temporary workaround. -func chtimes(path string, atime, mtime time.Time) error { - return errors.New("OSX missing UtimesNanoAt") -} diff -Nru containerd-1.2.6/archive/time_unix.go containerd-1.5.9/archive/time_unix.go --- containerd-1.2.6/archive/time_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/archive/time_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build freebsd linux openbsd solaris +// +build !windows /* Copyright The containerd Authors. @@ -32,7 +32,7 @@ utimes[1] = unix.NsecToTimespec(mtime.UnixNano()) if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil { - return errors.Wrap(err, "failed call to UtimesNanoAt") + return errors.Wrapf(err, "failed call to UtimesNanoAt for %s", path) } return nil diff -Nru containerd-1.2.6/benchmark_test.go containerd-1.5.9/benchmark_test.go --- containerd-1.2.6/benchmark_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/benchmark_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "fmt" - "testing" - - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" -) - -func BenchmarkContainerCreate(b *testing.B) { - client, err := newClient(b, address) - if err != nil { - b.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - b.Error(err) - return - } - spec, err := oci.GenerateSpec(ctx, client, &containers.Container{ID: b.Name()}, oci.WithImageConfig(image), withTrue()) - if err != nil { - b.Error(err) - return - } - var containers []Container - defer func() { - for _, c := range containers { - if err := c.Delete(ctx, WithSnapshotCleanup); err != nil { - b.Error(err) - } - } - }() - - // reset the timer before creating containers - b.ResetTimer() - for i := 0; i < b.N; i++ { - id := fmt.Sprintf("%s-%d", b.Name(), i) - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithSpec(spec)) - if err != nil { - b.Error(err) - return - } - containers = append(containers, container) - } - b.StopTimer() -} - -func BenchmarkContainerStart(b *testing.B) { - client, err := newClient(b, address) - if err != nil { - b.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - b.Error(err) - return - } - spec, err := oci.GenerateSpec(ctx, client, &containers.Container{ID: b.Name()}, oci.WithImageConfig(image), withTrue()) - if err != nil { - b.Error(err) - return - } - var containers []Container - defer func() { - for _, c := range containers { - if err := c.Delete(ctx, WithSnapshotCleanup); err != nil { - b.Error(err) - } - } - }() - - for i := 0; i < b.N; i++ { - id := fmt.Sprintf("%s-%d", b.Name(), i) - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithSpec(spec)) - if err != nil { - b.Error(err) - return - } - containers = append(containers, container) - - } - // reset the timer before starting tasks - b.ResetTimer() - for _, c := range containers { - task, err := c.NewTask(ctx, empty()) - if err != nil { - b.Error(err) - return - } - defer task.Delete(ctx) - if err := task.Start(ctx); err != nil { - b.Error(err) - return - } - } - b.StopTimer() -} diff -Nru containerd-1.2.6/BUILDING.md containerd-1.5.9/BUILDING.md --- containerd-1.2.6/BUILDING.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/BUILDING.md 2022-01-05 17:30:58.000000000 +0000 @@ -14,39 +14,35 @@ To build the `containerd` daemon, and the `ctr` simple test client, the following build system dependencies are required: -* Go 1.10.x or above +* Go 1.13.x or above except 1.14.x * Protoc 3.x compiler and headers (download at the [Google protobuf releases page](https://github.com/google/protobuf/releases)) * Btrfs headers and libraries for your distribution. Note that building the btrfs driver can be disabled via the build tag `no_btrfs`, removing this dependency. -* `libseccomp` is required if you're building with seccomp support ## Build the development environment First you need to setup your Go development environment. You can follow this guideline [How to write go code](https://golang.org/doc/code.html) and at the -end you need to have `GOPATH` and `GOROOT` set in your environment. +end you have `go` command in your `PATH`. -At this point you can use `go` to checkout `containerd` in your `GOPATH`: +You need `git` to checkout the source code: ```sh -go get github.com/containerd/containerd +git clone https://github.com/containerd/containerd ``` -For proper results, install the `protoc` release into `/usr/local` on your build system. For example, the following commands will download and install the 3.5.0 release for a 64-bit Linux host: +For proper results, install the `protoc` release into `/usr/local` on your build system. For example, the following commands will download and install the 3.11.4 release for a 64-bit Linux host: ``` -$ wget -c https://github.com/google/protobuf/releases/download/v3.5.0/protoc-3.5.0-linux-x86_64.zip -$ sudo unzip protoc-3.5.0-linux-x86_64.zip -d /usr/local +$ wget -c https://github.com/google/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip +$ sudo unzip protoc-3.11.4-linux-x86_64.zip -d /usr/local ``` `containerd` uses [Btrfs](https://en.wikipedia.org/wiki/Btrfs) it means that you -need to satisfy this dependencies in your system: +need to satisfy these dependencies in your system: * CentOS/Fedora: `yum install btrfs-progs-devel` -* Debian/Ubuntu: `apt-get install btrfs-tools` - -If you're building with seccomp, you'll need to install it with the following: - -* Debian/Ubuntu: `apt install libseccomp-dev` +* Debian/Ubuntu: `apt-get install btrfs-progs libbtrfs-dev` + * Debian(before Buster)/Ubuntu(before 19.10): `apt-get install btrfs-tools` At this point you are ready to build `containerd` yourself! @@ -58,28 +54,31 @@ container runtime development. You can skip this step if you already have the correct version of `runc` installed. +`runc` requires `libseccomp`. You may need to install the missing dependencies: + +* CentOS/Fedora: `yum install libseccomp libseccomp-devel` +* Debian/Ubuntu: `apt-get install libseccomp libseccomp-dev` + + For the quick and dirty installation, you can use the following: - go get github.com/opencontainers/runc +``` +git clone https://github.com/opencontainers/runc +cd runc +make +sudo make install +``` -This is not recommended, as the generated binary will not have version -information. Instead, cd into the source directory and use make to build and -install the binary: - - cd $GOPATH/src/github.com/opencontainers/runc - make - make install - -Make sure to follow the guidelines for versioning in [RUNC.md](RUNC.md) for the -best results. Some pointers on proper build tag setupVersion mismatches can -result in undefined behavior. +Make sure to follow the guidelines for versioning in [RUNC.md](/docs/RUNC.md) for the +best results. ## Build containerd `containerd` uses `make` to create a repeatable build flow. It means that you can run: -```sudo +``` +cd containerd make ``` @@ -102,13 +101,17 @@ > * `no_btrfs`: A build tag disables building the btrfs snapshot driver. > * `no_cri`: A build tag disables building Kubernetes [CRI](http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html) support into containerd. > See [here](https://github.com/containerd/cri-containerd#build-tags) for build tags of CRI plugin. +> * `no_devmapper`: A build tag disables building the device mapper snapshot driver. > > For example, adding `BUILDTAGS=no_btrfs` to your environment before calling the **binaries** > Makefile target will disable the btrfs driver within the containerd Go build. -Vendoring of external imports uses the [`vndr` tool](https://github.com/LK4D4/vndr) which uses a simple config file, `vendor.conf`, to provide the URL and version or hash details for each vendored import. After modifying `vendor.conf` run the `vndr` tool to update the `vendor/` directory contents. Combining the `vendor.conf` update with the changeset in `vendor/` after running `vndr` should become a single commit for a PR which relies on vendored updates. +Vendoring of external imports uses the [Go Modules](https://golang.org/ref/mod#vendoring). You need +to use `go mod` command to modify the dependencies. After modifition, you should run `go mod tidy` +and `go mod vendor` to ensure the `go.mod`, `go.sum` files and `vendor` directory are up to date. +Changes to these files should become a single commit for a PR which relies on vendored updates. -Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc` that is used by containerd. +Please refer to [RUNC.md](/docs/RUNC.md) for the currently supported version of `runc` that is used by containerd. ### Static binaries @@ -116,16 +119,18 @@ ```sudo make EXTRA_FLAGS="-buildmode pie" \ - EXTRA_LDFLAGS='-extldflags "-fno-PIC -static"' \ + EXTRA_LDFLAGS='-linkmode external -extldflags "-fno-PIC -static"' \ BUILDTAGS="netgo osusergo static_build" ``` > *Note*: > - static build is discouraged -> - static containerd binary does not support loading plugins +> - static containerd binary does not support loading shared object plugins (`*.so`) # Via Docker container +The following instructions assume you are at the parent directory of containerd source directory. + ## Build containerd You can build `containerd` via a Linux-based Docker container. @@ -135,7 +140,7 @@ FROM golang RUN apt-get update && \ - apt-get install -y btrfs-tools libseccomp-dev + apt-get install -y libbtrfs-dev ``` Let's suppose that you built an image called `containerd/build`. From the @@ -143,7 +148,7 @@ ```sh docker run -it \ - -v ${PWD}:/go/src/github.com/containerd/containerd \ + -v ${PWD}/containerd:/go/src/github.com/containerd/containerd \ -e GOPATH=/go \ -w /go/src/github.com/containerd/containerd containerd/build sh ``` @@ -157,12 +162,12 @@ ``` ## Build containerd and runc -To have complete core container runtime, you will both `containerd` and `runc`. It is possible to build both of these via Docker container. +To have complete core container runtime, you will need both `containerd` and `runc`. It is possible to build both of these via Docker container. -You can use `go` to checkout `runc` in your `GOPATH`: +You can use `git` to checkout `runc`: ```sh -go get github.com/opencontainers/runc +git clone https://github.com/opencontainers/runc ``` We can build an image from this `Dockerfile`: @@ -171,19 +176,25 @@ FROM golang RUN apt-get update && \ - apt-get install -y btrfs-tools libseccomp-dev + apt-get install -y libbtrfs-dev libseccomp-dev ``` -In our Docker container we will use a specific `runc` build which includes [seccomp](https://en.wikipedia.org/wiki/seccomp) and [apparmor](https://en.wikipedia.org/wiki/AppArmor) support. Hence why our Dockerfile includes `libseccomp-dev` as a dependency (apparmor support doesn't require external libraries). Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc` that is used by containerd. +In our Docker container we will build `runc` build, which includes +[seccomp](https://en.wikipedia.org/wiki/seccomp), [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), +and [AppArmor](https://en.wikipedia.org/wiki/AppArmor) support. Seccomp support +in runc requires `libseccomp-dev` as a dependency (AppArmor and SELinux support +do not require external libraries at build time). Refer to [RUNC.md](docs/RUNC.md) +in the docs directory to for details about building runc, and to learn about +supported versions of `runc` as used by containerd. Let's suppose you build an image called `containerd/build` from the above Dockerfile. You can run the following command: ```sh docker run -it --privileged \ -v /var/lib/containerd \ - -v ${GOPATH}/src/github.com/opencontainers/runc:/go/src/github.com/opencontainers/runc \ - -v ${GOPATH}/src/github.com/containerd/containerd:/go/src/github.com/containerd/containerd \ + -v ${PWD}/runc:/go/src/github.com/opencontainers/runc \ + -v ${PWD}/containerd:/go/src/github.com/containerd/containerd \ -e GOPATH=/go \ -w /go/src/github.com/containerd/containerd containerd/build sh ``` @@ -204,9 +215,12 @@ ```sh cd /go/src/github.com/opencontainers/runc -make BUILDTAGS='seccomp apparmor' && make install +make && make install ``` +For further details about building runc, refer to [RUNC.md](docs/RUNC.md) in the +docs directory. + When working with `ctr`, the simple test client we just built, don't forget to start the daemon! ```sh @@ -218,8 +232,7 @@ During the automated CI the unit tests and integration tests are run as part of the PR validation. As a developer you can run these tests locally by using any of the following `Makefile` targets: - `make test`: run all non-integration tests that do not require `root` privileges - `make root-test`: run all non-integration tests which require `root` - - `make integration`: run all tests, including integration tests and those which require `root` - - `make integration-parallel`: run all tests (integration and root-required included) in parallel mode + - `make integration`: run all tests, including integration tests and those which require `root`. `TESTFLAGS_PARALLEL` can be used to control parallelism. For example, `TESTFLAGS_PARALLEL=1 make integration` will lead a non-parallel execution. The default value of `TESTFLAGS_PARALLEL` is **8**. To execute a specific test or set of tests you can use the `go test` capabilities without using the `Makefile` targets. The following examples show how to specify a test diff -Nru containerd-1.2.6/cio/io.go containerd-1.5.9/cio/io.go --- containerd-1.2.6/cio/io.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cio/io.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,10 +18,13 @@ import ( "context" + "errors" "fmt" "io" + "net/url" "os" "path/filepath" + "strings" "sync" "github.com/containerd/containerd/defaults" @@ -77,7 +80,7 @@ // Close the FIFOSet func (f *FIFOSet) Close() error { - if f.close != nil { + if f != nil && f.close != nil { return f.close() } return nil @@ -222,46 +225,121 @@ cio } -var _ IO = &DirectIO{} +var ( + _ IO = &DirectIO{} + _ IO = &logURI{} +) + +// LogURI provides the raw logging URI +func LogURI(uri *url.URL) Creator { + return func(_ string) (IO, error) { + return &logURI{ + config: Config{ + Stdout: uri.String(), + Stderr: uri.String(), + }, + }, nil + } +} + +// BinaryIO forwards container STDOUT|STDERR directly to a logging binary +func BinaryIO(binary string, args map[string]string) Creator { + return func(_ string) (IO, error) { + uri, err := LogURIGenerator("binary", binary, args) + if err != nil { + return nil, err + } + + res := uri.String() + return &logURI{ + config: Config{ + Stdout: res, + Stderr: res, + }, + }, nil + } +} + +// TerminalBinaryIO forwards container STDOUT|STDERR directly to a logging binary +// It also sets the terminal option to true +func TerminalBinaryIO(binary string, args map[string]string) Creator { + return func(_ string) (IO, error) { + uri, err := LogURIGenerator("binary", binary, args) + if err != nil { + return nil, err + } + + res := uri.String() + return &logURI{ + config: Config{ + Stdout: res, + Stderr: res, + Terminal: true, + }, + }, nil + } +} // LogFile creates a file on disk that logs the task's STDOUT,STDERR. // If the log file already exists, the logs will be appended to the file. func LogFile(path string) Creator { return func(_ string) (IO, error) { - if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { - return nil, err - } - f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + uri, err := LogURIGenerator("file", path, nil) if err != nil { return nil, err } - f.Close() - return &logIO{ + + res := uri.String() + return &logURI{ config: Config{ - Stdout: path, - Stderr: path, + Stdout: res, + Stderr: res, }, }, nil } } -type logIO struct { +// LogURIGenerator is the helper to generate log uri with specific scheme. +func LogURIGenerator(scheme string, path string, args map[string]string) (*url.URL, error) { + path = filepath.Clean(path) + if !strings.HasPrefix(path, "/") { + return nil, errors.New("absolute path needed") + } + + uri := &url.URL{ + Scheme: scheme, + Path: path, + } + + if len(args) == 0 { + return uri, nil + } + + q := uri.Query() + for k, v := range args { + q.Set(k, v) + } + uri.RawQuery = q.Encode() + return uri, nil +} + +type logURI struct { config Config } -func (l *logIO) Config() Config { +func (l *logURI) Config() Config { return l.config } -func (l *logIO) Cancel() { +func (l *logURI) Cancel() { } -func (l *logIO) Wait() { +func (l *logURI) Wait() { } -func (l *logIO) Close() error { +func (l *logURI) Close() error { return nil } diff -Nru containerd-1.2.6/cio/io_test.go containerd-1.5.9/cio/io_test.go --- containerd-1.2.6/cio/io_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cio/io_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,6 +23,7 @@ "context" "io" "io/ioutil" + "net/url" "os" "path/filepath" "runtime" @@ -32,8 +33,8 @@ "github.com/containerd/fifo" "github.com/google/go-cmp/cmp/cmpopts" - "gotest.tools/assert" - is "gotest.tools/assert/cmp" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) func assertHasPrefix(t *testing.T, s, prefix string) { @@ -153,3 +154,88 @@ assert.NilError(t, err) assert.NilError(t, producers.Stderr.Close()) } + +func TestBinaryIOArgs(t *testing.T) { + res, err := BinaryIO("/file.bin", map[string]string{"id": "1"})("") + assert.NilError(t, err) + assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stdout) + assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stderr) +} + +func TestBinaryIOAbsolutePath(t *testing.T) { + res, err := BinaryIO("/full/path/bin", nil)("!") + assert.NilError(t, err) + + // Test parse back + parsed, err := url.Parse(res.Config().Stdout) + assert.NilError(t, err) + assert.Equal(t, "binary", parsed.Scheme) + assert.Equal(t, "/full/path/bin", parsed.Path) +} + +func TestBinaryIOFailOnRelativePath(t *testing.T) { + _, err := BinaryIO("./bin", nil)("!") + assert.Error(t, err, "absolute path needed") +} + +func TestLogFileAbsolutePath(t *testing.T) { + res, err := LogFile("/full/path/file.txt")("!") + assert.NilError(t, err) + assert.Equal(t, "file:///full/path/file.txt", res.Config().Stdout) + assert.Equal(t, "file:///full/path/file.txt", res.Config().Stderr) + + // Test parse back + parsed, err := url.Parse(res.Config().Stdout) + assert.NilError(t, err) + assert.Equal(t, "file", parsed.Scheme) + assert.Equal(t, "/full/path/file.txt", parsed.Path) +} + +func TestLogFileFailOnRelativePath(t *testing.T) { + _, err := LogFile("./file.txt")("!") + assert.Error(t, err, "absolute path needed") +} + +func TestLogURIGenerator(t *testing.T) { + for _, tc := range []struct { + scheme string + path string + args map[string]string + expected string + err string + }{ + { + scheme: "fifo", + path: "/full/path/pipe.fifo", + expected: "fifo:///full/path/pipe.fifo", + }, + { + scheme: "file", + path: "/full/path/file.txt", + args: map[string]string{ + "maxSize": "100MB", + }, + expected: "file:///full/path/file.txt?maxSize=100MB", + }, + { + scheme: "binary", + path: "/full/path/bin", + args: map[string]string{ + "id": "testing", + }, + expected: "binary:///full/path/bin?id=testing", + }, + { + scheme: "unknown", + path: "nowhere", + err: "absolute path needed", + }, + } { + uri, err := LogURIGenerator(tc.scheme, tc.path, tc.args) + if err != nil { + assert.Error(t, err, tc.err) + continue + } + assert.Equal(t, tc.expected, uri.String()) + } +} diff -Nru containerd-1.2.6/cio/io_unix.go containerd-1.5.9/cio/io_unix.go --- containerd-1.2.6/cio/io_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cio/io_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -72,17 +72,19 @@ } var wg = &sync.WaitGroup{} - wg.Add(1) - go func() { - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - - io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p) - pipes.Stdout.Close() - wg.Done() - }() + if fifos.Stdout != "" { + wg.Add(1) + go func() { + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + + io.CopyBuffer(ioset.Stdout, pipes.Stdout, *p) + pipes.Stdout.Close() + wg.Done() + }() + } - if !fifos.Terminal { + if !fifos.Terminal && fifos.Stderr != "" { wg.Add(1) go func() { p := bufPool.Get().(*[]byte) @@ -101,38 +103,36 @@ }, nil } -func openFifos(ctx context.Context, fifos *FIFOSet) (pipes, error) { - var err error +func openFifos(ctx context.Context, fifos *FIFOSet) (f pipes, retErr error) { defer func() { - if err != nil { + if retErr != nil { fifos.Close() } }() - var f pipes if fifos.Stdin != "" { - if f.Stdin, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return f, errors.Wrapf(err, "failed to open stdin fifo") + if f.Stdin, retErr = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil { + return f, errors.Wrapf(retErr, "failed to open stdin fifo") } defer func() { - if err != nil && f.Stdin != nil { + if retErr != nil && f.Stdin != nil { f.Stdin.Close() } }() } if fifos.Stdout != "" { - if f.Stdout, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return f, errors.Wrapf(err, "failed to open stdout fifo") + if f.Stdout, retErr = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil { + return f, errors.Wrapf(retErr, "failed to open stdout fifo") } defer func() { - if err != nil && f.Stdout != nil { + if retErr != nil && f.Stdout != nil { f.Stdout.Close() } }() } - if fifos.Stderr != "" { - if f.Stderr, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return f, errors.Wrapf(err, "failed to open stderr fifo") + if !fifos.Terminal && fifos.Stderr != "" { + if f.Stderr, retErr = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil { + return f, errors.Wrapf(retErr, "failed to open stderr fifo") } } return f, nil diff -Nru containerd-1.2.6/cio/io_unix_test.go containerd-1.5.9/cio/io_unix_test.go --- containerd-1.2.6/cio/io_unix_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cio/io_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,10 +20,13 @@ import ( "context" + "fmt" + "io/ioutil" + "os" "path/filepath" "testing" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) func TestOpenFifos(t *testing.T) { @@ -55,3 +58,46 @@ assert.Assert(t, err != nil, scenario) } } + +// TestOpenFifosWithTerminal tests openFifos should not open stderr if terminal +// is set. +func TestOpenFifosWithTerminal(t *testing.T) { + var ctx, cancel = context.WithCancel(context.Background()) + defer cancel() + + ioFifoDir, err := ioutil.TempDir("", fmt.Sprintf("cio-%s", t.Name())) + if err != nil { + t.Fatalf("unexpected error during creating temp dir: %v", err) + } + defer os.RemoveAll(ioFifoDir) + + cfg := Config{ + Stdout: filepath.Join(ioFifoDir, "test-stdout"), + Stderr: filepath.Join(ioFifoDir, "test-stderr"), + } + + // Without terminal, pipes.Stderr should not be nil + { + p, err := openFifos(ctx, NewFIFOSet(cfg, nil)) + if err != nil { + t.Fatalf("unexpected error during openFifos: %v", err) + } + + if p.Stderr == nil { + t.Fatalf("unexpected empty stderr pipe") + } + } + + // With terminal, pipes.Stderr should be nil + { + cfg.Terminal = true + p, err := openFifos(ctx, NewFIFOSet(cfg, nil)) + if err != nil { + t.Fatalf("unexpected error during openFifos: %v", err) + } + + if p.Stderr != nil { + t.Fatalf("unexpected stderr pipe") + } + } +} diff -Nru containerd-1.2.6/cio/io_windows.go containerd-1.5.9/cio/io_windows.go --- containerd-1.2.6/cio/io_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cio/io_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,6 @@ "context" "fmt" "io" - "net" winio "github.com/Microsoft/go-winio" "github.com/containerd/containerd/log" @@ -31,30 +30,33 @@ // NewFIFOSetInDir returns a new set of fifos for the task func NewFIFOSetInDir(_, id string, terminal bool) (*FIFOSet, error) { + stderrPipe := "" + if !terminal { + stderrPipe = fmt.Sprintf(`%s\ctr-%s-stderr`, pipeRoot, id) + } return NewFIFOSet(Config{ Terminal: terminal, Stdin: fmt.Sprintf(`%s\ctr-%s-stdin`, pipeRoot, id), Stdout: fmt.Sprintf(`%s\ctr-%s-stdout`, pipeRoot, id), - Stderr: fmt.Sprintf(`%s\ctr-%s-stderr`, pipeRoot, id), + Stderr: stderrPipe, }, nil), nil } -func copyIO(fifos *FIFOSet, ioset *Streams) (*cio, error) { - var ( - set []io.Closer - ) +func copyIO(fifos *FIFOSet, ioset *Streams) (_ *cio, retErr error) { + cios := &cio{config: fifos.Config} + + defer func() { + if retErr != nil { + _ = cios.Close() + } + }() if fifos.Stdin != "" { l, err := winio.ListenPipe(fifos.Stdin, nil) if err != nil { return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin) } - defer func(l net.Listener) { - if err != nil { - l.Close() - } - }(l) - set = append(set, l) + cios.closers = append(cios.closers, l) go func() { c, err := l.Accept() @@ -77,12 +79,7 @@ if err != nil { return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout) } - defer func(l net.Listener) { - if err != nil { - l.Close() - } - }(l) - set = append(set, l) + cios.closers = append(cios.closers, l) go func() { c, err := l.Accept() @@ -105,12 +102,7 @@ if err != nil { return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr) } - defer func(l net.Listener) { - if err != nil { - l.Close() - } - }(l) - set = append(set, l) + cios.closers = append(cios.closers, l) go func() { c, err := l.Accept() @@ -128,7 +120,7 @@ }() } - return &cio{config: fifos.Config, closers: set}, nil + return cios, nil } // NewDirectIO returns an IO implementation that exposes the IO streams as io.ReadCloser diff -Nru containerd-1.2.6/cio/io_windows_test.go containerd-1.5.9/cio/io_windows_test.go --- containerd-1.2.6/cio/io_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cio/io_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,49 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cio + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestNewFifoSetInDir_NoTerminal(t *testing.T) { + set, err := NewFIFOSetInDir("", t.Name(), false) + if err != nil { + t.Fatalf("NewFifoSetInDir failed with: %v", err) + } + + assert.Assert(t, !set.Terminal, "FIFOSet.Terminal should be false") + assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set") + assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set") + assert.Assert(t, set.Stderr != "", "FIFOSet.Stderr should be set") +} + +func TestNewFifoSetInDir_Terminal(t *testing.T) { + set, err := NewFIFOSetInDir("", t.Name(), true) + if err != nil { + t.Fatalf("NewFifoSetInDir failed with: %v", err) + } + + assert.Assert(t, set.Terminal, "FIFOSet.Terminal should be false") + assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set") + assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set") + assert.Assert(t, set.Stderr == "", "FIFOSet.Stderr should not be set") +} diff -Nru containerd-1.2.6/client.go containerd-1.5.9/client.go --- containerd-1.2.6/client.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,11 +17,14 @@ package containerd import ( + "bytes" "context" + "encoding/json" "fmt" "net/http" "runtime" "strconv" + "strings" "sync" "time" @@ -36,6 +39,7 @@ snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" "github.com/containerd/containerd/api/services/tasks/v1" versionservice "github.com/containerd/containerd/api/services/version/v1" + apitypes "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/containers" "github.com/containerd/containerd/content" contentproxy "github.com/containerd/containerd/content/proxy" @@ -51,7 +55,7 @@ "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" - "github.com/containerd/containerd/remotes/docker/schema1" + "github.com/containerd/containerd/services/introspection" "github.com/containerd/containerd/snapshots" snproxy "github.com/containerd/containerd/snapshots/proxy" "github.com/containerd/typeurl" @@ -59,7 +63,9 @@ ocispec "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "golang.org/x/sync/semaphore" "google.golang.org/grpc" + "google.golang.org/grpc/backoff" "google.golang.org/grpc/health/grpc_health_v1" ) @@ -85,23 +91,38 @@ if copts.timeout == 0 { copts.timeout = 10 * time.Second } - rt := fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS) + + c := &Client{ + defaultns: copts.defaultns, + } + if copts.defaultRuntime != "" { - rt = copts.defaultRuntime + c.runtime = copts.defaultRuntime + } else { + c.runtime = defaults.DefaultRuntime } - c := &Client{ - runtime: rt, + + if copts.defaultPlatform != nil { + c.platform = copts.defaultPlatform + } else { + c.platform = platforms.Default() } + if copts.services != nil { c.services = *copts.services } if address != "" { + backoffConfig := backoff.DefaultConfig + backoffConfig.MaxDelay = 3 * time.Second + connParams := grpc.ConnectParams{ + Backoff: backoffConfig, + } gopts := []grpc.DialOption{ grpc.WithBlock(), grpc.WithInsecure(), grpc.FailOnNonTempDialError(true), - grpc.WithBackoffMaxDelay(3 * time.Second), - grpc.WithDialer(dialer.Dialer), + grpc.WithConnectParams(connParams), + grpc.WithContextDialer(dialer.ContextDialer), // TODO(stevvooe): We may need to allow configuration of this on the client. grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), @@ -133,8 +154,18 @@ c.conn, c.connector = conn, connector } if copts.services == nil && c.conn == nil { - return nil, errors.New("no grpc connection or services is available") + return nil, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection or services is available") } + + // check namespace labels for default runtime + if copts.defaultRuntime == "" && c.defaultns != "" { + if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { + return nil, err + } else if label != "" { + c.runtime = label + } + } + return c, nil } @@ -148,9 +179,20 @@ } } c := &Client{ - conn: conn, - runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS), + defaultns: copts.defaultns, + conn: conn, + runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS), + } + + // check namespace labels for default runtime + if copts.defaultRuntime == "" && c.defaultns != "" { + if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { + return nil, err + } else if label != "" { + c.runtime = label + } } + if copts.services != nil { c.services = *copts.services } @@ -164,13 +206,15 @@ connMu sync.Mutex conn *grpc.ClientConn runtime string + defaultns string + platform platforms.MatchComparer connector func() (*grpc.ClientConn, error) } // Reconnect re-establishes the GRPC connection to the containerd daemon func (c *Client) Reconnect() error { if c.connector == nil { - return errors.New("unable to reconnect to containerd, no connector available") + return errors.Wrap(errdefs.ErrUnavailable, "unable to reconnect to containerd, no connector available") } c.connMu.Lock() defer c.connMu.Unlock() @@ -183,6 +227,11 @@ return nil } +// Runtime returns the name of the runtime being used +func (c *Client) Runtime() string { + return c.runtime +} + // IsServing returns true if the client can successfully connect to the // containerd daemon and the healthcheck service returns the SERVING // response. @@ -193,10 +242,10 @@ c.connMu.Lock() if c.conn == nil { c.connMu.Unlock() - return false, errors.New("no grpc connection available") + return false, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") } c.connMu.Unlock() - r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.FailFast(false)) + r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true)) if err != nil { return false, err } @@ -265,13 +314,20 @@ PlatformMatcher platforms.MatchComparer // Unpack is done after an image is pulled to extract into a snapshotter. + // It is done simultaneously for schema 2 images when they are pulled. // If an image is not unpacked on pull, it can be unpacked any time // afterwards. Unpacking is required to run an image. Unpack bool + // UnpackOpts handles options to the unpack call. + UnpackOpts []UnpackOpt + // Snapshotter used for unpacking Snapshotter string + // SnapshotterOpts are additional options to be passed to a snapshotter during pull + SnapshotterOpts []snapshots.Opt + // Labels to be applied to the created image Labels map[string]string @@ -280,6 +336,12 @@ // handlers. BaseHandlers []images.Handler + // HandlerWrapper wraps the handler which gets sent to dispatch. + // Unlike BaseHandlers, this can run before and after the built + // in handlers, allowing operations to run on the descriptor + // after it has completed transferring. + HandlerWrapper func(images.Handler) images.Handler + // ConvertSchema1 is whether to convert Docker registry schema 1 // manifests. If this option is false then any image which resolves // to schema 1 will return an error since schema 1 is not supported. @@ -290,6 +352,19 @@ // platforms will be used to create a PlatformMatcher with no ordering // preference. Platforms []string + + // MaxConcurrentDownloads is the max concurrent content downloads for each pull. + MaxConcurrentDownloads int + + // MaxConcurrentUploadedLayers is the max concurrent uploaded layers for each push. + MaxConcurrentUploadedLayers int + + // AllMetadata downloads all manifests and known-configuration files + AllMetadata bool + + // ChildLabelMap sets the labels used to reference child objects in the content + // store. By default, all GC reference labels will be set for all fetched content. + ChildLabelMap func(ocispec.Descriptor) []string } func defaultRemoteContext() *RemoteContext { @@ -297,7 +372,6 @@ Resolver: docker.NewResolver(docker.ResolverOptions{ Client: http.DefaultClient, }), - Snapshotter: DefaultSnapshotter, } } @@ -312,7 +386,7 @@ } if fetchCtx.Unpack { - return images.Image{}, errors.New("unpack on fetch not supported, try pull") + return images.Image{}, errors.Wrap(errdefs.ErrNotImplemented, "unpack on fetch not supported, try pull") } if fetchCtx.PlatformMatcher == nil { @@ -338,158 +412,11 @@ } defer done(ctx) - return c.fetch(ctx, fetchCtx, ref, 0) -} - -// Pull downloads the provided content into containerd's content store -// and returns a platform specific image object -func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) { - pullCtx := defaultRemoteContext() - for _, o := range opts { - if err := o(c, pullCtx); err != nil { - return nil, err - } - } - - if pullCtx.PlatformMatcher == nil { - if len(pullCtx.Platforms) > 1 { - return nil, errors.New("cannot pull multiplatform image locally, try Fetch") - } else if len(pullCtx.Platforms) == 0 { - pullCtx.PlatformMatcher = platforms.Default() - } else { - p, err := platforms.Parse(pullCtx.Platforms[0]) - if err != nil { - return nil, errors.Wrapf(err, "invalid platform %s", pullCtx.Platforms[0]) - } - - pullCtx.PlatformMatcher = platforms.Only(p) - } - } - - ctx, done, err := c.WithLease(ctx) - if err != nil { - return nil, err - } - defer done(ctx) - - img, err := c.fetch(ctx, pullCtx, ref, 1) + img, err := c.fetch(ctx, fetchCtx, ref, 0) if err != nil { - return nil, err - } - - i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher) - - if pullCtx.Unpack { - if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil { - return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) - } - } - - return i, nil -} - -func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) { - store := c.ContentStore() - name, desc, err := rCtx.Resolver.Resolve(ctx, ref) - if err != nil { - return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref) - } - - fetcher, err := rCtx.Resolver.Fetcher(ctx, name) - if err != nil { - return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name) - } - - var ( - handler images.Handler - - isConvertible bool - converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error) - ) - - if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 { - schema1Converter := schema1.NewConverter(store, fetcher) - - handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...) - - isConvertible = true - - converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) { - return schema1Converter.Convert(ctx) - } - } else { - // Get all the children for a descriptor - childrenHandler := images.ChildrenHandler(store) - // Set any children labels for that content - childrenHandler = images.SetChildrenLabels(store, childrenHandler) - // Filter children by platforms - childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher) - // Sort and limit manifests if a finite number is needed - if limit > 0 { - childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) - } - - // set isConvertible to true if there is application/octet-stream media type - convertibleHandler := images.HandlerFunc( - func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { - if desc.MediaType == docker.LegacyConfigMediaType { - isConvertible = true - } - - return []ocispec.Descriptor{}, nil - }, - ) - - handler = images.Handlers(append(rCtx.BaseHandlers, - remotes.FetchHandler(store, fetcher), - convertibleHandler, - childrenHandler, - )...) - - converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) { - return docker.ConvertManifest(ctx, store, desc) - } - } - - if err := images.Dispatch(ctx, handler, desc); err != nil { return images.Image{}, err } - - if isConvertible { - if desc, err = converterFunc(ctx, desc); err != nil { - return images.Image{}, err - } - } - - img := images.Image{ - Name: name, - Target: desc, - Labels: rCtx.Labels, - } - - is := c.ImageService() - for { - if created, err := is.Create(ctx, img); err != nil { - if !errdefs.IsAlreadyExists(err) { - return images.Image{}, err - } - - updated, err := is.Update(ctx, img) - if err != nil { - // if image was removed, try create again - if errdefs.IsNotFound(err) { - continue - } - return images.Image{}, err - } - - img = updated - } else { - img = created - } - - return img, nil - } + return c.createNewImage(ctx, img) } // Push uploads the provided content to a remote resource @@ -516,12 +443,36 @@ } } + // Annotate ref with digest to push only push tag for single digest + if !strings.Contains(ref, "@") { + ref = ref + "@" + desc.Digest.String() + } + pusher, err := pushCtx.Resolver.Pusher(ctx, ref) if err != nil { return err } - return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.PlatformMatcher, pushCtx.BaseHandlers...) + var wrapper func(images.Handler) images.Handler + + if len(pushCtx.BaseHandlers) > 0 { + wrapper = func(h images.Handler) images.Handler { + h = images.Handlers(append(pushCtx.BaseHandlers, h)...) + if pushCtx.HandlerWrapper != nil { + h = pushCtx.HandlerWrapper(h) + } + return h + } + } else if pushCtx.HandlerWrapper != nil { + wrapper = pushCtx.HandlerWrapper + } + + var limiter *semaphore.Weighted + if pushCtx.MaxConcurrentUploadedLayers > 0 { + limiter = semaphore.NewWeighted(int64(pushCtx.MaxConcurrentUploadedLayers)) + } + + return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), limiter, pushCtx.PlatformMatcher, wrapper) } // GetImage returns an existing image @@ -546,6 +497,66 @@ return images, nil } +// Restore restores a container from a checkpoint +func (c *Client) Restore(ctx context.Context, id string, checkpoint Image, opts ...RestoreOpts) (Container, error) { + store := c.ContentStore() + index, err := decodeIndex(ctx, store, checkpoint.Target()) + if err != nil { + return nil, err + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + copts := []NewContainerOpts{} + for _, o := range opts { + copts = append(copts, o(ctx, id, c, checkpoint, index)) + } + + ctr, err := c.NewContainer(ctx, id, copts...) + if err != nil { + return nil, err + } + + return ctr, nil +} + +func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) { + labels := map[string]string{} + for i, m := range index.Manifests { + labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String() + } + data, err := json.Marshal(index) + if err != nil { + return ocispec.Descriptor{}, err + } + return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) +} + +// GetLabel gets a label value from namespace store +// If there is no default label, an empty string returned with nil error +func (c *Client) GetLabel(ctx context.Context, label string) (string, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + if c.defaultns == "" { + return "", err + } + ns = c.defaultns + } + + srv := c.NamespaceService() + labels, err := srv.Labels(ctx, ns) + if err != nil { + return "", err + } + + value := labels[label] + return value, nil +} + // Subscribe to events that match one or more of the provided filters. // // Callers should listen on both the envelope and errs channels. If the errs @@ -599,6 +610,10 @@ // SnapshotService returns the underlying snapshotter for the provided snapshotter name func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter { + snapshotterName, err := c.resolveSnapshotterName(context.Background(), snapshotterName) + if err != nil { + snapshotterName = DefaultSnapshotter + } if c.snapshotters != nil { return c.snapshotters[snapshotterName] } @@ -638,10 +653,13 @@ } // IntrospectionService returns the underlying Introspection Client -func (c *Client) IntrospectionService() introspectionapi.IntrospectionClient { +func (c *Client) IntrospectionService() introspection.Service { + if c.introspectionService != nil { + return c.introspectionService + } c.connMu.Lock() defer c.connMu.Unlock() - return introspectionapi.NewIntrospectionClient(c.conn) + return introspection.NewIntrospectionServiceFromClient(introspectionapi.NewIntrospectionClient(c.conn)) } // LeasesService returns the underlying Leases Client @@ -678,6 +696,13 @@ return versionservice.NewVersionClient(c.conn) } +// Conn returns the underlying GRPC connection object +func (c *Client) Conn() *grpc.ClientConn { + c.connMu.Lock() + defer c.connMu.Unlock() + return c.conn +} + // Version of containerd type Version struct { // Version number @@ -691,7 +716,7 @@ c.connMu.Lock() if c.conn == nil { c.connMu.Unlock() - return Version{}, errors.New("no grpc connection available") + return Version{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") } c.connMu.Unlock() response, err := c.VersionService().Version(ctx, &ptypes.Empty{}) @@ -703,3 +728,106 @@ Revision: response.Revision, }, nil } + +// ServerInfo represents the introspected server information +type ServerInfo struct { + UUID string +} + +// Server returns server information from the introspection service +func (c *Client) Server(ctx context.Context) (ServerInfo, error) { + c.connMu.Lock() + if c.conn == nil { + c.connMu.Unlock() + return ServerInfo{}, errors.Wrap(errdefs.ErrUnavailable, "no grpc connection available") + } + c.connMu.Unlock() + + response, err := c.IntrospectionService().Server(ctx, &ptypes.Empty{}) + if err != nil { + return ServerInfo{}, err + } + return ServerInfo{ + UUID: response.UUID, + }, nil +} + +func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) { + if name == "" { + label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel) + if err != nil { + return "", err + } + + if label != "" { + name = label + } else { + name = DefaultSnapshotter + } + } + + return name, nil +} + +func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { + name, err := c.resolveSnapshotterName(ctx, name) + if err != nil { + return nil, err + } + + s := c.SnapshotService(name) + if s == nil { + return nil, errors.Wrapf(errdefs.ErrNotFound, "snapshotter %s was not found", name) + } + + return s, nil +} + +// CheckRuntime returns true if the current runtime matches the expected +// runtime. Providing various parts of the runtime schema will match those +// parts of the expected runtime +func CheckRuntime(current, expected string) bool { + cp := strings.Split(current, ".") + l := len(cp) + for i, p := range strings.Split(expected, ".") { + if i > l { + return false + } + if p != cp[i] { + return false + } + } + return true +} + +// GetSnapshotterSupportedPlatforms returns a platform matchers which represents the +// supported platforms for the given snapshotters +func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshotterName string) (platforms.MatchComparer, error) { + filters := []string{fmt.Sprintf("type==%s, id==%s", plugin.SnapshotPlugin, snapshotterName)} + in := c.IntrospectionService() + + resp, err := in.Plugins(ctx, filters) + if err != nil { + return nil, err + } + + if len(resp.Plugins) <= 0 { + return nil, fmt.Errorf("inspection service could not find snapshotter %s plugin", snapshotterName) + } + + sn := resp.Plugins[0] + snPlatforms := toPlatforms(sn.Platforms) + return platforms.Any(snPlatforms...), nil +} + +func toPlatforms(pt []apitypes.Platform) []ocispec.Platform { + platforms := make([]ocispec.Platform, len(pt)) + for i, p := range pt { + platforms[i] = ocispec.Platform{ + Architecture: p.Architecture, + OS: p.OS, + Variant: p.Variant, + } + } + return platforms +} diff -Nru containerd-1.2.6/client_opts.go containerd-1.5.9/client_opts.go --- containerd-1.2.6/client_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/client_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,15 +22,19 @@ "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/snapshots" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "google.golang.org/grpc" ) type clientOpts struct { - defaultns string - defaultRuntime string - services *services - dialOptions []grpc.DialOption - timeout time.Duration + defaultns string + defaultRuntime string + defaultPlatform platforms.MatchComparer + services *services + dialOptions []grpc.DialOption + timeout time.Duration } // ClientOpt allows callers to set options on the containerd client @@ -55,6 +59,14 @@ } } +// WithDefaultPlatform sets the default platform matcher on the client +func WithDefaultPlatform(platform platforms.MatchComparer) ClientOpt { + return func(c *clientOpts) error { + c.defaultPlatform = platform + return nil + } +} + // WithDialOpts allows grpc.DialOptions to be set on the connection func WithDialOpts(opts []grpc.DialOption) ClientOpt { return func(c *clientOpts) error { @@ -121,10 +133,19 @@ return nil } -// WithPullSnapshotter specifies snapshotter name used for unpacking -func WithPullSnapshotter(snapshotterName string) RemoteOpt { +// WithUnpackOpts is used to add unpack options to the unpacker. +func WithUnpackOpts(opts []UnpackOpt) RemoteOpt { + return func(_ *Client, c *RemoteContext) error { + c.UnpackOpts = append(c.UnpackOpts, opts...) + return nil + } +} + +// WithPullSnapshotter specifies snapshotter name used for unpacking. +func WithPullSnapshotter(snapshotterName string, opts ...snapshots.Opt) RemoteOpt { return func(_ *Client, c *RemoteContext) error { c.Snapshotter = snapshotterName + c.SnapshotterOpts = opts return nil } } @@ -155,6 +176,18 @@ } } +// WithChildLabelMap sets the map function used to define the labels set +// on referenced child content in the content store. This can be used +// to overwrite the default GC labels or filter which labels get set +// for content. +// The default is `images.ChildGCLabels`. +func WithChildLabelMap(fn func(ocispec.Descriptor) []string) RemoteOpt { + return func(_ *Client, c *RemoteContext) error { + c.ChildLabelMap = fn + return nil + } +} + // WithSchema1Conversion is used to convert Docker registry schema 1 // manifests to oci manifests on pull. Without this option schema 1 // manifests will return a not supported error. @@ -178,3 +211,35 @@ return nil } } + +// WithImageHandlerWrapper wraps the handlers to be called on dispatch. +func WithImageHandlerWrapper(w func(images.Handler) images.Handler) RemoteOpt { + return func(client *Client, c *RemoteContext) error { + c.HandlerWrapper = w + return nil + } +} + +// WithMaxConcurrentDownloads sets max concurrent download limit. +func WithMaxConcurrentDownloads(max int) RemoteOpt { + return func(client *Client, c *RemoteContext) error { + c.MaxConcurrentDownloads = max + return nil + } +} + +// WithMaxConcurrentUploadedLayers sets max concurrent uploaded layer limit. +func WithMaxConcurrentUploadedLayers(max int) RemoteOpt { + return func(client *Client, c *RemoteContext) error { + c.MaxConcurrentUploadedLayers = max + return nil + } +} + +// WithAllMetadata downloads all manifests and known-configuration files +func WithAllMetadata() RemoteOpt { + return func(_ *Client, c *RemoteContext) error { + c.AllMetadata = true + return nil + } +} diff -Nru containerd-1.2.6/client_test.go containerd-1.5.9/client_test.go --- containerd-1.2.6/client_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/client_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,345 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "bytes" - "context" - "flag" - "fmt" - "os" - "os/exec" - "testing" - "time" - - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/pkg/testutil" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/sys" - "github.com/sirupsen/logrus" -) - -var ( - address string - noDaemon bool - noCriu bool - supportsCriu bool - testNamespace = "testing" - - ctrd = &daemon{} -) - -func init() { - flag.StringVar(&address, "address", defaultAddress, "The address to the containerd socket for use in the tests") - flag.BoolVar(&noDaemon, "no-daemon", false, "Do not start a dedicated daemon for the tests") - flag.BoolVar(&noCriu, "no-criu", false, "Do not run the checkpoint tests") - flag.Parse() -} - -func testContext() (context.Context, context.CancelFunc) { - ctx, cancel := context.WithCancel(context.Background()) - ctx = namespaces.WithNamespace(ctx, testNamespace) - return ctx, cancel -} - -func TestMain(m *testing.M) { - if testing.Short() { - os.Exit(m.Run()) - } - testutil.RequiresRootM() - // check if criu is installed on the system - _, err := exec.LookPath("criu") - supportsCriu = err == nil && !noCriu - - var ( - buf = bytes.NewBuffer(nil) - ctx, cancel = testContext() - ) - defer cancel() - - if !noDaemon { - sys.ForceRemoveAll(defaultRoot) - - err := ctrd.start("containerd", address, []string{ - "--root", defaultRoot, - "--state", defaultState, - "--log-level", "debug", - }, buf, buf) - if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s", err, buf.String()) - os.Exit(1) - } - } - - waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) - client, err := ctrd.waitForStart(waitCtx) - waitCancel() - if err != nil { - ctrd.Kill() - ctrd.Wait() - fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String()) - os.Exit(1) - } - - // print out the version in information - version, err := client.Version(ctx) - if err != nil { - fmt.Fprintf(os.Stderr, "error getting version: %s\n", err) - os.Exit(1) - } - - // allow comparison with containerd under test - log.G(ctx).WithFields(logrus.Fields{ - "version": version.Version, - "revision": version.Revision, - }).Info("running tests against containerd") - - // pull a seed image - if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil { - ctrd.Stop() - ctrd.Wait() - fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String()) - os.Exit(1) - } - - if err := client.Close(); err != nil { - fmt.Fprintln(os.Stderr, "failed to close client", err) - } - - // run the test - status := m.Run() - - if !noDaemon { - // tear down the daemon and resources created - if err := ctrd.Stop(); err != nil { - if err := ctrd.Kill(); err != nil { - fmt.Fprintln(os.Stderr, "failed to signal containerd", err) - } - } - if err := ctrd.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { - fmt.Fprintln(os.Stderr, "failed to wait for containerd", err) - } - } - if err := sys.ForceRemoveAll(defaultRoot); err != nil { - fmt.Fprintln(os.Stderr, "failed to remove test root dir", err) - os.Exit(1) - } - // only print containerd logs if the test failed - if status != 0 { - fmt.Fprintln(os.Stderr, buf.String()) - } - } - os.Exit(status) -} - -func newClient(t testing.TB, address string, opts ...ClientOpt) (*Client, error) { - if testing.Short() { - t.Skip() - } - if rt := os.Getenv("TEST_RUNTIME"); rt != "" { - opts = append(opts, WithDefaultRuntime(rt)) - } - // testutil.RequiresRoot(t) is not needed here (already called in TestMain) - return New(address, opts...) -} - -func TestNewClient(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - if client == nil { - t.Fatal("New() returned nil client") - } - if err := client.Close(); err != nil { - t.Errorf("client closed returned error %v", err) - } -} - -// All the container's tests depends on this, we need it to run first. -func TestImagePull(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - _, err = client.Pull(ctx, testImage, WithPlatformMatcher(platforms.Default())) - if err != nil { - t.Fatal(err) - } -} - -func TestImagePullAllPlatforms(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - ctx, cancel := testContext() - defer cancel() - - cs := client.ContentStore() - img, err := client.Fetch(ctx, "docker.io/library/busybox:latest") - if err != nil { - t.Fatal(err) - } - index := img.Target - manifests, err := images.Children(ctx, cs, index) - if err != nil { - t.Fatal(err) - } - for _, manifest := range manifests { - children, err := images.Children(ctx, cs, manifest) - if err != nil { - t.Fatal("Th") - } - // check if childless data type has blob in content store - for _, desc := range children { - ra, err := cs.ReaderAt(ctx, desc) - if err != nil { - t.Fatal(err) - } - ra.Close() - } - } -} - -func TestImagePullSomePlatforms(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - ctx, cancel := testContext() - defer cancel() - - cs := client.ContentStore() - platformList := []string{"linux/amd64", "linux/arm64/v8", "linux/s390x"} - m := make(map[string]platforms.Matcher) - var opts []RemoteOpt - - for _, platform := range platformList { - p, err := platforms.Parse(platform) - if err != nil { - t.Fatal(err) - } - m[platform] = platforms.NewMatcher(p) - opts = append(opts, WithPlatform(platform)) - } - - img, err := client.Fetch(ctx, "k8s.gcr.io/pause:3.1", opts...) - if err != nil { - t.Fatal(err) - } - - index := img.Target - manifests, err := images.Children(ctx, cs, index) - if err != nil { - t.Fatal(err) - } - - count := 0 - for _, manifest := range manifests { - children, err := images.Children(ctx, cs, manifest) - found := false - for _, matcher := range m { - if matcher.Match(*manifest.Platform) { - count++ - found = true - } - } - - if found { - if len(children) == 0 { - t.Fatal("manifest should have pulled children content") - } - - // check if childless data type has blob in content store - for _, desc := range children { - ra, err := cs.ReaderAt(ctx, desc) - if err != nil { - t.Fatal(err) - } - ra.Close() - } - } else if !found && err == nil { - t.Fatal("manifest should not have pulled children content") - } - } - - if count != len(platformList) { - t.Fatal("expected a different number of pulled manifests") - } -} - -func TestImagePullSchema1(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - schema1TestImage := "gcr.io/google_containers/pause:3.0@sha256:0d093c962a6c2dd8bb8727b661e2b5f13e9df884af9945b4cc7088d9350cd3ee" - _, err = client.Pull(ctx, schema1TestImage, WithPlatform(platforms.DefaultString()), WithSchema1Conversion) - if err != nil { - t.Fatal(err) - } -} - -func TestClientReconnect(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - if client == nil { - t.Fatal("New() returned nil client") - } - ok, err := client.IsServing(ctx) - if err != nil { - t.Fatal(err) - } - if !ok { - t.Fatal("containerd is not serving") - } - if err := client.Reconnect(); err != nil { - t.Fatal(err) - } - if ok, err = client.IsServing(ctx); err != nil { - t.Fatal(err) - } - if !ok { - t.Fatal("containerd is not serving") - } - if err := client.Close(); err != nil { - t.Errorf("client closed returned error %v", err) - } -} diff -Nru containerd-1.2.6/client_unix_test.go containerd-1.5.9/client_unix_test.go --- containerd-1.2.6/client_unix_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/client_unix_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "runtime" -) - -const ( - defaultRoot = "/var/lib/containerd-test" - defaultState = "/run/containerd-test" - defaultAddress = "/run/containerd-test/containerd.sock" -) - -var ( - testImage string -) - -func init() { - switch runtime.GOARCH { - case "386": - testImage = "docker.io/i386/alpine:latest" - case "arm": - testImage = "docker.io/arm32v6/alpine:latest" - case "arm64": - testImage = "docker.io/arm64v8/alpine:latest" - case "ppc64le": - testImage = "docker.io/ppc64le/alpine:latest" - case "s390x": - testImage = "docker.io/s390x/alpine:latest" - default: - testImage = "docker.io/library/alpine:latest" - } -} diff -Nru containerd-1.2.6/client_windows_test.go containerd-1.5.9/client_windows_test.go --- containerd-1.2.6/client_windows_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/client_windows_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "os" - "path/filepath" -) - -const ( - defaultAddress = `\\.\pipe\containerd-containerd-test` - testImage = "docker.io/microsoft/nanoserver:latest" -) - -var ( - defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test") - defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test") -) diff -Nru containerd-1.2.6/cluster/gce/cloud-init/master.yaml containerd-1.5.9/cluster/gce/cloud-init/master.yaml --- containerd-1.2.6/cluster/gce/cloud-init/master.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cluster/gce/cloud-init/master.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,199 @@ +#cloud-config + +users: +- name: etcd + homedir: /var/etcd + lock_passwd: true + ssh_redirect_user: true + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-master-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-master-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes master + After=kube-master-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-master-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-master-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-master-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-master-installation.service + - systemctl enable kube-master-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/cluster/gce/cloud-init/node.yaml containerd-1.5.9/cluster/gce/cloud-init/node.yaml --- containerd-1.2.6/cluster/gce/cloud-init/node.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cluster/gce/cloud-init/node.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,193 @@ +#cloud-config + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-node-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-node-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes node + After=kube-node-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-node-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-node-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-node-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-node-installation.service + - systemctl enable kube-node-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/cluster/gce/cni.template containerd-1.5.9/cluster/gce/cni.template --- containerd-1.2.6/cluster/gce/cni.template 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cluster/gce/cni.template 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +{ + "name": "k8s-pod-network", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "ptp", + "mtu": 1460, + "ipam": { + "type": "host-local", + "ranges": [{{range $i, $range := .PodCIDRRanges}}{{if $i}}, {{end}}[{"subnet": "{{$range}}"}]{{end}}], + "routes": [{{range $i, $route := .Routes}}{{if $i}}, {{end}}{"dst": "{{$route}}"}{{end}}] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] +} diff -Nru containerd-1.2.6/cluster/gce/configure.sh containerd-1.5.9/cluster/gce/configure.sh --- containerd-1.2.6/cluster/gce/configure.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cluster/gce/configure.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,239 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o xtrace +set -o errexit +set -o nounset +set -o pipefail + +if [[ "$(python -V 2>&1)" =~ "Python 2" ]]; then + # found python2, just use that + PYTHON="python" +elif [[ -f "/usr/bin/python2.7" ]]; then + # System python not defaulted to python 2 but using 2.7 during migration + PYTHON="/usr/bin/python2.7" +else + # No python2 either by default, let's see if we can find python3 + PYTHON="python3" + if ! command -v ${PYTHON} >/dev/null 2>&1; then + echo "ERROR Python not found. Aborting." + exit 2 + fi +fi +echo "Version : " $(${PYTHON} -V 2>&1) + +# CONTAINERD_HOME is the directory for containerd. +CONTAINERD_HOME="/home/containerd" +cd "${CONTAINERD_HOME}" +# KUBE_HOME is the directory for kubernetes. +KUBE_HOME="/home/kubernetes" + +# fetch_metadata fetches metadata from GCE metadata server. +# Var set: +# 1. Metadata key: key of the metadata. +fetch_metadata() { + local -r key=$1 + local -r attributes="http://metadata.google.internal/computeMetadata/v1/instance/attributes" + if curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" "${attributes}/" | \ + grep -q "^${key}$"; then + curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" \ + "${attributes}/${key}" + fi +} + +# fetch_env fetches environment variables from GCE metadata server +# and generate a env file under ${CONTAINERD_HOME}. It assumes that +# the environment variables in metadata are in yaml format. +fetch_env() { + local -r env_file_name=$1 + ( + umask 077; + local -r tmp_env_file="/tmp/${env_file_name}.yaml" + tmp_env_content=$(fetch_metadata "${env_file_name}") + if [ -z "${tmp_env_content}" ]; then + echo "No environment variable is specified in ${env_file_name}" + return + fi + echo "${tmp_env_content}" > "${tmp_env_file}" + # Convert the yaml format file into a shell-style file. + eval $(${PYTHON} -c ''' +import pipes,sys,yaml +# check version of python and call methods appropriate for that version +if sys.version_info[0] < 3: + items = yaml.load(sys.stdin).iteritems() +else: + items = yaml.load(sys.stdin, Loader=yaml.BaseLoader).items() +for k,v in items: + print("readonly {var}={value}".format(var = k, value = pipes.quote(str(v)))) +''' < "${tmp_env_file}" > "${CONTAINERD_HOME}/${env_file_name}") + rm -f "${tmp_env_file}" + ) +} + +# is_preloaded checks whether a package has been preloaded in the image. +is_preloaded() { + local -r tar=$1 + local -r sha1=$2 + grep -qs "${tar},${sha1}" "${KUBE_HOME}/preload_info" +} + +# KUBE_ENV_METADATA is the metadata key for kubernetes envs. +KUBE_ENV_METADATA="kube-env" +fetch_env ${KUBE_ENV_METADATA} +if [ -f "${CONTAINERD_HOME}/${KUBE_ENV_METADATA}" ]; then + source "${CONTAINERD_HOME}/${KUBE_ENV_METADATA}" +fi + +# CONTAINERD_ENV_METADATA is the metadata key for containerd envs. +CONTAINERD_ENV_METADATA="containerd-env" +fetch_env ${CONTAINERD_ENV_METADATA} +if [ -f "${CONTAINERD_HOME}/${CONTAINERD_ENV_METADATA}" ]; then + source "${CONTAINERD_HOME}/${CONTAINERD_ENV_METADATA}" +fi + +# CONTAINERD_PKG_PREFIX is the prefix of the cri-containerd tarball name. +# By default use the release tarball with cni built in. +pkg_prefix=${CONTAINERD_PKG_PREFIX:-"cri-containerd-cni"} +# Behave differently for test and production. +if [ "${CONTAINERD_TEST:-"false"}" != "true" ]; then + # CONTAINERD_DEPLOY_PATH is the gcs path where cri-containerd tarball is stored. + deploy_path=${CONTAINERD_DEPLOY_PATH:-"cri-containerd-release"} + # CONTAINERD_VERSION is the cri-containerd version to use. + version=${CONTAINERD_VERSION:-""} +else + deploy_path=${CONTAINERD_DEPLOY_PATH:-"cri-containerd-staging"} + + # PULL_REFS_METADATA is the metadata key of PULL_REFS from prow. + PULL_REFS_METADATA="PULL_REFS" + pull_refs=$(fetch_metadata "${PULL_REFS_METADATA}") + if [ ! -z "${pull_refs}" ]; then + deploy_dir=$(echo "${pull_refs}" | sha1sum | awk '{print $1}') + deploy_path="${deploy_path}/containerd/${deploy_dir}" + fi + + # TODO(random-liu): Put version into the metadata instead of + # deciding it in cloud init. This may cause issue to reboot test. + version=$(curl -f --ipv4 --retry 6 --retry-delay 3 --silent --show-error \ + https://storage.googleapis.com/${deploy_path}/latest) +fi + +TARBALL_GCS_NAME="${pkg_prefix}-${version}.linux-amd64.tar.gz" +# TARBALL_GCS_PATH is the path to download cri-containerd tarball for node e2e. +TARBALL_GCS_PATH="https://storage.googleapis.com/${deploy_path}/${TARBALL_GCS_NAME}" +# TARBALL is the name of the tarball after being downloaded. +TARBALL="containerd.tar.gz" +# CONTAINERD_TAR_SHA1 is the sha1sum of containerd tarball. +tar_sha1="${CONTAINERD_TAR_SHA1:-""}" + +if [ -z "${version}" ]; then + # Try using preloaded containerd if version is not specified. + tarball_gcs_pattern="${pkg_prefix}-.*.linux-amd64.tar.gz" + if is_preloaded "${tarball_gcs_pattern}" "${tar_sha1}"; then + echo "CONTAINERD_VERSION is not set, use preloaded containerd" + else + echo "CONTAINERD_VERSION is not set, and containerd is not preloaded" + exit 1 + fi +else + if is_preloaded "${TARBALL_GCS_NAME}" "${tar_sha1}"; then + echo "${TARBALL_GCS_NAME} is preloaded" + else + # Download and untar the release tar ball. + curl -f --ipv4 -Lo "${TARBALL}" --connect-timeout 20 --max-time 300 --retry 6 --retry-delay 10 "${TARBALL_GCS_PATH}" + tar xvf "${TARBALL}" + rm -f "${TARBALL}" + fi +fi + +# Remove crictl shipped with containerd, use crictl installed +# by kube-up.sh. +rm -f "${CONTAINERD_HOME}/usr/local/bin/crictl" +rm -f "${CONTAINERD_HOME}/etc/crictl.yaml" + +# Generate containerd config +config_path="${CONTAINERD_CONFIG_PATH:-"/etc/containerd/config.toml"}" +mkdir -p $(dirname ${config_path}) +cni_bin_dir="${CONTAINERD_HOME}/opt/cni/bin" +cni_template_path="${CONTAINERD_HOME}/opt/containerd/cluster/gce/cni.template" +if [ "${KUBERNETES_MASTER:-}" != "true" ]; then + if [ "${NETWORK_POLICY_PROVIDER:-"none"}" != "none" ] || [ "${ENABLE_NETD:-}" == "true" ]; then + # Use Kubernetes cni daemonset on node if network policy provider is specified + # or netd is enabled. + cni_bin_dir="${KUBE_HOME}/bin" + cni_template_path="" + fi +fi +log_level="${CONTAINERD_LOG_LEVEL:-"info"}" +max_container_log_line="${CONTAINERD_MAX_CONTAINER_LOG_LINE:-16384}" +cat > ${config_path} <> ${config_path} < \ + /etc/profile.d/containerd_env.sh + +# Run extra init script for test. +if [ "${CONTAINERD_TEST:-"false"}" == "true" ]; then + # EXTRA_INIT_SCRIPT is the name of the extra init script after being downloaded. + EXTRA_INIT_SCRIPT="containerd-extra-init.sh" + # EXTRA_INIT_SCRIPT_METADATA is the metadata key of init script. + EXTRA_INIT_SCRIPT_METADATA="containerd-extra-init-sh" + extra_init=$(fetch_metadata "${EXTRA_INIT_SCRIPT_METADATA}") + # Return if containerd-extra-init-sh is not set. + if [ -z "${extra_init}" ]; then + exit 0 + fi + echo "${extra_init}" > "${EXTRA_INIT_SCRIPT}" + chmod 544 "${EXTRA_INIT_SCRIPT}" + ./${EXTRA_INIT_SCRIPT} +fi diff -Nru containerd-1.2.6/cluster/gce/env containerd-1.5.9/cluster/gce/env --- containerd-1.2.6/cluster/gce/env 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cluster/gce/env 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,20 @@ +#!/bin/bash +GCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# TODO(random-liu): Upload release tarball to user's own GCS, and use it. We should +# not let all nodes of all users download tarball from cri-containerd-release. +version_file=${GCE_DIR}/../version +if [ ! -f "${version_file}" ]; then + echo "version file does not exist" + exit 1 +fi +export KUBE_MASTER_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/master.yaml,containerd-configure-sh=${GCE_DIR}/configure.sh,containerd-env=${version_file}" +export KUBE_NODE_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/node.yaml,containerd-configure-sh=${GCE_DIR}/configure.sh,containerd-env=${version_file}" +export KUBE_CONTAINER_RUNTIME="remote" +export KUBE_CONTAINER_RUNTIME_ENDPOINT="unix:///run/containerd/containerd.sock" +export KUBE_CONTAINER_RUNTIME_NAME=containerd +export KUBE_LOAD_IMAGE_COMMAND="/home/containerd/usr/local/bin/ctr -n=k8s.io images import" +export NETWORK_PROVIDER="" +export NON_MASQUERADE_CIDR="0.0.0.0/0" +export KUBE_KUBELET_EXTRA_ARGS="--runtime-cgroups=/system.slice/containerd.service" +export KUBE_FEATURE_GATES="ExperimentalCriticalPodAnnotation=true,CRIContainerLogRotation=true" diff -Nru containerd-1.2.6/cmd/containerd/builtins_aufs_linux.go containerd-1.5.9/cmd/containerd/builtins_aufs_linux.go --- containerd-1.2.6/cmd/containerd/builtins_aufs_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_aufs_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +// +build !no_aufs + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import _ "github.com/containerd/aufs/plugin" diff -Nru containerd-1.2.6/cmd/containerd/builtins_btrfs_linux.go containerd-1.5.9/cmd/containerd/builtins_btrfs_linux.go --- containerd-1.2.6/cmd/containerd/builtins_btrfs_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_btrfs_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !no_btrfs +// +build !no_btrfs,cgo /* Copyright The containerd Authors. @@ -18,4 +18,4 @@ package main -import _ "github.com/containerd/containerd/snapshots/btrfs" +import _ "github.com/containerd/containerd/snapshots/btrfs/plugin" diff -Nru containerd-1.2.6/cmd/containerd/builtins_cri.go containerd-1.5.9/cmd/containerd/builtins_cri.go --- containerd-1.2.6/cmd/containerd/builtins_cri.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_cri.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +// +build linux,!no_cri windows,!no_cri + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import _ "github.com/containerd/containerd/pkg/cri" diff -Nru containerd-1.2.6/cmd/containerd/builtins_cri_linux.go containerd-1.5.9/cmd/containerd/builtins_cri_linux.go --- containerd-1.2.6/cmd/containerd/builtins_cri_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_cri_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -// +build !no_cri - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import _ "github.com/containerd/cri" diff -Nru containerd-1.2.6/cmd/containerd/builtins_devmapper_linux.go containerd-1.5.9/cmd/containerd/builtins_devmapper_linux.go --- containerd-1.2.6/cmd/containerd/builtins_devmapper_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_devmapper_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +// +build !no_devmapper + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import _ "github.com/containerd/containerd/snapshots/devmapper/plugin" diff -Nru containerd-1.2.6/cmd/containerd/builtins_freebsd.go containerd-1.5.9/cmd/containerd/builtins_freebsd.go --- containerd-1.2.6/cmd/containerd/builtins_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import _ "github.com/containerd/zfs/plugin" diff -Nru containerd-1.2.6/cmd/containerd/builtins_linux.go containerd-1.5.9/cmd/containerd/builtins_linux.go --- containerd-1.2.6/cmd/containerd/builtins_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,12 +17,11 @@ package main import ( - _ "github.com/containerd/aufs" _ "github.com/containerd/containerd/metrics/cgroups" + _ "github.com/containerd/containerd/metrics/cgroups/v2" _ "github.com/containerd/containerd/runtime/v1/linux" _ "github.com/containerd/containerd/runtime/v2" _ "github.com/containerd/containerd/runtime/v2/runc/options" - _ "github.com/containerd/containerd/snapshots/native" - _ "github.com/containerd/containerd/snapshots/overlay" - _ "github.com/containerd/zfs" + _ "github.com/containerd/containerd/snapshots/native/plugin" + _ "github.com/containerd/containerd/snapshots/overlay/plugin" ) diff -Nru containerd-1.2.6/cmd/containerd/builtins_unix.go containerd-1.5.9/cmd/containerd/builtins_unix.go --- containerd-1.2.6/cmd/containerd/builtins_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,5 +19,5 @@ package main import ( - _ "github.com/containerd/containerd/snapshots/native" + _ "github.com/containerd/containerd/snapshots/native/plugin" ) diff -Nru containerd-1.2.6/cmd/containerd/builtins_windows.go containerd-1.5.9/cmd/containerd/builtins_windows.go --- containerd-1.2.6/cmd/containerd/builtins_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !windows_v2 +// +build windows /* Copyright The containerd Authors. @@ -21,7 +21,7 @@ import ( _ "github.com/containerd/containerd/diff/lcow" _ "github.com/containerd/containerd/diff/windows" + _ "github.com/containerd/containerd/runtime/v2" _ "github.com/containerd/containerd/snapshots/lcow" _ "github.com/containerd/containerd/snapshots/windows" - _ "github.com/containerd/containerd/windows" ) diff -Nru containerd-1.2.6/cmd/containerd/builtins_windows_v2.go containerd-1.5.9/cmd/containerd/builtins_windows_v2.go --- containerd-1.2.6/cmd/containerd/builtins_windows_v2.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_windows_v2.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -// +build windows_v2 - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import ( - _ "github.com/containerd/containerd/diff/lcow" - _ "github.com/containerd/containerd/diff/windows" - _ "github.com/containerd/containerd/runtime/v2" - _ "github.com/containerd/containerd/snapshots/lcow" - _ "github.com/containerd/containerd/snapshots/windows" -) diff -Nru containerd-1.2.6/cmd/containerd/builtins_zfs_linux.go containerd-1.5.9/cmd/containerd/builtins_zfs_linux.go --- containerd-1.2.6/cmd/containerd/builtins_zfs_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/builtins_zfs_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +// +build !no_zfs + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import _ "github.com/containerd/zfs/plugin" diff -Nru containerd-1.2.6/cmd/containerd/command/config.go containerd-1.5.9/cmd/containerd/command/config.go --- containerd-1.2.6/cmd/containerd/command/config.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,17 +20,22 @@ gocontext "context" "io" "os" + "path/filepath" - "github.com/BurntSushi/toml" + "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/services/server" srvconfig "github.com/containerd/containerd/services/server/config" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pelletier/go-toml" "github.com/urfave/cli" ) // Config is a wrapper of server config for printing out. type Config struct { *srvconfig.Config - // Plugins overrides `Plugins map[string]toml.Primitive` in server config. + // Plugins overrides `Plugins map[string]toml.Tree` in server config. Plugins map[string]interface{} `toml:"plugins"` } @@ -39,6 +44,54 @@ return 0, toml.NewEncoder(w).Encode(c) } +func outputConfig(cfg *srvconfig.Config) error { + config := &Config{ + Config: cfg, + } + + plugins, err := server.LoadPlugins(gocontext.Background(), config.Config) + if err != nil { + return err + } + if len(plugins) != 0 { + config.Plugins = make(map[string]interface{}) + for _, p := range plugins { + if p.Config == nil { + continue + } + + pc, err := config.Decode(p) + if err != nil { + return err + } + + config.Plugins[p.URI()] = pc + } + } + + if config.Timeouts == nil { + config.Timeouts = make(map[string]string) + } + timeouts := timeout.All() + for k, v := range timeouts { + if config.Timeouts[k] == "" { + config.Timeouts[k] = v.String() + } + } + + // for the time being, keep the defaultConfig's version set at 1 so that + // when a config without a version is loaded from disk and has no version + // set, we assume it's a v1 config. But when generating new configs via + // this command, generate the v2 config + config.Config.Version = 2 + + // remove overridden Plugins type to avoid duplication in output + config.Config.Plugins = nil + + _, err = config.WriteTo(os.Stdout) + return err +} + var configCommand = cli.Command{ Name: "config", Usage: "information on the containerd config", @@ -47,25 +100,70 @@ Name: "default", Usage: "see the output of the default config", Action: func(context *cli.Context) error { - config := &Config{ - Config: defaultConfig(), - } - plugins, err := server.LoadPlugins(gocontext.Background(), config.Config) - if err != nil { + return outputConfig(defaultConfig()) + }, + }, + { + Name: "dump", + Usage: "see the output of the final main config with imported in subconfig files", + Action: func(context *cli.Context) error { + config := defaultConfig() + if err := srvconfig.LoadConfig(context.GlobalString("config"), config); err != nil && !os.IsNotExist(err) { return err } - if len(plugins) != 0 { - config.Plugins = make(map[string]interface{}) - for _, p := range plugins { - if p.Config == nil { - continue - } - config.Plugins[p.ID] = p.Config - } - } - _, err = config.WriteTo(os.Stdout) - return err + + return outputConfig(config) }, }, }, } + +func platformAgnosticDefaultConfig() *srvconfig.Config { + return &srvconfig.Config{ + // see: https://github.com/containerd/containerd/blob/5c6ea7fdc1247939edaddb1eba62a94527418687/RELEASES.md#daemon-configuration + // this version MUST remain set to 1 until either there exists a means to + // override / configure the default at the containerd cli .. or when + // version 1 is no longer supported + Version: 1, + Root: defaults.DefaultRootDir, + State: defaults.DefaultStateDir, + GRPC: srvconfig.GRPCConfig{ + Address: defaults.DefaultAddress, + MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, + MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, + }, + DisabledPlugins: []string{}, + RequiredPlugins: []string{}, + StreamProcessors: streamProcessors(), + } +} + +func streamProcessors() map[string]srvconfig.StreamProcessor { + const ( + ctdDecoder = "ctd-decoder" + basename = "io.containerd.ocicrypt.decoder.v1" + ) + decryptionKeysPath := filepath.Join(defaults.DefaultConfigDir, "ocicrypt", "keys") + ctdDecoderArgs := []string{ + "--decryption-keys-path", decryptionKeysPath, + } + ctdDecoderEnv := []string{ + "OCICRYPT_KEYPROVIDER_CONFIG=" + filepath.Join(defaults.DefaultConfigDir, "ocicrypt", "ocicrypt_keyprovider.conf"), + } + return map[string]srvconfig.StreamProcessor{ + basename + ".tar.gzip": { + Accepts: []string{images.MediaTypeImageLayerGzipEncrypted}, + Returns: ocispec.MediaTypeImageLayerGzip, + Path: ctdDecoder, + Args: ctdDecoderArgs, + Env: ctdDecoderEnv, + }, + basename + ".tar": { + Accepts: []string{images.MediaTypeImageLayerEncrypted}, + Returns: ocispec.MediaTypeImageLayer, + Path: ctdDecoder, + Args: ctdDecoderArgs, + Env: ctdDecoderEnv, + }, + } +} diff -Nru containerd-1.2.6/cmd/containerd/command/config_linux.go containerd-1.5.9/cmd/containerd/command/config_linux.go --- containerd-1.2.6/cmd/containerd/command/config_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/config_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,18 +17,9 @@ package command import ( - "github.com/containerd/containerd/defaults" srvconfig "github.com/containerd/containerd/services/server/config" ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, - MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, - }, - } + return platformAgnosticDefaultConfig() } diff -Nru containerd-1.2.6/cmd/containerd/command/config_unsupported.go containerd-1.5.9/cmd/containerd/command/config_unsupported.go --- containerd-1.2.6/cmd/containerd/command/config_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/config_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,15 +24,10 @@ ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - }, - Debug: srvconfig.Debug{ - Level: "info", - Address: defaults.DefaultDebugAddress, - }, + cfg := platformAgnosticDefaultConfig() + cfg.Debug = srvconfig.Debug{ + Level: "info", + Address: defaults.DefaultDebugAddress, } + return cfg } diff -Nru containerd-1.2.6/cmd/containerd/command/config_windows.go containerd-1.5.9/cmd/containerd/command/config_windows.go --- containerd-1.2.6/cmd/containerd/command/config_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/config_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,18 +17,9 @@ package command import ( - "github.com/containerd/containerd/defaults" srvconfig "github.com/containerd/containerd/services/server/config" ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, - MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, - }, - } + return platformAgnosticDefaultConfig() } diff -Nru containerd-1.2.6/cmd/containerd/command/main.go containerd-1.5.9/cmd/containerd/command/main.go --- containerd-1.2.6/cmd/containerd/command/main.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,8 +24,11 @@ "os" "os/signal" "path/filepath" + "runtime" "time" + "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/services/server" @@ -49,11 +52,6 @@ ` func init() { - logrus.SetFormatter(&logrus.TextFormatter{ - TimestampFormat: log.RFC3339NanoFixed, - FullTimestamp: true, - }) - // Discard grpc logs so that they don't mess with our stdio grpclog.SetLoggerV2(grpclog.NewLoggerV2(ioutil.Discard, ioutil.Discard, ioutil.Discard)) @@ -68,11 +66,22 @@ app.Name = "containerd" app.Version = version.Version app.Usage = usage + app.Description = ` +containerd is a high performance container runtime whose daemon can be started +by using this command. If none of the *config*, *publish*, or *help* commands +are specified, the default action of the **containerd** command is to start the +containerd daemon in the foreground. + + +A default configuration is used if no TOML configuration is specified or located +at the default file location. The *containerd config* command can be used to +generate the default configuration for containerd. The output of that command +can be used and modified as necessary as a custom configuration.` app.Flags = []cli.Flag{ cli.StringFlag{ Name: "config,c", Usage: "path to the configuration file", - Value: defaultConfigPath, + Value: filepath.Join(defaults.DefaultConfigDir, "config.toml"), }, cli.StringFlag{ Name: "log-level,l", @@ -91,6 +100,7 @@ Usage: "containerd state directory", }, } + app.Flags = append(app.Flags, serviceFlags()...) app.Commands = []cli.Command{ configCommand, publishCommand, @@ -105,18 +115,40 @@ config = defaultConfig() ) - done := handleSignals(ctx, signals, serverC) - // start the signal handler as soon as we can to make sure that - // we don't miss any signals during boot - signal.Notify(signals, handledSignals...) + // Only try to load the config if it either exists, or the user explicitly + // told us to load this path. + configPath := context.GlobalString("config") + _, err := os.Stat(configPath) + if !os.IsNotExist(err) || context.GlobalIsSet("config") { + if err := srvconfig.LoadConfig(configPath, config); err != nil { + return err + } + } - if err := srvconfig.LoadConfig(context.GlobalString("config"), config); err != nil && !os.IsNotExist(err) { + // Apply flags to the config + if err := applyFlags(context, config); err != nil { return err } - // apply flags to the config - if err := applyFlags(context, config); err != nil { + + // Make sure top-level directories are created early. + if err := server.CreateTopLevelDirectories(config); err != nil { return err } + + // Stop if we are registering or unregistering against Windows SCM. + stop, err := registerUnregisterService(config.Root) + if err != nil { + logrus.Fatal(err) + } + if stop { + return nil + } + + done := handleSignals(ctx, signals, serverC) + // start the signal handler as soon as we can to make sure that + // we don't miss any signals during boot + signal.Notify(signals, handledSignals...) + // cleanup temp mounts if err := mount.SetTempMountLocation(filepath.Join(config.Root, "tmpmounts")); err != nil { return errors.Wrap(err, "creating temp mount location") @@ -129,9 +161,15 @@ for _, w := range warnings { log.G(ctx).WithError(w).Warn("cleanup temp mount") } - address := config.GRPC.Address - if address == "" { - return errors.New("grpc address cannot be empty") + + if config.GRPC.Address == "" { + return errors.Wrap(errdefs.ErrInvalidArgument, "grpc address cannot be empty") + } + if config.TTRPC.Address == "" { + // If TTRPC was not explicitly configured, use defaults based on GRPC. + config.TTRPC.Address = fmt.Sprintf("%s.ttrpc", config.GRPC.Address) + config.TTRPC.UID = config.GRPC.UID + config.TTRPC.GID = config.GRPC.GID } log.G(ctx).WithFields(logrus.Fields{ "version": version.Version, @@ -142,10 +180,17 @@ if err != nil { return err } + + // Launch as a Windows Service if necessary + if err := launchService(server, done); err != nil { + logrus.Fatal(err) + } + serverC <- server + if config.Debug.Address != "" { var l net.Listener - if filepath.IsAbs(config.Debug.Address) { + if isLocalAddress(config.Debug.Address) { if l, err = sys.GetLocalListener(config.Debug.Address, config.Debug.UID, config.Debug.GID); err != nil { return errors.Wrapf(err, "failed to get listener for debug endpoint") } @@ -163,13 +208,31 @@ } serve(ctx, l, server.ServeMetrics) } + // setup the ttrpc endpoint + tl, err := sys.GetLocalListener(config.TTRPC.Address, config.TTRPC.UID, config.TTRPC.GID) + if err != nil { + return errors.Wrapf(err, "failed to get listener for main ttrpc endpoint") + } + serve(ctx, tl, server.ServeTTRPC) - l, err := sys.GetLocalListener(address, config.GRPC.UID, config.GRPC.GID) + if config.GRPC.TCPAddress != "" { + l, err := net.Listen("tcp", config.GRPC.TCPAddress) + if err != nil { + return errors.Wrapf(err, "failed to get listener for TCP grpc endpoint") + } + serve(ctx, l, server.ServeTCP) + } + // setup the main grpc endpoint + l, err := sys.GetLocalListener(config.GRPC.Address, config.GRPC.UID, config.GRPC.GID) if err != nil { return errors.Wrapf(err, "failed to get listener for main endpoint") } serve(ctx, l, server.ServeGRPC) + if err := notifyReady(ctx); err != nil { + log.G(ctx).WithError(err).Warn("notify ready failed") + } + log.G(ctx).Infof("containerd successfully booted in %fs", time.Since(start).Seconds()) <-done return nil @@ -191,7 +254,10 @@ func applyFlags(context *cli.Context, config *srvconfig.Config) error { // the order for config vs flag values is that flags will always override // the config values if they are set - if err := setLevel(context, config); err != nil { + if err := setLogLevel(context, config); err != nil { + return err + } + if err := setLogFormat(config); err != nil { return err } for _, v := range []struct { @@ -215,16 +281,19 @@ *v.d = s } } + + applyPlatformFlags(context) + return nil } -func setLevel(context *cli.Context, config *srvconfig.Config) error { +func setLogLevel(context *cli.Context, config *srvconfig.Config) error { l := context.GlobalString("log-level") if l == "" { l = config.Debug.Level } if l != "" { - lvl, err := log.ParseLevel(l) + lvl, err := logrus.ParseLevel(l) if err != nil { return err } @@ -232,3 +301,53 @@ } return nil } + +func setLogFormat(config *srvconfig.Config) error { + f := config.Debug.Format + if f == "" { + f = log.TextFormat + } + + switch f { + case log.TextFormat: + logrus.SetFormatter(&logrus.TextFormatter{ + TimestampFormat: log.RFC3339NanoFixed, + FullTimestamp: true, + }) + case log.JSONFormat: + logrus.SetFormatter(&logrus.JSONFormatter{ + TimestampFormat: log.RFC3339NanoFixed, + }) + default: + return errors.Errorf("unknown log format: %s", f) + } + + return nil +} + +func dumpStacks(writeToFile bool) { + var ( + buf []byte + stackSize int + ) + bufferLen := 16384 + for stackSize == len(buf) { + buf = make([]byte, bufferLen) + stackSize = runtime.Stack(buf, true) + bufferLen *= 2 + } + buf = buf[:stackSize] + logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) + + if writeToFile { + // Also write to file to aid gathering diagnostics + name := filepath.Join(os.TempDir(), fmt.Sprintf("containerd.%d.stacks.log", os.Getpid())) + f, err := os.Create(name) + if err != nil { + return + } + defer f.Close() + f.WriteString(string(buf)) + logrus.Infof("goroutine stack dump written to %s", name) + } +} diff -Nru containerd-1.2.6/cmd/containerd/command/main_unix.go containerd-1.5.9/cmd/containerd/command/main_unix.go --- containerd-1.2.6/cmd/containerd/command/main_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/main_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,16 +21,13 @@ import ( "context" "os" - "runtime" + "path/filepath" "github.com/containerd/containerd/log" "github.com/containerd/containerd/services/server" - "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) -const defaultConfigPath = "/etc/containerd/config.toml" - var handledSignals = []os.Signal{ unix.SIGTERM, unix.SIGINT, @@ -47,19 +44,29 @@ case s := <-serverC: server = s case s := <-signals: + + // Do not print message when deailing with SIGPIPE, which may cause + // nested signals and consume lots of cpu bandwidth. + if s == unix.SIGPIPE { + continue + } + log.G(ctx).WithField("signal", s).Debug("received signal") switch s { case unix.SIGUSR1: - dumpStacks() - case unix.SIGPIPE: - continue + dumpStacks(true) default: + if err := notifyStopping(ctx); err != nil { + log.G(ctx).WithError(err).Error("notify stopping failed") + } + if server == nil { close(done) return } server.Stop() close(done) + return } } } @@ -67,17 +74,6 @@ return done } -func dumpStacks() { - var ( - buf []byte - stackSize int - ) - bufferLen := 16384 - for stackSize == len(buf) { - buf = make([]byte, bufferLen) - stackSize = runtime.Stack(buf, true) - bufferLen *= 2 - } - buf = buf[:stackSize] - logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) +func isLocalAddress(path string) bool { + return filepath.IsAbs(path) } diff -Nru containerd-1.2.6/cmd/containerd/command/main_windows.go containerd-1.5.9/cmd/containerd/command/main_windows.go --- containerd-1.2.6/cmd/containerd/command/main_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/main_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,18 +18,22 @@ import ( "context" + "fmt" "os" - "path/filepath" + "strings" + "unsafe" + "github.com/Microsoft/go-winio/pkg/etw" + "github.com/Microsoft/go-winio/pkg/etwlogrus" + "github.com/Microsoft/go-winio/pkg/guid" "github.com/containerd/containerd/log" "github.com/containerd/containerd/services/server" - + "github.com/sirupsen/logrus" "golang.org/x/sys/windows" ) var ( - defaultConfigPath = filepath.Join(os.Getenv("programfiles"), "containerd", "config.toml") - handledSignals = []os.Signal{ + handledSignals = []os.Signal{ windows.SIGTERM, windows.SIGINT, } @@ -45,6 +49,11 @@ server = s case s := <-signals: log.G(ctx).WithField("signal", s).Debug("received signal") + + if err := notifyStopping(ctx); err != nil { + log.G(ctx).WithError(err).Error("notify stopping failed") + } + if server == nil { close(done) return @@ -54,5 +63,62 @@ } } }() + setupDumpStacks() return done } + +func setupDumpStacks() { + // Windows does not support signals like *nix systems. So instead of + // trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be + // signaled. ACL'd to builtin administrators and local system + event := "Global\\stackdump-" + fmt.Sprint(os.Getpid()) + ev, _ := windows.UTF16PtrFromString(event) + sd, err := windows.SecurityDescriptorFromString("D:P(A;;GA;;;BA)(A;;GA;;;SY)") + if err != nil { + logrus.Errorf("failed to get security descriptor for debug stackdump event %s: %s", event, err.Error()) + return + } + var sa windows.SecurityAttributes + sa.Length = uint32(unsafe.Sizeof(sa)) + sa.InheritHandle = 1 + sa.SecurityDescriptor = sd + h, err := windows.CreateEvent(&sa, 0, 0, ev) + if h == 0 || err != nil { + logrus.Errorf("failed to create debug stackdump event %s: %s", event, err.Error()) + return + } + go func() { + logrus.Debugf("Stackdump - waiting signal at %s", event) + for { + windows.WaitForSingleObject(h, windows.INFINITE) + dumpStacks(true) + } + }() +} + +func etwCallback(sourceID guid.GUID, state etw.ProviderState, level etw.Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr) { + if state == etw.ProviderStateCaptureState { + dumpStacks(false) + } +} + +func init() { + // Provider ID: 2acb92c0-eb9b-571a-69cf-8f3410f383ad + // Provider and hook aren't closed explicitly, as they will exist until + // process exit. GUID is generated based on name - see + // Microsoft/go-winio/tools/etw-provider-gen. + provider, err := etw.NewProvider("ContainerD", etwCallback) + if err != nil { + logrus.Error(err) + } else { + if hook, err := etwlogrus.NewHookFromProvider(provider); err == nil { + logrus.AddHook(hook) + } else { + logrus.Error(err) + } + } +} + +func isLocalAddress(path string) bool { + return strings.HasPrefix(path, `\\.\pipe\`) +} diff -Nru containerd-1.2.6/cmd/containerd/command/notify_linux.go containerd-1.5.9/cmd/containerd/command/notify_linux.go --- containerd-1.2.6/cmd/containerd/command/notify_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/notify_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import ( + "context" + + sd "github.com/coreos/go-systemd/v22/daemon" + + "github.com/containerd/containerd/log" +) + +// notifyReady notifies systemd that the daemon is ready to serve requests +func notifyReady(ctx context.Context) error { + return sdNotify(ctx, sd.SdNotifyReady) +} + +// notifyStopping notifies systemd that the daemon is about to be stopped +func notifyStopping(ctx context.Context) error { + return sdNotify(ctx, sd.SdNotifyStopping) +} + +func sdNotify(ctx context.Context, state string) error { + notified, err := sd.SdNotify(false, state) + log.G(ctx). + WithError(err). + WithField("notified", notified). + WithField("state", state). + Debug("sd notification") + return err +} diff -Nru containerd-1.2.6/cmd/containerd/command/notify_unsupported.go containerd-1.5.9/cmd/containerd/command/notify_unsupported.go --- containerd-1.2.6/cmd/containerd/command/notify_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/notify_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import ( + "context" +) + +func notifyReady(ctx context.Context) error { + return nil +} + +func notifyStopping(ctx context.Context) error { + return nil +} diff -Nru containerd-1.2.6/cmd/containerd/command/oci-hook.go containerd-1.5.9/cmd/containerd/command/oci-hook.go --- containerd-1.2.6/cmd/containerd/command/oci-hook.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/oci-hook.go 2022-01-05 17:30:58.000000000 +0000 @@ -129,7 +129,7 @@ } func (t *templateContext) status() string { - return t.state.Status + return string(t.state.Status) } func render(ctx *templateContext, source string, out io.Writer) error { diff -Nru containerd-1.2.6/cmd/containerd/command/publish.go containerd-1.5.9/cmd/containerd/command/publish.go --- containerd-1.2.6/cmd/containerd/command/publish.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/publish.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,6 +32,7 @@ "github.com/pkg/errors" "github.com/urfave/cli" "google.golang.org/grpc" + "google.golang.org/grpc/backoff" ) var publishCommand = cli.Command{ @@ -51,7 +52,7 @@ ctx := namespaces.WithNamespace(gocontext.Background(), context.String("namespace")) topic := context.String("topic") if topic == "" { - return errors.New("topic required to publish event") + return errors.Wrap(errdefs.ErrInvalidArgument, "topic required to publish event") } payload, err := getEventPayload(os.Stdin) if err != nil { @@ -84,20 +85,25 @@ } func connectEvents(address string) (eventsapi.EventsClient, error) { - conn, err := connect(address, dialer.Dialer) + conn, err := connect(address, dialer.ContextDialer) if err != nil { return nil, errors.Wrapf(err, "failed to dial %q", address) } return eventsapi.NewEventsClient(conn), nil } -func connect(address string, d func(string, time.Duration) (net.Conn, error)) (*grpc.ClientConn, error) { +func connect(address string, d func(gocontext.Context, string) (net.Conn, error)) (*grpc.ClientConn, error) { + backoffConfig := backoff.DefaultConfig + backoffConfig.MaxDelay = 3 * time.Second + connParams := grpc.ConnectParams{ + Backoff: backoffConfig, + } gopts := []grpc.DialOption{ grpc.WithBlock(), grpc.WithInsecure(), - grpc.WithDialer(d), + grpc.WithContextDialer(d), grpc.FailOnNonTempDialError(true), - grpc.WithBackoffMaxDelay(3 * time.Second), + grpc.WithConnectParams(connParams), } ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 2*time.Second) defer cancel() diff -Nru containerd-1.2.6/cmd/containerd/command/service_unsupported.go containerd-1.5.9/cmd/containerd/command/service_unsupported.go --- containerd-1.2.6/cmd/containerd/command/service_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/service_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import ( + "github.com/containerd/containerd/services/server" + "github.com/urfave/cli" +) + +// serviceFlags returns an array of flags for configuring containerd to run +// as a service. Only relevant on Windows. +func serviceFlags() []cli.Flag { + return nil +} + +// applyPlatformFlags applies platform-specific flags. +func applyPlatformFlags(context *cli.Context) { +} + +// registerUnregisterService is only relevant on Windows. +func registerUnregisterService(root string) (bool, error) { + return false, nil +} + +// launchService is only relevant on Windows. +func launchService(s *server.Server, done chan struct{}) error { + return nil +} diff -Nru containerd-1.2.6/cmd/containerd/command/service_windows.go containerd-1.5.9/cmd/containerd/command/service_windows.go --- containerd-1.2.6/cmd/containerd/command/service_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd/command/service_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,381 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "time" + "unsafe" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/services/server" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/debug" + "golang.org/x/sys/windows/svc/mgr" +) + +var ( + serviceNameFlag string + registerServiceFlag bool + unregisterServiceFlag bool + runServiceFlag bool + logFileFlag string + + kernel32 = windows.NewLazySystemDLL("kernel32.dll") + setStdHandle = kernel32.NewProc("SetStdHandle") + allocConsole = kernel32.NewProc("AllocConsole") + oldStderr windows.Handle + panicFile *os.File +) + +const defaultServiceName = "containerd" + +// serviceFlags returns an array of flags for configuring containerd to run +// as a Windows service under control of SCM. +func serviceFlags() []cli.Flag { + return []cli.Flag{ + cli.StringFlag{ + Name: "service-name", + Usage: "Set the Windows service name", + Value: defaultServiceName, + }, + cli.BoolFlag{ + Name: "register-service", + Usage: "Register the service and exit", + }, + cli.BoolFlag{ + Name: "unregister-service", + Usage: "Unregister the service and exit", + }, + cli.BoolFlag{ + Name: "run-service", + Usage: "", + Hidden: true, + }, + cli.StringFlag{ + Name: "log-file", + Usage: "Path to the containerd log file", + }, + } +} + +// applyPlatformFlags applies platform-specific flags. +func applyPlatformFlags(context *cli.Context) { + serviceNameFlag = context.GlobalString("service-name") + if serviceNameFlag == "" { + serviceNameFlag = defaultServiceName + } + for _, v := range []struct { + name string + d *bool + }{ + { + name: "register-service", + d: ®isterServiceFlag, + }, + { + name: "unregister-service", + d: &unregisterServiceFlag, + }, + { + name: "run-service", + d: &runServiceFlag, + }, + } { + *v.d = context.GlobalBool(v.name) + } + logFileFlag = context.GlobalString("log-file") +} + +type handler struct { + fromsvc chan error + s *server.Server + done chan struct{} // Indicates back to app main to quit +} + +func getServicePath() (string, error) { + p, err := exec.LookPath(os.Args[0]) + if err != nil { + return "", err + } + return filepath.Abs(p) +} + +func registerService() error { + p, err := getServicePath() + if err != nil { + return err + } + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + + c := mgr.Config{ + ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, + StartType: mgr.StartAutomatic, + ErrorControl: mgr.ErrorNormal, + DisplayName: "Containerd", + Description: "Container runtime", + } + + // Configure the service to launch with the arguments that were just passed. + args := []string{"--run-service"} + for _, a := range os.Args[1:] { + if a != "--register-service" && a != "--unregister-service" { + args = append(args, a) + } + } + + s, err := m.CreateService(serviceNameFlag, p, c, args...) + if err != nil { + return err + } + defer s.Close() + + // See http://stackoverflow.com/questions/35151052/how-do-i-configure-failure-actions-of-a-windows-service-written-in-go + const ( + scActionNone = 0 + scActionRestart = 1 + + serviceConfigFailureActions = 2 + ) + + type serviceFailureActions struct { + ResetPeriod uint32 + RebootMsg *uint16 + Command *uint16 + ActionsCount uint32 + Actions uintptr + } + + type scAction struct { + Type uint32 + Delay uint32 + } + t := []scAction{ + {Type: scActionRestart, Delay: uint32(15 * time.Second / time.Millisecond)}, + {Type: scActionRestart, Delay: uint32(15 * time.Second / time.Millisecond)}, + {Type: scActionNone}, + } + lpInfo := serviceFailureActions{ResetPeriod: uint32(24 * time.Hour / time.Second), ActionsCount: uint32(3), Actions: uintptr(unsafe.Pointer(&t[0]))} + err = windows.ChangeServiceConfig2(s.Handle, serviceConfigFailureActions, (*byte)(unsafe.Pointer(&lpInfo))) + if err != nil { + return err + } + + return nil +} + +func unregisterService() error { + m, err := mgr.Connect() + if err != nil { + return err + } + defer m.Disconnect() + + s, err := m.OpenService(serviceNameFlag) + if err != nil { + return err + } + defer s.Close() + + err = s.Delete() + if err != nil { + return err + } + return nil +} + +// registerUnregisterService is an entrypoint early in the daemon startup +// to handle (un-)registering against Windows Service Control Manager (SCM). +// It returns an indication to stop on successful SCM operation, and an error. +func registerUnregisterService(root string) (bool, error) { + + if unregisterServiceFlag { + if registerServiceFlag { + return true, errors.Wrap(errdefs.ErrInvalidArgument, "--register-service and --unregister-service cannot be used together") + } + return true, unregisterService() + } + + if registerServiceFlag { + return true, registerService() + } + + if runServiceFlag { + // Allocate a conhost for containerd here. We don't actually use this + // at all in containerd, but it will be inherited by any processes + // containerd executes, so they won't need to allocate their own + // conhosts. This is important for two reasons: + // - Creating a conhost slows down process launch. + // - We have seen reliability issues when launching many processes. + // Sometimes the process invocation will fail due to an error when + // creating the conhost. + // + // This needs to be done before initializing the panic file, as + // AllocConsole sets the stdio handles to point to the new conhost, + // and we want to make sure stderr goes to the panic file. + r, _, err := allocConsole.Call() + if r == 0 && err != nil { + return true, fmt.Errorf("error allocating conhost: %s", err) + } + + if err := initPanicFile(filepath.Join(root, "panic.log")); err != nil { + return true, err + } + + logOutput := ioutil.Discard + if logFileFlag != "" { + f, err := os.OpenFile(logFileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return true, errors.Wrapf(err, "open log file %q", logFileFlag) + } + logOutput = f + } + logrus.SetOutput(logOutput) + } + return false, nil +} + +// launchService is the entry point for running the daemon under SCM. +func launchService(s *server.Server, done chan struct{}) error { + + if !runServiceFlag { + return nil + } + + h := &handler{ + fromsvc: make(chan error), + s: s, + done: done, + } + + interactive, err := svc.IsAnInteractiveSession() // nolint:staticcheck + if err != nil { + return err + } + + go func() { + if interactive { + err = debug.Run(serviceNameFlag, h) + } else { + err = svc.Run(serviceNameFlag, h) + } + h.fromsvc <- err + }() + + // Wait for the first signal from the service handler. + err = <-h.fromsvc + if err != nil { + return err + } + return nil +} + +func (h *handler) Execute(_ []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (bool, uint32) { + s <- svc.Status{State: svc.StartPending, Accepts: 0} + // Unblock launchService() + h.fromsvc <- nil + + s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)} + +Loop: + for c := range r { + switch c.Cmd { + case svc.Interrogate: + s <- c.CurrentStatus + case svc.Stop, svc.Shutdown: + s <- svc.Status{State: svc.StopPending, Accepts: 0} + h.s.Stop() + break Loop + } + } + + removePanicFile() + close(h.done) + return false, 0 +} + +func initPanicFile(path string) error { + var err error + panicFile, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + return err + } + + st, err := panicFile.Stat() + if err != nil { + return err + } + + // If there are contents in the file already, move the file out of the way + // and replace it. + if st.Size() > 0 { + panicFile.Close() + os.Rename(path, path+".old") + panicFile, err = os.Create(path) + if err != nil { + return err + } + } + + // Update STD_ERROR_HANDLE to point to the panic file so that Go writes to + // it when it panics. Remember the old stderr to restore it before removing + // the panic file. + sh := uint32(windows.STD_ERROR_HANDLE) + h, err := windows.GetStdHandle(sh) + if err != nil { + return err + } + + oldStderr = h + + r, _, err := setStdHandle.Call(uintptr(sh), panicFile.Fd()) + if r == 0 && err != nil { + return err + } + + // Reset os.Stderr to the panic file (so fmt.Fprintf(os.Stderr,...) actually gets redirected) + os.Stderr = os.NewFile(panicFile.Fd(), "/dev/stderr") + + // Force threads that panic to write to stderr (the panicFile handle now), otherwise it will go into the ether + log.SetOutput(os.Stderr) + + return nil +} + +func removePanicFile() { + if st, err := panicFile.Stat(); err == nil { + if st.Size() == 0 { + sh := uint32(windows.STD_ERROR_HANDLE) + setStdHandle.Call(uintptr(sh), uintptr(oldStderr)) + panicFile.Close() + os.Remove(panicFile.Name()) + } + } +} diff -Nru containerd-1.2.6/cmd/containerd-shim/main_unix.go containerd-1.5.9/cmd/containerd-shim/main_unix.go --- containerd-1.2.6/cmd/containerd-shim/main_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim/main_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,6 +23,7 @@ "context" "flag" "fmt" + "io" "net" "os" "os/exec" @@ -36,9 +37,11 @@ "github.com/containerd/containerd/events" "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/runtime/v1/linux/proc" + "github.com/containerd/containerd/pkg/process" + shimlog "github.com/containerd/containerd/runtime/v1" "github.com/containerd/containerd/runtime/v1/shim" shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" + "github.com/containerd/containerd/sys/reaper" "github.com/containerd/ttrpc" "github.com/containerd/typeurl" ptypes "github.com/gogo/protobuf/types" @@ -57,15 +60,21 @@ criuFlag string systemdCgroupFlag bool containerdBinaryFlag string + + bufPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, + } ) func init() { flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs") flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim") - flag.StringVar(&socketFlag, "socket", "", "abstract socket path to serve") + flag.StringVar(&socketFlag, "socket", "", "socket path to serve") flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd") flag.StringVar(&workdirFlag, "workdir", "", "path used to storge large temporary data") - flag.StringVar(&runtimeRootFlag, "runtime-root", proc.RuncRoot, "root directory for the runtime") + flag.StringVar(&runtimeRootFlag, "runtime-root", process.RuncRoot, "root directory for the runtime") flag.StringVar(&criuFlag, "criu", "", "path to criu binary") flag.BoolVar(&systemdCgroupFlag, "systemd-cgroup", false, "set runtime to use systemd-cgroup") // currently, the `containerd publish` utility is embedded in the daemon binary. @@ -92,12 +101,42 @@ runtime.GOMAXPROCS(2) } + stdout, stderr, err := openStdioKeepAlivePipes(workdirFlag) + if err != nil { + fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err) + os.Exit(1) + } + defer func() { + stdout.Close() + stderr.Close() + }() + + // redirect the following output into fifo to make sure that containerd + // still can read the log after restart + logrus.SetOutput(stdout) + if err := executeShim(); err != nil { fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err) os.Exit(1) } } +// If containerd server process dies, we need the shim to keep stdout/err reader +// FDs so that Linux does not SIGPIPE the shim process if it tries to use its end of +// these pipes. +func openStdioKeepAlivePipes(dir string) (io.ReadWriteCloser, io.ReadWriteCloser, error) { + background := context.Background() + keepStdoutAlive, err := shimlog.OpenShimStdoutLog(background, dir) + if err != nil { + return nil, nil, err + } + keepStderrAlive, err := shimlog.OpenShimStderrLog(background, dir) + if err != nil { + return nil, nil, err + } + return keepStdoutAlive, keepStderrAlive, nil +} + func executeShim() error { // start handling signals as soon as possible so that things are properly reaped // or if runtime exits before we hit the handler @@ -158,13 +197,23 @@ err error ) if path == "" { - l, err = net.FileListener(os.NewFile(3, "socket")) + f := os.NewFile(3, "socket") + l, err = net.FileListener(f) + f.Close() path = "[inherited from parent]" } else { - if len(path) > 106 { - return errors.Errorf("%q: unix socket path too long (> 106)", path) + const ( + abstractSocketPrefix = "\x00" + socketPathLimit = 106 + ) + p := strings.TrimPrefix(path, "unix://") + if len(p) == len(path) { + p = abstractSocketPrefix + p + } + if len(p) > socketPathLimit { + return errors.Errorf("%q: unix socket path too long (> %d)", p, socketPathLimit) } - l, err = net.Listen("unix", "\x00"+path) + l, err = net.Listen("unix", p) } if err != nil { return err @@ -193,7 +242,7 @@ case s := <-signals: switch s { case unix.SIGCHLD: - if err := shim.Reap(); err != nil { + if err := reaper.Reap(); err != nil { logger.WithError(err).Error("reap exit status") } case unix.SIGTERM, unix.SIGINT: @@ -247,16 +296,23 @@ } cmd := exec.CommandContext(ctx, containerdBinaryFlag, "--address", l.address, "publish", "--topic", topic, "--namespace", ns) cmd.Stdin = bytes.NewReader(data) - c, err := shim.Default.Start(cmd) + b := bufPool.Get().(*bytes.Buffer) + defer func() { + b.Reset() + bufPool.Put(b) + }() + cmd.Stdout = b + cmd.Stderr = b + c, err := reaper.Default.Start(cmd) if err != nil { return err } - status, err := shim.Default.Wait(cmd, c) + status, err := reaper.Default.Wait(cmd, c) if err != nil { - return err + return errors.Wrapf(err, "failed to publish event: %s", b.String()) } if status != 0 { - return errors.New("failed to publish event") + return errors.Errorf("failed to publish event: %s", b.String()) } return nil } diff -Nru containerd-1.2.6/cmd/containerd-shim/shim_darwin.go containerd-1.5.9/cmd/containerd-shim/shim_darwin.go --- containerd-1.2.6/cmd/containerd-shim/shim_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim/shim_darwin.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,7 +22,7 @@ "os" "os/signal" - "github.com/containerd/containerd/runtime/v1/shim" + "github.com/containerd/containerd/sys/reaper" runc "github.com/containerd/go-runc" "github.com/containerd/ttrpc" ) @@ -34,7 +34,7 @@ signal.Notify(signals) // make sure runc is setup to use the monitor // for waiting on processes - runc.Monitor = shim.Default + runc.Monitor = reaper.Default return signals, nil } diff -Nru containerd-1.2.6/cmd/containerd-shim/shim_freebsd.go containerd-1.5.9/cmd/containerd-shim/shim_freebsd.go --- containerd-1.2.6/cmd/containerd-shim/shim_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim/shim_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "os" + "os/signal" + + "github.com/containerd/containerd/sys/reaper" + + runc "github.com/containerd/go-runc" + "github.com/containerd/ttrpc" +) + +// setupSignals creates a new signal handler for all signals and sets the shim as a +// sub-reaper so that the container processes are reparented +func setupSignals() (chan os.Signal, error) { + signals := make(chan os.Signal, 2048) + signal.Notify(signals) + // make sure runc is setup to use the monitor + // for waiting on processes + runc.Monitor = reaper.Default + return signals, nil +} + +func newServer() (*ttrpc.Server, error) { + // for freebsd, we omit the socket credentials because these syscalls are + // slightly different. since we don't have freebsd support yet, this can be + // implemented later and the build can continue without issue. + return ttrpc.NewServer() +} diff -Nru containerd-1.2.6/cmd/containerd-shim/shim_linux.go containerd-1.5.9/cmd/containerd-shim/shim_linux.go --- containerd-1.2.6/cmd/containerd-shim/shim_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim/shim_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,10 +20,9 @@ "os" "os/signal" - "github.com/containerd/containerd/runtime/v1/shim" + "github.com/containerd/containerd/sys/reaper" runc "github.com/containerd/go-runc" "github.com/containerd/ttrpc" - "github.com/opencontainers/runc/libcontainer/system" "golang.org/x/sys/unix" ) @@ -34,9 +33,9 @@ signal.Notify(signals, unix.SIGTERM, unix.SIGINT, unix.SIGCHLD, unix.SIGPIPE) // make sure runc is setup to use the monitor // for waiting on processes - runc.Monitor = shim.Default + runc.Monitor = reaper.Default // set the shim as the subreaper for all orphaned processes created by the container - if err := system.SetSubreaper(1); err != nil { + if err := reaper.SetSubreaper(1); err != nil { return nil, err } return signals, nil diff -Nru containerd-1.2.6/cmd/containerd-shim/shim_unix.go containerd-1.5.9/cmd/containerd-shim/shim_unix.go --- containerd-1.2.6/cmd/containerd-shim/shim_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim/shim_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -// +build !linux,!windows,!darwin - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import ( - "os" - "os/signal" - - "github.com/containerd/containerd/runtime/v1/shim" - runc "github.com/containerd/go-runc" - "github.com/containerd/ttrpc" -) - -// setupSignals creates a new signal handler for all signals and sets the shim as a -// sub-reaper so that the container processes are reparented -func setupSignals() (chan os.Signal, error) { - signals := make(chan os.Signal, 2048) - signal.Notify(signals) - // make sure runc is setup to use the monitor - // for waiting on processes - runc.Monitor = shim.Default - return signals, nil -} - -func newServer() (*ttrpc.Server, error) { - return ttrpc.NewServer(ttrpc.WithServerHandshaker(ttrpc.UnixSocketRequireSameUser())) -} diff -Nru containerd-1.2.6/cmd/containerd-shim-runc-v1/main.go containerd-1.5.9/cmd/containerd-shim-runc-v1/main.go --- containerd-1.2.6/cmd/containerd-shim-runc-v1/main.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim-runc-v1/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,10 +19,10 @@ package main import ( - "github.com/containerd/containerd/runtime/v2/runc" + v1 "github.com/containerd/containerd/runtime/v2/runc/v1" "github.com/containerd/containerd/runtime/v2/shim" ) func main() { - shim.Run("io.containerd.runc.v1", runc.New) + shim.Run("io.containerd.runc.v1", v1.New) } diff -Nru containerd-1.2.6/cmd/containerd-shim-runc-v2/main.go containerd-1.5.9/cmd/containerd-shim-runc-v2/main.go --- containerd-1.2.6/cmd/containerd-shim-runc-v2/main.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim-runc-v2/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + v2 "github.com/containerd/containerd/runtime/v2/runc/v2" + "github.com/containerd/containerd/runtime/v2/shim" +) + +func main() { + shim.Run("io.containerd.runc.v2", v2.New) +} diff -Nru containerd-1.2.6/cmd/containerd-shim-runhcs-v1/main.go containerd-1.5.9/cmd/containerd-shim-runhcs-v1/main.go --- containerd-1.2.6/cmd/containerd-shim-runhcs-v1/main.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-shim-runhcs-v1/main.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import ( - "github.com/containerd/containerd/runtime/v2/runhcs" - "github.com/containerd/containerd/runtime/v2/shim" -) - -func main() { - shim.Run("io.containerd.runhcs.v1", runhcs.New) -} diff -Nru containerd-1.2.6/cmd/containerd-stress/density.go containerd-1.5.9/cmd/containerd-stress/density.go --- containerd-1.2.6/cmd/containerd-stress/density.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/density.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,7 +31,6 @@ "github.com/containerd/containerd" "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/containers" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" "github.com/sirupsen/logrus" @@ -56,6 +55,7 @@ Exec: cliContext.GlobalBool("exec"), JSON: cliContext.GlobalBool("json"), Metrics: cliContext.GlobalString("metrics"), + Snapshotter: cliContext.GlobalString("snapshotter"), } client, err := config.newClient() if err != nil { @@ -67,7 +67,7 @@ return err } logrus.Infof("pulling %s", imageName) - image, err := client.Pull(ctx, imageName, containerd.WithPullUnpack) + image, err := client.Pull(ctx, imageName, containerd.WithPullUnpack, containerd.WithPullSnapshotter(config.Snapshotter)) if err != nil { return err } @@ -76,11 +76,6 @@ s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGTERM, syscall.SIGINT) - spec, err := oci.GenerateSpec(ctx, client, - &containers.Container{}, - oci.WithImageConfig(image), - oci.WithProcessArgs("sleep", "120m"), - ) if err != nil { return err } @@ -95,11 +90,14 @@ break loop default: id := fmt.Sprintf("density-%d", i) - spec.Linux.CgroupsPath = filepath.Join("/", "density", id) c, err := client.NewContainer(ctx, id, + containerd.WithSnapshotter(config.Snapshotter), containerd.WithNewSnapshot(id, image), - containerd.WithSpec(spec, oci.WithUsername("games")), + containerd.WithNewSpec( + oci.WithImageConfig(image), + oci.WithProcessArgs("sleep", "120m"), + oci.WithUsername("games")), ) if err != nil { return err diff -Nru containerd-1.2.6/cmd/containerd-stress/exec_worker.go containerd-1.5.9/cmd/containerd-stress/exec_worker.go --- containerd-1.2.6/cmd/containerd-stress/exec_worker.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/exec_worker.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "context" + "fmt" "strings" "syscall" "time" @@ -38,8 +39,10 @@ w.wg.Done() logrus.Infof("worker %d finished", w.id) }() - c, err := w.client.NewContainer(ctx, "exec-container", - containerd.WithNewSnapshot("exec-container", w.image), + id := fmt.Sprintf("exec-container-%d", w.id) + c, err := w.client.NewContainer(ctx, id, + containerd.WithNewSnapshot(id, w.image), + containerd.WithSnapshotter(w.snapshotter), containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("sleep", "30d")), ) if err != nil { diff -Nru containerd-1.2.6/cmd/containerd-stress/main.go containerd-1.5.9/cmd/containerd-stress/main.go --- containerd-1.2.6/cmd/containerd-stress/main.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -30,6 +30,7 @@ "github.com/containerd/containerd" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/plugin" metrics "github.com/docker/go-metrics" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -146,7 +147,12 @@ cli.StringFlag{ Name: "runtime", Usage: "set the runtime to stress test", - Value: "io.containerd.runtime.v1.linux", + Value: plugin.RuntimeRuncV2, + }, + cli.StringFlag{ + Name: "snapshotter", + Usage: "set the snapshotter to use", + Value: "overlayfs", }, } app.Before = func(context *cli.Context) error { @@ -170,6 +176,7 @@ JSON: context.GlobalBool("json"), Metrics: context.GlobalString("metrics"), Runtime: context.GlobalString("runtime"), + Snapshotter: context.GlobalString("snapshotter"), } if config.Metrics != "" { return serve(config) @@ -190,6 +197,7 @@ JSON bool Metrics string Runtime string + Snapshotter string } func (c config) newClient() (*containerd.Client, error) { @@ -221,7 +229,7 @@ return err } logrus.Infof("pulling %s", imageName) - image, err := client.Pull(ctx, imageName, containerd.WithPullUnpack) + image, err := client.Pull(ctx, imageName, containerd.WithPullUnpack, containerd.WithPullSnapshotter(c.Snapshotter)) if err != nil { return err } @@ -246,27 +254,31 @@ for i := 0; i < c.Concurrency; i++ { wg.Add(1) w := &worker{ - id: i, - wg: &wg, - image: image, - client: client, - commit: v.Revision, + id: i, + wg: &wg, + image: image, + client: client, + commit: v.Revision, + snapshotter: c.Snapshotter, } workers = append(workers, w) } var exec *execWorker if c.Exec { - wg.Add(1) - exec = &execWorker{ - worker: worker{ - id: c.Concurrency, - wg: &wg, - image: image, - client: client, - commit: v.Revision, - }, + for i := c.Concurrency; i < c.Concurrency+c.Concurrency; i++ { + wg.Add(1) + exec = &execWorker{ + worker: worker{ + id: i, + wg: &wg, + image: image, + client: client, + commit: v.Revision, + snapshotter: c.Snapshotter, + }, + } + go exec.exec(ctx, tctx) } - go exec.exec(ctx, tctx) } // start the timer and run the worker diff -Nru containerd-1.2.6/cmd/containerd-stress/rlimit_freebsd.go containerd-1.5.9/cmd/containerd-stress/rlimit_freebsd.go --- containerd-1.2.6/cmd/containerd-stress/rlimit_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/rlimit_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "syscall" +) + +func setRlimit() error { + rlimit := int64(100000) + if rlimit > 0 { + var limit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return err + } + if limit.Cur < rlimit { + limit.Cur = rlimit + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + return err + } + } + } + return nil +} diff -Nru containerd-1.2.6/cmd/containerd-stress/rlimit_unix.go containerd-1.5.9/cmd/containerd-stress/rlimit_unix.go --- containerd-1.2.6/cmd/containerd-stress/rlimit_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/rlimit_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!freebsd /* Copyright The containerd Authors. @@ -31,6 +31,9 @@ } if limit.Cur < rlimit { limit.Cur = rlimit + if limit.Max < limit.Cur { + limit.Max = limit.Cur + } if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { return err } diff -Nru containerd-1.2.6/cmd/containerd-stress/size.go containerd-1.5.9/cmd/containerd-stress/size.go --- containerd-1.2.6/cmd/containerd-stress/size.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/size.go 2022-01-05 17:30:58.000000000 +0000 @@ -27,6 +27,8 @@ "ctr", "containerd", "containerd-shim", + "containerd-shim-runc-v1", + "containerd-shim-runc-v2", } // checkBinarySizes checks and reports the binary sizes for the containerd compiled binaries to prometheus diff -Nru containerd-1.2.6/cmd/containerd-stress/worker.go containerd-1.5.9/cmd/containerd-stress/worker.go --- containerd-1.2.6/cmd/containerd-stress/worker.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/containerd-stress/worker.go 2022-01-05 17:30:58.000000000 +0000 @@ -35,9 +35,10 @@ count int failures int - client *containerd.Client - image containerd.Image - commit string + client *containerd.Client + image containerd.Image + commit string + snapshotter string } func (w *worker) run(ctx, tctx context.Context) { @@ -74,6 +75,7 @@ func (w *worker) runContainer(ctx context.Context, id string) (err error) { // fix up cgroups path for a default config c, err := w.client.NewContainer(ctx, id, + containerd.WithSnapshotter(w.snapshotter), containerd.WithNewSnapshot(id, w.image), containerd.WithNewSpec(oci.WithImageConfig(w.image), oci.WithUsername("games"), oci.WithProcessArgs("true")), ) diff -Nru containerd-1.2.6/cmd/ctr/app/main.go containerd-1.5.9/cmd/ctr/app/main.go --- containerd-1.2.6/cmd/ctr/app/main.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/app/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -27,6 +27,7 @@ "github.com/containerd/containerd/cmd/ctr/commands/install" "github.com/containerd/containerd/cmd/ctr/commands/leases" namespacesCmd "github.com/containerd/containerd/cmd/ctr/commands/namespaces" + ociCmd "github.com/containerd/containerd/cmd/ctr/commands/oci" "github.com/containerd/containerd/cmd/ctr/commands/plugins" "github.com/containerd/containerd/cmd/ctr/commands/pprof" "github.com/containerd/containerd/cmd/ctr/commands/run" @@ -57,6 +58,11 @@ app := cli.NewApp() app.Name = "ctr" app.Version = version.Version + app.Description = ` +ctr is an unsupported debug and administrative client for interacting +with the containerd daemon. Because it is unsupported, the commands, +options, and operations are not guaranteed to be backward compatible or +stable from release to release of the containerd project.` app.Usage = ` __ _____/ /______ @@ -66,15 +72,17 @@ containerd CLI ` + app.EnableBashCompletion = true app.Flags = []cli.Flag{ cli.BoolFlag{ Name: "debug", Usage: "enable debug output in logs", }, cli.StringFlag{ - Name: "address, a", - Usage: "address for containerd's GRPC server", - Value: defaults.DefaultAddress, + Name: "address, a", + Usage: "address for containerd's GRPC server", + Value: defaults.DefaultAddress, + EnvVar: "CONTAINERD_ADDRESS", }, cli.DurationFlag{ Name: "timeout", @@ -105,6 +113,7 @@ snapshots.Command, tasks.Command, install.Command, + ociCmd.Command, }, extraCmds...) app.Before = func(context *cli.Context) error { if context.GlobalBool("debug") { diff -Nru containerd-1.2.6/cmd/ctr/builtins_cri_linux.go containerd-1.5.9/cmd/ctr/builtins_cri_linux.go --- containerd-1.2.6/cmd/ctr/builtins_cri_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/builtins_cri_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -// +build !no_cri - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import "github.com/containerd/cri/cli" - -func init() { - pluginCmds = append(pluginCmds, cli.Command) -} diff -Nru containerd-1.2.6/cmd/ctr/commands/client.go containerd-1.5.9/cmd/ctr/commands/client.go --- containerd-1.2.6/cmd/ctr/commands/client.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -47,6 +47,8 @@ // NewClient returns a new containerd client func NewClient(context *cli.Context, opts ...containerd.ClientOpt) (*containerd.Client, gocontext.Context, gocontext.CancelFunc, error) { + timeoutOpt := containerd.WithTimeout(context.GlobalDuration("connect-timeout")) + opts = append(opts, timeoutOpt) client, err := containerd.New(context.GlobalString("address"), opts...) if err != nil { return nil, nil, nil, err diff -Nru containerd-1.2.6/cmd/ctr/commands/commands.go containerd-1.5.9/cmd/ctr/commands/commands.go --- containerd-1.2.6/cmd/ctr/commands/commands.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/commands.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,10 +21,9 @@ "fmt" "os" "path/filepath" - "runtime" "strings" - "github.com/containerd/containerd" + "github.com/containerd/containerd/defaults" "github.com/urfave/cli" ) @@ -34,7 +33,6 @@ cli.StringFlag{ Name: "snapshotter", Usage: "snapshotter name. Empty value stands for the default value.", - Value: containerd.DefaultSnapshotter, EnvVar: "CONTAINERD_SNAPSHOTTER", }, } @@ -63,6 +61,31 @@ Name: "refresh", Usage: "refresh token for authorization server", }, + cli.StringFlag{ + Name: "hosts-dir", + // compatible with "/etc/docker/certs.d" + Usage: "Custom hosts configuration directory", + }, + cli.StringFlag{ + Name: "tlscacert", + Usage: "path to TLS root CA", + }, + cli.StringFlag{ + Name: "tlscert", + Usage: "path to TLS client certificate", + }, + cli.StringFlag{ + Name: "tlskey", + Usage: "path to TLS client key", + }, + cli.BoolFlag{ + Name: "http-dump", + Usage: "dump all HTTP request/responses when interacting with container registry", + }, + cli.BoolFlag{ + Name: "http-trace", + Usage: "enable HTTP tracing for registry interactions", + }, } // ContainerFlags are cli flags specifying container options @@ -72,24 +95,24 @@ Usage: "path to the runtime-specific spec config file", }, cli.StringFlag{ - Name: "checkpoint", - Usage: "provide the checkpoint digest to restore the container", - }, - cli.StringFlag{ Name: "cwd", Usage: "specify the working directory of the process", }, cli.StringSliceFlag{ Name: "env", - Usage: "specify additional container environment variables (i.e. FOO=bar)", + Usage: "specify additional container environment variables (e.g. FOO=bar)", + }, + cli.StringFlag{ + Name: "env-file", + Usage: "specify additional container environment variables in a file(e.g. FOO=bar, one per line)", }, cli.StringSliceFlag{ Name: "label", - Usage: "specify additional labels (i.e. foo=bar)", + Usage: "specify additional labels (e.g. foo=bar)", }, cli.StringSliceFlag{ Name: "mount", - Usage: "specify additional container mount (ex: type=bind,src=/tmp,dst=/host,options=rbind:ro)", + Usage: "specify additional container mount (e.g. type=bind,src=/tmp,dst=/host,options=rbind:ro)", }, cli.BoolFlag{ Name: "net-host", @@ -106,7 +129,11 @@ cli.StringFlag{ Name: "runtime", Usage: "runtime name", - Value: fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS), + Value: defaults.DefaultRuntime, + }, + cli.StringFlag{ + Name: "runtime-config-path", + Usage: "optional runtime config path", }, cli.BoolFlag{ Name: "tty,t", @@ -128,6 +155,30 @@ Name: "allow-new-privs", Usage: "turn off OCI spec's NoNewPrivileges feature flag", }, + cli.Uint64Flag{ + Name: "memory-limit", + Usage: "memory limit (in bytes) for the container", + }, + cli.StringSliceFlag{ + Name: "device", + Usage: "file path to a device to add to the container; or a path to a directory tree of devices to add to the container", + }, + cli.BoolFlag{ + Name: "seccomp", + Usage: "enable the default seccomp profile", + }, + cli.StringFlag{ + Name: "seccomp-profile", + Usage: "file path to custom seccomp profile. seccomp must be set to true, before using seccomp-profile", + }, + cli.StringFlag{ + Name: "apparmor-default-profile", + Usage: "enable AppArmor with the default profile with the specified name, e.g. \"cri-containerd.apparmor.d\"", + }, + cli.StringFlag{ + Name: "apparmor-profile", + Usage: "enable AppArmor with an existing custom profile", + }, } ) diff -Nru containerd-1.2.6/cmd/ctr/commands/commands_unix.go containerd-1.5.9/cmd/ctr/commands/commands_unix.go --- containerd-1.2.6/cmd/ctr/commands/commands_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/commands_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,5 +29,12 @@ }, cli.BoolFlag{ Name: "no-pivot", Usage: "disable use of pivot-root (linux only)", + }, cli.Int64Flag{ + Name: "cpu-quota", + Usage: "Limit CPU CFS quota", + Value: -1, + }, cli.Uint64Flag{ + Name: "cpu-period", + Usage: "Limit CPU CFS period", }) } diff -Nru containerd-1.2.6/cmd/ctr/commands/commands_windows.go containerd-1.5.9/cmd/ctr/commands/commands_windows.go --- containerd-1.2.6/cmd/ctr/commands/commands_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/commands_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,30 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +import ( + "github.com/urfave/cli" +) + +func init() { + ContainerFlags = append(ContainerFlags, cli.Uint64Flag{ + Name: "cpu-count", + Usage: "number of CPUs available to the container", + }) +} diff -Nru containerd-1.2.6/cmd/ctr/commands/containers/checkpoint.go containerd-1.5.9/cmd/ctr/commands/containers/checkpoint.go --- containerd-1.2.6/cmd/ctr/commands/containers/checkpoint.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/containers/checkpoint.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,102 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containers + +import ( + "fmt" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var checkpointCommand = cli.Command{ + Name: "checkpoint", + Usage: "checkpoint a container", + ArgsUsage: "CONTAINER REF", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "rw", + Usage: "include the rw layer in the checkpoint", + }, + cli.BoolFlag{ + Name: "image", + Usage: "include the image in the checkpoint", + }, + cli.BoolFlag{ + Name: "task", + Usage: "checkpoint container task", + }, + }, + Action: func(context *cli.Context) error { + id := context.Args().First() + if id == "" { + return errors.New("container id must be provided") + } + ref := context.Args().Get(1) + if ref == "" { + return errors.New("ref must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + opts := []containerd.CheckpointOpts{ + containerd.WithCheckpointRuntime, + } + + if context.Bool("image") { + opts = append(opts, containerd.WithCheckpointImage) + } + if context.Bool("rw") { + opts = append(opts, containerd.WithCheckpointRW) + } + if context.Bool("task") { + opts = append(opts, containerd.WithCheckpointTask) + } + container, err := client.LoadContainer(ctx, id) + if err != nil { + return err + } + task, err := container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return err + } + } + // pause if running + if task != nil { + if err := task.Pause(ctx); err != nil { + return err + } + defer func() { + if err := task.Resume(ctx); err != nil { + fmt.Println(errors.Wrap(err, "error resuming task")) + } + }() + } + + if _, err := container.Checkpoint(ctx, ref, opts...); err != nil { + return err + } + + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/containers/containers.go containerd-1.5.9/cmd/ctr/commands/containers/containers.go --- containerd-1.2.6/cmd/ctr/commands/containers/containers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/containers/containers.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,7 +18,6 @@ import ( "context" - "errors" "fmt" "os" "strings" @@ -29,8 +28,10 @@ "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/cmd/ctr/commands/run" "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/typeurl" + "github.com/pkg/errors" "github.com/urfave/cli" ) @@ -45,13 +46,15 @@ infoCommand, listCommand, setLabelsCommand, + checkpointCommand, + restoreCommand, }, } var createCommand = cli.Command{ Name: "create", Usage: "create container", - ArgsUsage: "[flags] Image|RootFS CONTAINER", + ArgsUsage: "[flags] Image|RootFS CONTAINER [COMMAND] [ARG...]", Flags: append(commands.SnapshotterFlags, commands.ContainerFlags...), Action: func(context *cli.Context) error { var ( @@ -63,17 +66,17 @@ if config { id = context.Args().First() if context.NArg() > 1 { - return errors.New("with spec config file, only container id should be provided") + return errors.Wrap(errdefs.ErrInvalidArgument, "with spec config file, only container id should be provided") } } else { id = context.Args().Get(1) ref = context.Args().First() if ref == "" { - return errors.New("image ref must be provided") + return errors.Wrap(errdefs.ErrInvalidArgument, "image ref must be provided") } } if id == "" { - return errors.New("container id must be provided") + return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided") } client, ctx, cancel, err := commands.NewClient(context) if err != nil { @@ -122,7 +125,7 @@ w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\t") for _, c := range containers { - info, err := c.Info(ctx) + info, err := c.Info(ctx, containerd.WithoutRefreshedMetadata) if err != nil { return err } @@ -166,7 +169,7 @@ } if context.NArg() == 0 { - return errors.New("must specify at least one container to delete") + return errors.Wrap(errdefs.ErrInvalidArgument, "must specify at least one container to delete") } for _, arg := range context.Args() { if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil { @@ -212,7 +215,7 @@ Action: func(context *cli.Context) error { containerID, labels := commands.ObjectWithLabelArgs(context) if containerID == "" { - return errors.New("container id must be provided") + return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided") } client, ctx, cancel, err := commands.NewClient(context) if err != nil { @@ -245,10 +248,16 @@ Name: "info", Usage: "get info about a container", ArgsUsage: "CONTAINER", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "spec", + Usage: "only display the spec", + }, + }, Action: func(context *cli.Context) error { id := context.Args().First() if id == "" { - return errors.New("container id must be provided") + return errors.Wrap(errdefs.ErrInvalidArgument, "container id must be provided") } client, ctx, cancel, err := commands.NewClient(context) if err != nil { @@ -259,10 +268,18 @@ if err != nil { return err } - info, err := container.Info(ctx) + info, err := container.Info(ctx, containerd.WithoutRefreshedMetadata) if err != nil { return err } + if context.Bool("spec") { + v, err := typeurl.UnmarshalAny(info.Spec) + if err != nil { + return err + } + commands.PrintAsJSON(v) + return nil + } if info.Spec != nil && info.Spec.Value != nil { v, err := typeurl.UnmarshalAny(info.Spec) diff -Nru containerd-1.2.6/cmd/ctr/commands/containers/restore.go containerd-1.5.9/cmd/ctr/commands/containers/restore.go --- containerd-1.2.6/cmd/ctr/commands/containers/restore.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/containers/restore.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,96 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containers + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var restoreCommand = cli.Command{ + Name: "restore", + Usage: "restore a container from checkpoint", + ArgsUsage: "CONTAINER REF", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "rw", + Usage: "restore the rw layer from the checkpoint", + }, + cli.BoolFlag{ + Name: "live", + Usage: "restore the runtime and memory data from the checkpoint", + }, + }, + Action: func(context *cli.Context) error { + id := context.Args().First() + if id == "" { + return errors.New("container id must be provided") + } + ref := context.Args().Get(1) + if ref == "" { + return errors.New("ref must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + checkpoint, err := client.GetImage(ctx, ref) + if err != nil { + if !errdefs.IsNotFound(err) { + return err + } + // TODO (ehazlett): consider other options (always/never fetch) + ck, err := client.Fetch(ctx, ref) + if err != nil { + return err + } + checkpoint = containerd.NewImage(client, ck) + } + + opts := []containerd.RestoreOpts{ + containerd.WithRestoreImage, + containerd.WithRestoreSpec, + containerd.WithRestoreRuntime, + } + if context.Bool("rw") { + opts = append(opts, containerd.WithRestoreRW) + } + + ctr, err := client.Restore(ctx, id, checkpoint, opts...) + if err != nil { + return err + } + + topts := []containerd.NewTaskOpts{} + if context.Bool("live") { + topts = append(topts, containerd.WithTaskCheckpoint(checkpoint)) + } + + task, err := ctr.NewTask(ctx, cio.NewCreator(cio.WithStdio), topts...) + if err != nil { + return err + } + + return task.Start(ctx) + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/content/content.go containerd-1.5.9/cmd/ctr/commands/content/content.go --- containerd-1.2.6/cmd/ctr/commands/content/content.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/content/content.go 2022-01-05 17:30:58.000000000 +0000 @@ -53,6 +53,7 @@ listCommand, pushObjectCommand, setLabelsCommand, + pruneCommand, }, } @@ -78,7 +79,9 @@ } defer ra.Close() - _, err = io.Copy(os.Stdout, content.NewReader(ra)) + // use 1MB buffer like we do for ingesting + buf := make([]byte, 1<<20) + _, err = io.CopyBuffer(os.Stdout, content.NewReader(ra), buf) return err }, } @@ -290,6 +293,11 @@ Name: "validate", Usage: "validate the result against a format (json, mediatype, etc.)", }, + cli.StringFlag{ + Name: "editor", + Usage: "select editor (vim, emacs, etc.)", + EnvVar: "EDITOR", + }, }, Action: func(context *cli.Context) error { var ( @@ -320,7 +328,7 @@ } defer ra.Close() - nrc, err := edit(content.NewReader(ra)) + nrc, err := edit(context, content.NewReader(ra)) if err != nil { return err } @@ -505,7 +513,12 @@ } ) -func edit(rd io.Reader) (io.ReadCloser, error) { +func edit(context *cli.Context, rd io.Reader) (io.ReadCloser, error) { + editor := context.String("editor") + if editor == "" { + return nil, fmt.Errorf("editor is required") + } + tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-") if err != nil { return nil, err @@ -516,7 +529,7 @@ return nil, err } - cmd := exec.Command("sh", "-c", "$EDITOR "+tmp.Name()) + cmd := exec.Command("sh", "-c", fmt.Sprintf("%s %s", editor, tmp.Name())) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff -Nru containerd-1.2.6/cmd/ctr/commands/content/fetch.go containerd-1.5.9/cmd/ctr/commands/content/fetch.go --- containerd-1.2.6/cmd/ctr/commands/content/fetch.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/content/fetch.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ "context" "fmt" "io" + "net/http/httptrace" "os" "sync" "text/tabwriter" @@ -34,7 +35,7 @@ "github.com/containerd/containerd/pkg/progress" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" - digest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli" ) @@ -66,6 +67,14 @@ Name: "all-platforms", Usage: "pull content from all platforms", }, + cli.BoolFlag{ + Name: "all-metadata", + Usage: "Pull metadata for all platforms", + }, + cli.BoolFlag{ + Name: "metadata-only", + Usage: "Pull all metadata including manifests and configs", + }, ), Action: func(clicontext *cli.Context) error { var ( @@ -80,6 +89,7 @@ if err != nil { return err } + _, err = Fetch(ctx, client, ref, config) return err }, @@ -93,8 +103,16 @@ ProgressOutput io.Writer // Labels to set on the content Labels []string + // PlatformMatcher matches platforms, supersedes Platforms + PlatformMatcher platforms.MatchComparer // Platforms to fetch Platforms []string + // Whether or not download all metadata + AllMetadata bool + // RemoteOpts to configure object resolutions and transfers with remote content providers + RemoteOpts []containerd.RemoteOpt + // TraceHTTP writes DNS and connection information to the log when dealing with a container registry + TraceHTTP bool } // NewFetchConfig returns the default FetchConfig from cli flags @@ -104,8 +122,9 @@ return nil, err } config := &FetchConfig{ - Resolver: resolver, - Labels: clicontext.StringSlice("label"), + Resolver: resolver, + Labels: clicontext.StringSlice("label"), + TraceHTTP: clicontext.Bool("http-trace"), } if !clicontext.GlobalBool("debug") { config.ProgressOutput = os.Stdout @@ -117,12 +136,35 @@ } config.Platforms = p } + + if clicontext.Bool("metadata-only") { + config.AllMetadata = true + // Any with an empty set is None + config.PlatformMatcher = platforms.Any() + } else if clicontext.Bool("all-metadata") { + config.AllMetadata = true + } + + if clicontext.IsSet("max-concurrent-downloads") { + mcd := clicontext.Int("max-concurrent-downloads") + config.RemoteOpts = append(config.RemoteOpts, containerd.WithMaxConcurrentDownloads(mcd)) + } + + if clicontext.IsSet("max-concurrent-uploaded-layers") { + mcu := clicontext.Int("max-concurrent-uploaded-layers") + config.RemoteOpts = append(config.RemoteOpts, containerd.WithMaxConcurrentUploadedLayers(mcu)) + } + return config, nil } // Fetch loads all resources into the content store and returns the image func Fetch(ctx context.Context, client *containerd.Client, ref string, config *FetchConfig) (images.Image, error) { - ongoing := newJobs(ref) + ongoing := NewJobs(ref) + + if config.TraceHTTP { + ctx = httptrace.WithClientTrace(ctx, commands.NewDebugClientTrace(ctx)) + } pctx, stopProgress := context.WithCancel(ctx) progress := make(chan struct{}) @@ -130,14 +172,14 @@ go func() { if config.ProgressOutput != nil { // no progress bar, because it hides some debug logs - showProgress(pctx, ongoing, client.ContentStore(), config.ProgressOutput) + ShowProgress(pctx, ongoing, client.ContentStore(), config.ProgressOutput) } close(progress) }() h := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { if desc.MediaType != images.MediaTypeDockerSchema1Manifest { - ongoing.add(desc) + ongoing.Add(desc) } return nil, nil }) @@ -150,9 +192,20 @@ containerd.WithImageHandler(h), containerd.WithSchema1Conversion, } - for _, platform := range config.Platforms { - opts = append(opts, containerd.WithPlatform(platform)) + opts = append(opts, config.RemoteOpts...) + + if config.AllMetadata { + opts = append(opts, containerd.WithAllMetadata()) } + + if config.PlatformMatcher != nil { + opts = append(opts, containerd.WithPlatformMatcher(config.PlatformMatcher)) + } else { + for _, platform := range config.Platforms { + opts = append(opts, containerd.WithPlatform(platform)) + } + } + img, err := client.Fetch(pctx, ref, opts...) stopProgress() if err != nil { @@ -163,7 +216,9 @@ return img, nil } -func showProgress(ctx context.Context, ongoing *jobs, cs content.Store, out io.Writer) { +// ShowProgress continuously updates the output with job progress +// by checking status in the content store. +func ShowProgress(ctx context.Context, ongoing *Jobs, cs content.Store, out io.Writer) { var ( ticker = time.NewTicker(100 * time.Millisecond) fw = progress.NewWriter(out) @@ -182,7 +237,7 @@ tw := tabwriter.NewWriter(fw, 1, 8, 1, ' ', 0) resolved := "resolved" - if !ongoing.isResolved() { + if !ongoing.IsResolved() { resolved = "resolving" } statuses[ongoing.name] = StatusInfo{ @@ -213,7 +268,7 @@ } // now, update the items in jobs that are not in active - for _, j := range ongoing.jobs() { + for _, j := range ongoing.Jobs() { key := remotes.MakeRefKey(ctx, j) keys = append(keys, key) if _, ok := activeSeen[key]; ok { @@ -280,12 +335,12 @@ } } -// jobs provides a way of identifying the download keys for a particular task +// Jobs provides a way of identifying the download keys for a particular task // encountering during the pull walk. // // This is very minimal and will probably be replaced with something more // featured. -type jobs struct { +type Jobs struct { name string added map[digest.Digest]struct{} descs []ocispec.Descriptor @@ -293,14 +348,16 @@ resolved bool } -func newJobs(name string) *jobs { - return &jobs{ +// NewJobs creates a new instance of the job status tracker +func NewJobs(name string) *Jobs { + return &Jobs{ name: name, added: map[digest.Digest]struct{}{}, } } -func (j *jobs) add(desc ocispec.Descriptor) { +// Add adds a descriptor to be tracked +func (j *Jobs) Add(desc ocispec.Descriptor) { j.mu.Lock() defer j.mu.Unlock() j.resolved = true @@ -312,7 +369,8 @@ j.added[desc.Digest] = struct{}{} } -func (j *jobs) jobs() []ocispec.Descriptor { +// Jobs returns a list of all tracked descriptors +func (j *Jobs) Jobs() []ocispec.Descriptor { j.mu.Lock() defer j.mu.Unlock() @@ -320,7 +378,8 @@ return append(descs, j.descs...) } -func (j *jobs) isResolved() bool { +// IsResolved checks whether a descriptor has been resolved +func (j *Jobs) IsResolved() bool { j.mu.Lock() defer j.mu.Unlock() return j.resolved diff -Nru containerd-1.2.6/cmd/ctr/commands/content/prune.go containerd-1.5.9/cmd/ctr/commands/content/prune.go --- containerd-1.2.6/cmd/ctr/commands/content/prune.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/content/prune.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,139 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package content + +import ( + "strings" + "time" + "unicode" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/log" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +const ( + layerPrefix = "containerd.io/gc.ref.content.l." + contentPrefix = "containerd.io/gc.ref.content." +) + +var pruneFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "async", + Usage: "allow garbage collection to cleanup asynchronously", + }, + cli.BoolFlag{ + Name: "dry", + Usage: "just show updates without applying (enables debug logging)", + }, +} + +var pruneCommand = cli.Command{ + Name: "prune", + Usage: "prunes content from the content store", + Subcommands: cli.Commands{ + pruneReferencesCommand, + }, +} + +var pruneReferencesCommand = cli.Command{ + Name: "references", + Usage: "prunes preference labels from the content store (layers only by default)", + Flags: pruneFlags, + Action: func(clicontext *cli.Context) error { + client, ctx, cancel, err := commands.NewClient(clicontext) + if err != nil { + return err + } + defer cancel() + + dryRun := clicontext.Bool("dry") + if dryRun { + log.G(ctx).Logger.SetLevel(logrus.DebugLevel) + log.G(ctx).Debug("dry run, no changes will be applied") + } + + var deleteOpts []leases.DeleteOpt + if !clicontext.Bool("async") { + deleteOpts = append(deleteOpts, leases.SynchronousDelete) + } + + cs := client.ContentStore() + if err := cs.Walk(ctx, func(info content.Info) error { + var fields []string + + for k := range info.Labels { + if isLayerLabel(k) { + log.G(ctx).WithFields(logrus.Fields{ + "digest": info.Digest, + "label": k, + }).Debug("Removing label") + if dryRun { + continue + } + fields = append(fields, "labels."+k) + delete(info.Labels, k) + } + } + + if len(fields) == 0 { + return nil + } + + _, err := cs.Update(ctx, info, fields...) + return err + }); err != nil { + return err + } + + ls := client.LeasesService() + l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(time.Hour)) + if err != nil { + return err + } + return ls.Delete(ctx, l, deleteOpts...) + }, +} + +func isLayerLabel(key string) bool { + if strings.HasPrefix(key, layerPrefix) { + return true + } + if !strings.HasPrefix(key, contentPrefix) { + return false + } + + // handle legacy labels which used content prefix and index (0 always for config) + key = key[len(contentPrefix):] + if isInteger(key) && key != "0" { + return true + } + + return false +} + +func isInteger(key string) bool { + for _, r := range key { + if !unicode.IsDigit(r) { + return false + } + } + return true +} diff -Nru containerd-1.2.6/cmd/ctr/commands/events/events.go containerd-1.5.9/cmd/ctr/commands/events/events.go --- containerd-1.2.6/cmd/ctr/commands/events/events.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/events/events.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,6 +22,7 @@ "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/events" + "github.com/containerd/containerd/log" "github.com/containerd/typeurl" "github.com/urfave/cli" @@ -42,12 +43,11 @@ defer cancel() eventsClient := client.EventService() eventsCh, errCh := eventsClient.Subscribe(ctx, context.Args()...) - open := true - for open { + for { var e *events.Envelope select { case e = <-eventsCh: - case err, open = <-errCh: + case err = <-errCh: return err } if e != nil { @@ -55,11 +55,13 @@ if e.Event != nil { v, err := typeurl.UnmarshalAny(e.Event) if err != nil { - return err + log.G(ctx).WithError(err).Warn("cannot unmarshal an event from Any") + continue } out, err = json.Marshal(v) if err != nil { - return err + log.G(ctx).WithError(err).Warn("cannot marshal Any into JSON") + continue } } if _, err := fmt.Println( @@ -72,6 +74,5 @@ } } } - return nil }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/images/convert.go containerd-1.5.9/cmd/ctr/commands/images/convert.go --- containerd-1.2.6/cmd/ctr/commands/images/convert.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/convert.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,108 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "fmt" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/images/converter" + "github.com/containerd/containerd/images/converter/uncompress" + "github.com/containerd/containerd/platforms" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var convertCommand = cli.Command{ + Name: "convert", + Usage: "convert an image", + ArgsUsage: "[flags] ", + Description: `Convert an image format. + +e.g., 'ctr convert --uncompress --oci example.com/foo:orig example.com/foo:converted' + +Use '--platform' to define the output platform. +When '--all-platforms' is given all images in a manifest list must be available. +`, + Flags: []cli.Flag{ + // generic flags + cli.BoolFlag{ + Name: "uncompress", + Usage: "convert tar.gz layers to uncompressed tar layers", + }, + cli.BoolFlag{ + Name: "oci", + Usage: "convert Docker media types to OCI media types", + }, + // platform flags + cli.StringSliceFlag{ + Name: "platform", + Usage: "Pull content from a specific platform", + Value: &cli.StringSlice{}, + }, + cli.BoolFlag{ + Name: "all-platforms", + Usage: "exports content from all platforms", + }, + }, + Action: func(context *cli.Context) error { + var convertOpts []converter.Opt + srcRef := context.Args().Get(0) + targetRef := context.Args().Get(1) + if srcRef == "" || targetRef == "" { + return errors.New("src and target image need to be specified") + } + + if !context.Bool("all-platforms") { + if pss := context.StringSlice("platform"); len(pss) > 0 { + var all []ocispec.Platform + for _, ps := range pss { + p, err := platforms.Parse(ps) + if err != nil { + return errors.Wrapf(err, "invalid platform %q", ps) + } + all = append(all, p) + } + convertOpts = append(convertOpts, converter.WithPlatform(platforms.Ordered(all...))) + } else { + convertOpts = append(convertOpts, converter.WithPlatform(platforms.DefaultStrict())) + } + } + + if context.Bool("uncompress") { + convertOpts = append(convertOpts, converter.WithLayerConvertFunc(uncompress.LayerConvertFunc)) + } + + if context.Bool("oci") { + convertOpts = append(convertOpts, converter.WithDockerToOCI(true)) + } + + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + newImg, err := converter.Convert(ctx, client, targetRef, srcRef, convertOpts...) + if err != nil { + return err + } + fmt.Fprintln(context.App.Writer, newImg.Target.Digest.String()) + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/images/export.go containerd-1.5.9/cmd/ctr/commands/images/export.go --- containerd-1.2.6/cmd/ctr/commands/images/export.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/export.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,9 +21,8 @@ "os" "github.com/containerd/containerd/cmd/ctr/commands" - oci "github.com/containerd/containerd/images/oci" - "github.com/containerd/containerd/reference" - digest "github.com/opencontainers/go-digest" + "github.com/containerd/containerd/images/archive" + "github.com/containerd/containerd/platforms" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/urfave/cli" @@ -31,95 +30,92 @@ var exportCommand = cli.Command{ Name: "export", - Usage: "export an image", - ArgsUsage: "[flags] ", - Description: `Export an image to a tar stream. -Currently, only OCI format is supported. + Usage: "export images", + ArgsUsage: "[flags] ...", + Description: `Export images to an OCI tar archive. + +Tar output is formatted as an OCI archive, a Docker manifest is provided for the platform. +Use '--skip-manifest-json' to avoid including the Docker manifest.json file. +Use '--platform' to define the output platform. +When '--all-platforms' is given all images in a manifest list must be available. `, Flags: []cli.Flag{ - // TODO(AkihiroSuda): make this map[string]string as in moby/moby#33355? - cli.StringFlag{ - Name: "oci-ref-name", - Value: "", - Usage: "override org.opencontainers.image.ref.name annotation", + cli.BoolFlag{ + Name: "skip-manifest-json", + Usage: "do not add Docker compatible manifest.json to archive", + }, + cli.BoolFlag{ + Name: "skip-non-distributable", + Usage: "do not add non-distributable blobs such as Windows layers to archive", }, - cli.StringFlag{ - Name: "manifest", - Usage: "digest of manifest", + cli.StringSliceFlag{ + Name: "platform", + Usage: "Pull content from a specific platform", + Value: &cli.StringSlice{}, }, - cli.StringFlag{ - Name: "manifest-type", - Usage: "media type of manifest digest", - Value: ocispec.MediaTypeImageManifest, + cli.BoolFlag{ + Name: "all-platforms", + Usage: "exports content from all platforms", }, }, Action: func(context *cli.Context) error { var ( - out = context.Args().First() - local = context.Args().Get(1) - desc ocispec.Descriptor + out = context.Args().First() + images = context.Args().Tail() + exportOpts = []archive.ExportOpt{} ) - if out == "" || local == "" { + if out == "" || len(images) == 0 { return errors.New("please provide both an output filename and an image reference to export") } + + if pss := context.StringSlice("platform"); len(pss) > 0 { + var all []ocispec.Platform + for _, ps := range pss { + p, err := platforms.Parse(ps) + if err != nil { + return errors.Wrapf(err, "invalid platform %q", ps) + } + all = append(all, p) + } + exportOpts = append(exportOpts, archive.WithPlatform(platforms.Ordered(all...))) + } else { + exportOpts = append(exportOpts, archive.WithPlatform(platforms.Default())) + } + + if context.Bool("all-platforms") { + exportOpts = append(exportOpts, archive.WithAllPlatforms()) + } + + if context.Bool("skip-manifest-json") { + exportOpts = append(exportOpts, archive.WithSkipDockerManifest()) + } + + if context.Bool("skip-non-distributable") { + exportOpts = append(exportOpts, archive.WithSkipNonDistributableBlobs()) + } + client, ctx, cancel, err := commands.NewClient(context) if err != nil { return err } defer cancel() - if manifest := context.String("manifest"); manifest != "" { - desc.Digest, err = digest.Parse(manifest) - if err != nil { - return errors.Wrap(err, "invalid manifest digest") - } - desc.MediaType = context.String("manifest-type") - } else { - img, err := client.ImageService().Get(ctx, local) - if err != nil { - return errors.Wrap(err, "unable to resolve image to manifest") - } - desc = img.Target - } - if desc.Annotations == nil { - desc.Annotations = make(map[string]string) - } - if s, ok := desc.Annotations[ocispec.AnnotationRefName]; !ok || s == "" { - if ociRefName := determineOCIRefName(local); ociRefName != "" { - desc.Annotations[ocispec.AnnotationRefName] = ociRefName - } - if ociRefName := context.String("oci-ref-name"); ociRefName != "" { - desc.Annotations[ocispec.AnnotationRefName] = ociRefName - } + is := client.ImageService() + for _, img := range images { + exportOpts = append(exportOpts, archive.WithImage(is, img)) } + var w io.WriteCloser if out == "-" { w = os.Stdout } else { w, err = os.Create(out) if err != nil { - return nil + return err } } - r, err := client.Export(ctx, &oci.V1Exporter{}, desc) - if err != nil { - return err - } - if _, err := io.Copy(w, r); err != nil { - return err - } - if err := w.Close(); err != nil { - return err - } - return r.Close() - }, -} + defer w.Close() -func determineOCIRefName(local string) string { - refspec, err := reference.Parse(local) - if err != nil { - return "" - } - tag, _ := reference.SplitObject(refspec.Object) - return tag + return client.Export(ctx, w, exportOpts...) + }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/images/images.go containerd-1.5.9/cmd/ctr/commands/images/images.go --- containerd-1.2.6/cmd/ctr/commands/images/images.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/images.go 2022-01-05 17:30:58.000000000 +0000 @@ -43,10 +43,14 @@ exportCommand, importCommand, listCommand, + mountCommand, + unmountCommand, pullCommand, pushCommand, removeCommand, + tagCommand, setLabelsCommand, + convertCommand, }, } @@ -54,7 +58,7 @@ Name: "list", Aliases: []string{"ls"}, Usage: "list images known to containerd", - ArgsUsage: "[flags] ", + ArgsUsage: "[flags] [, ...]", Description: "list images registered with containerd", Flags: []cli.Flag{ cli.BoolFlag{ @@ -195,30 +199,42 @@ var checkCommand = cli.Command{ Name: "check", - Usage: "check that an image has all content available locally", - ArgsUsage: "[flags] [, ...]", - Description: "check that an image has all content available locally", - Flags: commands.SnapshotterFlags, + Usage: "check existing images to ensure all content is available locally", + ArgsUsage: "[flags] [, ...]", + Description: "check existing images to ensure all content is available locally", + Flags: append([]cli.Flag{ + cli.BoolFlag{ + Name: "quiet, q", + Usage: "print only the ready image refs (fully downloaded and unpacked)", + }, + }, commands.SnapshotterFlags...), Action: func(context *cli.Context) error { var ( exitErr error + quiet = context.Bool("quiet") ) client, ctx, cancel, err := commands.NewClient(context) if err != nil { return err } defer cancel() - var ( - contentStore = client.ContentStore() - tw = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0) - ) - fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSTATUS\tSIZE\tUNPACKED\t") + + var contentStore = client.ContentStore() args := []string(context.Args()) imageList, err := client.ListImages(ctx, args...) if err != nil { return errors.Wrap(err, "failed listing images") } + if len(imageList) == 0 { + log.G(ctx).Debugf("no images found") + return exitErr + } + + var tw = tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0) + if !quiet { + fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSTATUS\tSIZE\tUNPACKED\t") + } for _, image := range imageList { var ( @@ -226,6 +242,7 @@ size string requiredSize int64 presentSize int64 + complete bool = true ) available, required, present, missing, err := images.Check(ctx, contentStore, image.Target(), platforms.Default()) @@ -235,6 +252,7 @@ } log.G(ctx).WithError(err).Errorf("unable to check %v", image.Name()) status = "error" + complete = false } if status != "error" { @@ -248,6 +266,7 @@ if len(missing) > 0 { status = "incomplete" + complete = false } if available { @@ -256,6 +275,7 @@ } else { status = fmt.Sprintf("unavailable (%v/?)", len(present)) size = fmt.Sprintf("%v/?", progress.Bytes(presentSize)) + complete = false } } else { size = "-" @@ -269,16 +289,23 @@ log.G(ctx).WithError(err).Errorf("unable to check unpack for %v", image.Name()) } - fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t%v\t%t\n", - image.Name(), - image.Target().MediaType, - image.Target().Digest, - status, - size, - unpacked) + if !quiet { + fmt.Fprintf(tw, "%v\t%v\t%v\t%v\t%v\t%t\n", + image.Name(), + image.Target().MediaType, + image.Target().Digest, + status, + size, + unpacked) + } else { + if complete { + fmt.Println(image.Name()) + } + } + } + if !quiet { + tw.Flush() } - tw.Flush() - return exitErr }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/images/import.go containerd-1.5.9/cmd/ctr/commands/images/import.go --- containerd-1.2.6/cmd/ctr/commands/images/import.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/import.go 2022-01-05 17:30:58.000000000 +0000 @@ -64,6 +64,18 @@ Name: "index-name", Usage: "image name to keep index as, by default index is discarded", }, + cli.BoolFlag{ + Name: "all-platforms", + Usage: "imports content for all platforms, false by default", + }, + cli.BoolFlag{ + Name: "no-unpack", + Usage: "skip unpacking the images, false by default", + }, + cli.BoolFlag{ + Name: "compress-blobs", + Usage: "compress uncompressed blobs when creating manifest (Docker format only)", + }, }, commands.SnapshotterFlags...), Action: func(context *cli.Context) error { @@ -89,6 +101,12 @@ opts = append(opts, containerd.WithIndexName(idxName)) } + if context.Bool("compress-blobs") { + opts = append(opts, containerd.WithImportCompression()) + } + + opts = append(opts, containerd.WithAllPlatforms(context.Bool("all-platforms"))) + client, ctx, cancel, err := commands.NewClient(context) if err != nil { return err @@ -113,19 +131,21 @@ return closeErr } - log.G(ctx).Debugf("unpacking %d images", len(imgs)) + if !context.Bool("no-unpack") { + log.G(ctx).Debugf("unpacking %d images", len(imgs)) - for _, img := range imgs { - // TODO: Allow configuration of the platform - image := containerd.NewImage(client, img) - - // TODO: Show unpack status - fmt.Printf("unpacking %s (%s)...", img.Name, img.Target.Digest) - err = image.Unpack(ctx, context.String("snapshotter")) - if err != nil { - return err + for _, img := range imgs { + // TODO: Allow configuration of the platform + image := containerd.NewImage(client, img) + + // TODO: Show unpack status + fmt.Printf("unpacking %s (%s)...", img.Name, img.Target.Digest) + err = image.Unpack(ctx, context.String("snapshotter")) + if err != nil { + return err + } + fmt.Println("done") } - fmt.Println("done") } return nil }, diff -Nru containerd-1.2.6/cmd/ctr/commands/images/mount.go containerd-1.5.9/cmd/ctr/commands/images/mount.go --- containerd-1.2.6/cmd/ctr/commands/images/mount.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/mount.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,143 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "fmt" + "time" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/platforms" + "github.com/opencontainers/image-spec/identity" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var mountCommand = cli.Command{ + Name: "mount", + Usage: "mount an image to a target path", + ArgsUsage: "[flags] ", + Description: `Mount an image rootfs to a specified path. + +When you are done, use the unmount command. +`, + Flags: append(append(commands.RegistryFlags, append(commands.SnapshotterFlags, commands.LabelFlag)...), + cli.BoolFlag{ + Name: "rw", + Usage: "Enable write support on the mount", + }, + cli.StringFlag{ + Name: "platform", + Usage: "Mount the image for the specified platform", + Value: platforms.DefaultString(), + }, + ), + Action: func(context *cli.Context) (retErr error) { + var ( + ref = context.Args().First() + target = context.Args().Get(1) + ) + if ref == "" { + return fmt.Errorf("please provide an image reference to mount") + } + if target == "" { + return fmt.Errorf("please provide a target path to mount to") + } + + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + snapshotter := context.GlobalString("snapshotter") + if snapshotter == "" { + snapshotter = containerd.DefaultSnapshotter + } + + ctx, done, err := client.WithLease(ctx, + leases.WithID(target), + leases.WithExpiration(24*time.Hour), + leases.WithLabels(map[string]string{ + "containerd.io/gc.ref.snapshot." + snapshotter: target, + }), + ) + if err != nil && !errdefs.IsAlreadyExists(err) { + return err + } + + defer func() { + if retErr != nil && done != nil { + done(ctx) + } + }() + + ps := context.String("platform") + p, err := platforms.Parse(ps) + if err != nil { + return errors.Wrapf(err, "unable to parse platform %s", ps) + } + + img, err := client.ImageService().Get(ctx, ref) + if err != nil { + return err + } + + i := containerd.NewImageWithPlatform(client, img, platforms.Only(p)) + if err := i.Unpack(ctx, snapshotter); err != nil { + return errors.Wrap(err, "error unpacking image") + } + + diffIDs, err := i.RootFS(ctx) + if err != nil { + return err + } + chainID := identity.ChainID(diffIDs).String() + fmt.Println(chainID) + + s := client.SnapshotService(snapshotter) + + var mounts []mount.Mount + if context.Bool("rw") { + mounts, err = s.Prepare(ctx, target, chainID) + } else { + mounts, err = s.View(ctx, target, chainID) + } + if err != nil { + if errdefs.IsAlreadyExists(err) { + mounts, err = s.Mounts(ctx, target) + } + if err != nil { + return err + } + } + + if err := mount.All(mounts, target); err != nil { + if err := s.Remove(ctx, target); err != nil && !errdefs.IsNotFound(err) { + fmt.Fprintln(context.App.ErrWriter, "Error cleaning up snapshot after mount error:", err) + } + return err + } + + fmt.Fprintln(context.App.Writer, target) + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/images/pull.go containerd-1.5.9/cmd/ctr/commands/images/pull.go --- containerd-1.2.6/cmd/ctr/commands/images/pull.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/pull.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "fmt" + "time" "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" @@ -25,6 +26,7 @@ "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/platforms" + "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/urfave/cli" @@ -51,7 +53,19 @@ }, cli.BoolFlag{ Name: "all-platforms", - Usage: "pull content from all platforms", + Usage: "pull content and metadata from all platforms", + }, + cli.BoolFlag{ + Name: "all-metadata", + Usage: "Pull metadata for all platforms", + }, + cli.BoolFlag{ + Name: "print-chainid", + Usage: "Print the resulting image's chain ID", + }, + cli.IntFlag{ + Name: "max-concurrent-downloads", + Usage: "Set the max concurrent downloads for each pull", }, ), Action: func(context *cli.Context) error { @@ -78,6 +92,7 @@ if err != nil { return err } + img, err := content.Fetch(ctx, client, ref, config) if err != nil { return err @@ -106,6 +121,7 @@ p = append(p, platforms.DefaultSpec()) } + start := time.Now() for _, platform := range p { fmt.Printf("unpacking %s %s...\n", platforms.Format(platform), img.Target.Digest) i := containerd.NewImageWithPlatform(client, img, platforms.Only(platform)) @@ -113,9 +129,16 @@ if err != nil { return err } + if context.Bool("print-chainid") { + diffIDs, err := i.RootFS(ctx) + if err != nil { + return err + } + chainID := identity.ChainID(diffIDs).String() + fmt.Printf("image chain ID: %s\n", chainID) + } } - - fmt.Println("done") + fmt.Printf("done: %s\t\n", time.Since(start)) return nil }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/images/push.go containerd-1.5.9/cmd/ctr/commands/images/push.go --- containerd-1.2.6/cmd/ctr/commands/images/push.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/push.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( gocontext "context" + "net/http/httptrace" "os" "sync" "text/tabwriter" @@ -29,6 +30,7 @@ "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/pkg/progress" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" digest "github.com/opencontainers/go-digest" @@ -58,21 +60,31 @@ Name: "manifest-type", Usage: "media type of manifest digest", Value: ocispec.MediaTypeImageManifest, + }, cli.StringSliceFlag{ + Name: "platform", + Usage: "push content from a specific platform", + Value: &cli.StringSlice{}, + }, cli.IntFlag{ + Name: "max-concurrent-uploaded-layers", + Usage: "Set the max concurrent uploaded layers for each push", }), Action: func(context *cli.Context) error { var ( ref = context.Args().First() local = context.Args().Get(1) + debug = context.GlobalBool("debug") desc ocispec.Descriptor ) if ref == "" { return errors.New("please provide a remote image reference to push") } + client, ctx, cancel, err := commands.NewClient(context) if err != nil { return err } defer cancel() + if manifest := context.String("manifest"); manifest != "" { desc.Digest, err = digest.Parse(manifest) if err != nil { @@ -88,8 +100,32 @@ return errors.Wrap(err, "unable to resolve image to manifest") } desc = img.Target + + if pss := context.StringSlice("platform"); len(pss) == 1 { + p, err := platforms.Parse(pss[0]) + if err != nil { + return errors.Wrapf(err, "invalid platform %q", pss[0]) + } + + cs := client.ContentStore() + if manifests, err := images.Children(ctx, cs, desc); err == nil && len(manifests) > 0 { + matcher := platforms.NewMatcher(p) + for _, manifest := range manifests { + if manifest.Platform != nil && matcher.Match(*manifest.Platform) { + if _, err := images.Children(ctx, cs, manifest); err != nil { + return errors.Wrap(err, "no matching manifest") + } + desc = manifest + break + } + } + } + } } + if context.Bool("http-trace") { + ctx = httptrace.WithClientTrace(ctx, commands.NewDebugClientTrace(ctx)) + } resolver, err := commands.GetResolver(ctx, context) if err != nil { return err @@ -98,7 +134,12 @@ eg, ctx := errgroup.WithContext(ctx) + // used to notify the progress writer + doneCh := make(chan struct{}) + eg.Go(func() error { + defer close(doneCh) + log.G(ctx).WithField("image", ref).WithField("digest", desc.Digest).Debug("pushing") jobHandler := images.HandlerFunc(func(ctx gocontext.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { @@ -106,49 +147,54 @@ return nil, nil }) - return client.Push(ctx, ref, desc, + ropts := []containerd.RemoteOpt{ containerd.WithResolver(resolver), containerd.WithImageHandler(jobHandler), - ) - }) - - errs := make(chan error) - go func() { - defer close(errs) - errs <- eg.Wait() - }() - - var ( - ticker = time.NewTicker(100 * time.Millisecond) - fw = progress.NewWriter(os.Stdout) - start = time.Now() - done bool - ) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - fw.Flush() + } - tw := tabwriter.NewWriter(fw, 1, 8, 1, ' ', 0) + if context.IsSet("max-concurrent-uploaded-layers") { + mcu := context.Int("max-concurrent-uploaded-layers") + ropts = append(ropts, containerd.WithMaxConcurrentUploadedLayers(mcu)) + } - content.Display(tw, ongoing.status(), start) - tw.Flush() + return client.Push(ctx, ref, desc, ropts...) + }) - if done { - fw.Flush() - return nil - } - case err := <-errs: - if err != nil { - return err + // don't show progress if debug mode is set + if !debug { + eg.Go(func() error { + var ( + ticker = time.NewTicker(100 * time.Millisecond) + fw = progress.NewWriter(os.Stdout) + start = time.Now() + done bool + ) + + defer ticker.Stop() + + for { + select { + case <-ticker.C: + fw.Flush() + + tw := tabwriter.NewWriter(fw, 1, 8, 1, ' ', 0) + + content.Display(tw, ongoing.status(), start) + tw.Flush() + + if done { + fw.Flush() + return nil + } + case <-doneCh: + done = true + case <-ctx.Done(): + done = true // allow ui to update once more + } } - done = true - case <-ctx.Done(): - done = true // allow ui to update once more - } + }) } + return eg.Wait() }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/images/tag.go containerd-1.5.9/cmd/ctr/commands/images/tag.go --- containerd-1.2.6/cmd/ctr/commands/images/tag.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/tag.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,88 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "fmt" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/urfave/cli" +) + +var tagCommand = cli.Command{ + Name: "tag", + Usage: "tag an image", + ArgsUsage: "[flags] [, ...]", + Description: `Tag an image for use in containerd.`, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "force", + Usage: "force target_ref to be created, regardless if it already exists", + }, + }, + Action: func(context *cli.Context) error { + var ( + ref = context.Args().First() + ) + if ref == "" { + return fmt.Errorf("please provide an image reference to tag from") + } + if context.NArg() <= 1 { + return fmt.Errorf("please provide an image reference to tag to") + } + + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + ctx, done, err := client.WithLease(ctx) + if err != nil { + return err + } + defer done(ctx) + + imageService := client.ImageService() + image, err := imageService.Get(ctx, ref) + if err != nil { + return err + } + // Support multiple references for one command run + for _, targetRef := range context.Args()[1:] { + image.Name = targetRef + // Attempt to create the image first + if _, err = imageService.Create(ctx, image); err != nil { + // If user has specified force and the image already exists then + // delete the original image and attempt to create the new one + if errdefs.IsAlreadyExists(err) && context.Bool("force") { + if err = imageService.Delete(ctx, targetRef); err != nil { + return err + } + if _, err = imageService.Create(ctx, image); err != nil { + return err + } + } else { + return err + } + } + fmt.Println(targetRef) + } + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/images/unmount.go containerd-1.5.9/cmd/ctr/commands/images/unmount.go --- containerd-1.2.6/cmd/ctr/commands/images/unmount.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/images/unmount.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "fmt" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/mount" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var unmountCommand = cli.Command{ + Name: "unmount", + Usage: "unmount the image from the target", + ArgsUsage: "[flags] ", + Description: "Unmount the image rootfs from the specified target.", + Flags: append(append(commands.RegistryFlags, append(commands.SnapshotterFlags, commands.LabelFlag)...), + cli.BoolFlag{ + Name: "rm", + Usage: "remove the snapshot after a successful unmount", + }, + ), + Action: func(context *cli.Context) error { + var ( + target = context.Args().First() + ) + if target == "" { + return fmt.Errorf("please provide a target path to unmount from") + } + + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + if err := mount.UnmountAll(target, 0); err != nil { + return err + } + + if context.Bool("rm") { + snapshotter := context.String("snapshotter") + s := client.SnapshotService(snapshotter) + if err := client.LeasesService().Delete(ctx, leases.Lease{ID: target}); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "error deleting lease") + } + if err := s.Remove(ctx, target); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "error removing snapshot") + } + } + + fmt.Fprintln(context.App.Writer, target) + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces.go containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces.go --- containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,7 +33,7 @@ // Command is the cli command for managing namespaces var Command = cli.Command{ Name: "namespaces", - Aliases: []string{"namespace"}, + Aliases: []string{"namespace", "ns"}, Usage: "manage namespaces", Subcommands: cli.Commands{ createCommand, @@ -45,6 +45,7 @@ var createCommand = cli.Command{ Name: "create", + Aliases: []string{"c"}, Usage: "create a new namespace", ArgsUsage: " [= [, ...]", Description: "remove one or more namespaces. for now, the namespace must be empty", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "cgroup,c", + Usage: "delete the namespace's cgroup", + }, + }, Action: func(context *cli.Context) error { var exitErr error client, ctx, cancel, err := commands.NewClient(context) @@ -153,9 +160,11 @@ return err } defer cancel() + + opts := deleteOpts(context) namespaces := client.NamespaceService() for _, target := range context.Args() { - if err := namespaces.Delete(ctx, target); err != nil { + if err := namespaces.Delete(ctx, target, opts...); err != nil { if !errdefs.IsNotFound(err) { if exitErr == nil { exitErr = errors.Wrapf(err, "unable to delete %v", target) diff -Nru containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces_linux.go containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces_linux.go --- containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package namespaces + +import ( + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/runtime/opts" + "github.com/urfave/cli" +) + +func deleteOpts(context *cli.Context) []namespaces.DeleteOpts { + var delOpts []namespaces.DeleteOpts + if context.Bool("cgroup") { + delOpts = append(delOpts, opts.WithNamespaceCgroupDeletion) + } + return delOpts +} diff -Nru containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces_other.go containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces_other.go --- containerd-1.2.6/cmd/ctr/commands/namespaces/namespaces_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/namespaces/namespaces_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package namespaces + +import ( + "github.com/containerd/containerd/namespaces" + "github.com/urfave/cli" +) + +func deleteOpts(context *cli.Context) []namespaces.DeleteOpts { + return nil +} diff -Nru containerd-1.2.6/cmd/ctr/commands/oci/oci.go containerd-1.5.9/cmd/ctr/commands/oci/oci.go --- containerd-1.2.6/cmd/ctr/commands/oci/oci.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/oci/oci.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "github.com/pkg/errors" + "github.com/urfave/cli" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" +) + +// Command is the parent for all OCI related tools under 'oci' +var Command = cli.Command{ + Name: "oci", + Usage: "OCI tools", + Subcommands: []cli.Command{ + defaultSpecCommand, + }, +} + +var defaultSpecCommand = cli.Command{ + Name: "spec", + Usage: "see the output of the default OCI spec", + Action: func(context *cli.Context) error { + ctx, cancel := commands.AppContext(context) + defer cancel() + + spec, err := oci.GenerateSpec(ctx, nil, &containers.Container{}) + if err != nil { + return errors.Wrap(err, "failed to generate spec") + } + + commands.PrintAsJSON(spec) + return nil + }, +} diff -Nru containerd-1.2.6/cmd/ctr/commands/plugins/plugins.go containerd-1.5.9/cmd/ctr/commands/plugins/plugins.go --- containerd-1.2.6/cmd/ctr/commands/plugins/plugins.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/plugins/plugins.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,11 +23,11 @@ "strings" "text/tabwriter" - introspection "github.com/containerd/containerd/api/services/introspection/v1" "github.com/containerd/containerd/api/types" "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/platforms" - "github.com/opencontainers/image-spec/specs-go/v1" + pluginutils "github.com/containerd/containerd/plugin" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli" "google.golang.org/grpc/codes" ) @@ -67,9 +67,7 @@ } defer cancel() ps := client.IntrospectionService() - response, err := ps.Plugins(ctx, &introspection.PluginsRequest{ - Filters: context.Args(), - }) + response, err := ps.Plugins(ctx, context.Args()) if err != nil { return err } @@ -124,7 +122,11 @@ status := "ok" if plugin.InitErr != nil { - status = "error" + if strings.Contains(plugin.InitErr.Message, pluginutils.ErrSkipPlugin.Error()) { + status = "skip" + } else { + status = "error" + } } var platformColumn = "-" diff -Nru containerd-1.2.6/cmd/ctr/commands/resolver.go containerd-1.5.9/cmd/ctr/commands/resolver.go --- containerd-1.2.6/cmd/ctr/commands/resolver.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/resolver.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,15 +20,20 @@ "bufio" gocontext "context" "crypto/tls" + "crypto/x509" "fmt" - "net" + "io" + "io/ioutil" "net/http" + "net/http/httptrace" + "net/http/httputil" "strings" - "time" "github.com/containerd/console" + "github.com/containerd/containerd/log" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" + "github.com/containerd/containerd/remotes/docker/config" "github.com/pkg/errors" "github.com/urfave/cli" ) @@ -60,8 +65,7 @@ username = username[0:i] } options := docker.ResolverOptions{ - PlainHTTP: clicontext.Bool("plain-http"), - Tracker: PushTracker, + Tracker: PushTracker, } if username != "" { if secret == "" { @@ -79,31 +83,124 @@ secret = rt } - tr := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 10, - IdleConnTimeout: 30 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: clicontext.Bool("insecure"), - }, - ExpectContinueTimeout: 5 * time.Second, + hostOptions := config.HostOptions{} + hostOptions.Credentials = func(host string) (string, string, error) { + // If host doesn't match... + // Only one host + return username, secret, nil } - - options.Client = &http.Client{ - Transport: tr, + if clicontext.Bool("plain-http") { + hostOptions.DefaultScheme = "http" + } + defaultTLS, err := resolverDefaultTLS(clicontext) + if err != nil { + return nil, err + } + hostOptions.DefaultTLS = defaultTLS + if hostDir := clicontext.String("hosts-dir"); hostDir != "" { + hostOptions.HostDir = config.HostDirFromRoot(hostDir) } - credentials := func(host string) (string, string, error) { - // Only one host - return username, secret, nil + if clicontext.Bool("http-dump") { + hostOptions.UpdateClient = func(client *http.Client) error { + client.Transport = &DebugTransport{ + transport: client.Transport, + writer: log.G(ctx).Writer(), + } + return nil + } } - options.Authorizer = docker.NewAuthorizer(options.Client, credentials) + + options.Hosts = config.ConfigureHosts(ctx, hostOptions) return docker.NewResolver(options), nil } + +func resolverDefaultTLS(clicontext *cli.Context) (*tls.Config, error) { + config := &tls.Config{} + + if clicontext.Bool("skip-verify") { + config.InsecureSkipVerify = true + } + + if tlsRootPath := clicontext.String("tlscacert"); tlsRootPath != "" { + tlsRootData, err := ioutil.ReadFile(tlsRootPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to read %q", tlsRootPath) + } + + config.RootCAs = x509.NewCertPool() + if !config.RootCAs.AppendCertsFromPEM(tlsRootData) { + return nil, fmt.Errorf("failed to load TLS CAs from %q: invalid data", tlsRootPath) + } + } + + tlsCertPath := clicontext.String("tlscert") + tlsKeyPath := clicontext.String("tlskey") + if tlsCertPath != "" || tlsKeyPath != "" { + if tlsCertPath == "" || tlsKeyPath == "" { + return nil, errors.New("flags --tlscert and --tlskey must be set together") + } + keyPair, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to load TLS client credentials (cert=%q, key=%q)", tlsCertPath, tlsKeyPath) + } + config.Certificates = []tls.Certificate{keyPair} + } + + return config, nil +} + +// DebugTransport wraps the underlying http.RoundTripper interface and dumps all requests/responses to the writer. +type DebugTransport struct { + transport http.RoundTripper + writer io.Writer +} + +// RoundTrip dumps request/responses and executes the request using the underlying transport. +func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) { + in, err := httputil.DumpRequest(req, true) + if err != nil { + return nil, errors.Wrap(err, "failed to dump request") + } + + if _, err := t.writer.Write(in); err != nil { + return nil, err + } + + resp, err := t.transport.RoundTrip(req) + if err != nil { + return nil, err + } + + out, err := httputil.DumpResponse(resp, true) + if err != nil { + return nil, errors.Wrap(err, "failed to dump response") + } + + if _, err := t.writer.Write(out); err != nil { + return nil, err + } + + return resp, err +} + +// NewDebugClientTrace returns a Go http trace client predefined to write DNS and connection +// information to the log. This is used via the --http-trace flag on push and pull operations in ctr. +func NewDebugClientTrace(ctx gocontext.Context) *httptrace.ClientTrace { + return &httptrace.ClientTrace{ + DNSStart: func(dnsInfo httptrace.DNSStartInfo) { + log.G(ctx).WithField("host", dnsInfo.Host).Debugf("DNS lookup") + }, + DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { + if dnsInfo.Err != nil { + log.G(ctx).WithField("lookup_err", dnsInfo.Err).Debugf("DNS lookup error") + } else { + log.G(ctx).WithField("result", dnsInfo.Addrs[0].String()).WithField("coalesced", dnsInfo.Coalesced).Debugf("DNS lookup complete") + } + }, + GotConn: func(connInfo httptrace.GotConnInfo) { + log.G(ctx).WithField("reused", connInfo.Reused).WithField("remote_addr", connInfo.Conn.RemoteAddr().String()).Debugf("Connection successful") + }, + } +} diff -Nru containerd-1.2.6/cmd/ctr/commands/run/run.go containerd-1.5.9/cmd/ctr/commands/run/run.go --- containerd-1.2.6/cmd/ctr/commands/run/run.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/run/run.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package run import ( + "context" gocontext "context" "encoding/csv" "fmt" @@ -28,7 +29,10 @@ "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/cmd/ctr/commands/tasks" "github.com/containerd/containerd/containers" + clabels "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" + gocni "github.com/containerd/go-cni" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -86,9 +90,10 @@ // Command runs a container var Command = cli.Command{ - Name: "run", - Usage: "run a container", - ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]", + Name: "run", + Usage: "run a container", + ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]", + SkipArgReorder: true, Flags: append([]cli.Flag{ cli.BoolFlag{ Name: "rm", @@ -98,6 +103,10 @@ Name: "null-io", Usage: "send all IO to /dev/null", }, + cli.StringFlag{ + Name: "log-uri", + Usage: "log uri", + }, cli.BoolFlag{ Name: "detach,d", Usage: "detach from the task after it has started execution", @@ -106,20 +115,25 @@ Name: "fifo-dir", Usage: "directory used for storing IO FIFOs", }, - cli.BoolFlag{ - Name: "isolated", - Usage: "run the container with vm isolation", + cli.StringFlag{ + Name: "cgroup", + Usage: "cgroup path (To disable use of cgroup, set to \"\" explicitly)", + }, + cli.StringFlag{ + Name: "platform", + Usage: "run image for specific platform", }, - }, append(commands.SnapshotterFlags, commands.ContainerFlags...)...), + }, append(platformRunFlags, append(commands.SnapshotterFlags, commands.ContainerFlags...)...)...), Action: func(context *cli.Context) error { var ( err error id string ref string - tty = context.Bool("tty") - detach = context.Bool("detach") - config = context.IsSet("config") + tty = context.Bool("tty") + detach = context.Bool("detach") + config = context.IsSet("config") + enableCNI = context.Bool("cni") ) if config { @@ -158,15 +172,31 @@ return err } } + var network gocni.CNI + if enableCNI { + if network, err = gocni.New(gocni.WithDefaultConf); err != nil { + return err + } + } + opts := getNewTaskOpts(context) ioOpts := []cio.Opt{cio.WithFIFODir(context.String("fifo-dir"))} - task, err := tasks.NewTask(ctx, client, container, context.String("checkpoint"), con, context.Bool("null-io"), ioOpts, opts...) + task, err := tasks.NewTask(ctx, client, container, context.String("checkpoint"), con, context.Bool("null-io"), context.String("log-uri"), ioOpts, opts...) if err != nil { return err } + var statusC <-chan containerd.ExitStatus if !detach { - defer task.Delete(ctx) + defer func() { + if enableCNI { + if err := network.Remove(ctx, fullID(ctx, container), ""); err != nil { + logrus.WithError(err).Error("network review") + } + } + task.Delete(ctx) + }() + if statusC, err = task.Wait(ctx); err != nil { return err } @@ -176,6 +206,11 @@ return err } } + if enableCNI { + if _, err := network.Setup(ctx, fullID(ctx, container), fmt.Sprintf("/proc/%d/ns/net", task.Pid())); err != nil { + return err + } + } if err := task.Start(ctx); err != nil { return err } @@ -204,3 +239,31 @@ return nil }, } + +func fullID(ctx context.Context, c containerd.Container) string { + id := c.ID() + ns, ok := namespaces.Namespace(ctx) + if !ok { + return id + } + return fmt.Sprintf("%s-%s", ns, id) +} + +// buildLabel builds the labels from command line labels and the image labels +func buildLabels(cmdLabels, imageLabels map[string]string) map[string]string { + labels := make(map[string]string) + for k, v := range imageLabels { + if err := clabels.Validate(k, v); err == nil { + labels[k] = v + } else { + // In case the image label is invalid, we output a warning and skip adding it to the + // container. + logrus.WithError(err).Warnf("unable to add image label with key %s to the container", k) + } + } + // labels from the command line will override image and the initial image config labels + for k, v := range cmdLabels { + labels[k] = v + } + return labels +} diff -Nru containerd-1.2.6/cmd/ctr/commands/run/run_unix.go containerd-1.5.9/cmd/ctr/commands/run/run_unix.go --- containerd-1.2.6/cmd/ctr/commands/run/run_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/run/run_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,18 +20,62 @@ import ( gocontext "context" + "fmt" "path/filepath" + "strconv" "strings" "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/contrib/apparmor" "github.com/containerd/containerd/contrib/nvidia" + "github.com/containerd/containerd/contrib/seccomp" "github.com/containerd/containerd/oci" + runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) +var platformRunFlags = []cli.Flag{ + cli.StringFlag{ + Name: "runc-binary", + Usage: "specify runc-compatible binary", + }, + cli.StringFlag{ + Name: "runc-root", + Usage: "specify runc-compatible root", + }, + cli.BoolFlag{ + Name: "runc-systemd-cgroup", + Usage: "start runc with systemd cgroup manager", + }, + cli.StringFlag{ + Name: "uidmap", + Usage: "run inside a user namespace with the specified UID mapping range; specified with the format `container-uid:host-uid:length`", + }, + cli.StringFlag{ + Name: "gidmap", + Usage: "run inside a user namespace with the specified GID mapping range; specified with the format `container-gid:host-gid:length`", + }, + cli.BoolFlag{ + Name: "remap-labels", + Usage: "provide the user namespace ID remapping to the snapshotter via label options; requires snapshotter support", + }, + cli.Float64Flag{ + Name: "cpus", + Usage: "set the CFS cpu quota", + Value: 0.0, + }, + cli.BoolFlag{ + Name: "cni", + Usage: "enable cni networking for the container", + }, +} + // NewContainer creates a new container func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) { var ( @@ -44,22 +88,14 @@ id = context.Args().Get(1) } - if raw := context.String("checkpoint"); raw != "" { - im, err := client.GetImage(ctx, raw) - if err != nil { - return nil, err - } - return client.NewContainer(ctx, id, containerd.WithCheckpoint(im, id), containerd.WithRuntime(context.String("runtime"), nil)) - } - var ( opts []oci.SpecOpts cOpts []containerd.NewContainerOpts spec containerd.NewContainerOpts ) - cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label")))) if config { + cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("labels")))) opts = append(opts, oci.WithSpecFromFile(context.String("config"))) } else { var ( @@ -68,6 +104,9 @@ args = context.Args()[2:] ) opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices) + if ef := context.String("env-file"); ef != "" { + opts = append(opts, oci.WithEnvFile(ef)) + } opts = append(opts, oci.WithEnv(context.StringSlice("env"))) opts = append(opts, withMounts(context)) @@ -77,12 +116,24 @@ return nil, err } opts = append(opts, oci.WithRootFSPath(rootfs)) + cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("labels")))) } else { snapshotter := context.String("snapshotter") - image, err := client.GetImage(ctx, ref) + var image containerd.Image + i, err := client.ImageService().Get(ctx, ref) if err != nil { return nil, err } + if ps := context.String("platform"); ps != "" { + platform, err := platforms.Parse(ps) + if err != nil { + return nil, err + } + image = containerd.NewImageWithPlatform(client, i, platforms.Only(platform)) + } else { + image = containerd.NewImage(client, i) + } + unpacked, err := image.IsUnpacked(ctx, snapshotter) if err != nil { return nil, err @@ -92,17 +143,42 @@ return nil, err } } + labels := buildLabels(commands.LabelArgs(context.StringSlice("label")), image.Labels()) opts = append(opts, oci.WithImageConfig(image)) cOpts = append(cOpts, containerd.WithImage(image), - containerd.WithSnapshotter(snapshotter), - // Even when "readonly" is set, we don't use KindView snapshot here. (#1495) + containerd.WithImageConfigLabels(image), + containerd.WithAdditionalContainerLabels(labels), + containerd.WithSnapshotter(snapshotter)) + if uidmap, gidmap := context.String("uidmap"), context.String("gidmap"); uidmap != "" && gidmap != "" { + uidMap, err := parseIDMapping(uidmap) + if err != nil { + return nil, err + } + gidMap, err := parseIDMapping(gidmap) + if err != nil { + return nil, err + } + opts = append(opts, + oci.WithUserNamespace([]specs.LinuxIDMapping{uidMap}, []specs.LinuxIDMapping{gidMap})) + // use snapshotter opts or the remapped snapshot support to shift the filesystem + // currently the only snapshotter known to support the labels is fuse-overlayfs: + // https://github.com/AkihiroSuda/containerd-fuse-overlayfs + if context.Bool("remap-labels") { + cOpts = append(cOpts, containerd.WithNewSnapshot(id, image, + containerd.WithRemapperLabels(0, uidMap.HostID, 0, gidMap.HostID, uidMap.Size))) + } else { + cOpts = append(cOpts, containerd.WithRemappedSnapshot(id, image, uidMap.HostID, gidMap.HostID)) + } + } else { + // Even when "read-only" is set, we don't use KindView snapshot here. (#1495) // We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only, // after creating some mount points on demand. - containerd.WithNewSnapshot(id, image), - containerd.WithImageStopSignal(image, "SIGTERM")) + cOpts = append(cOpts, containerd.WithNewSnapshot(id, image)) + } + cOpts = append(cOpts, containerd.WithImageStopSignal(image, "SIGTERM")) } - if context.Bool("readonly") { + if context.Bool("read-only") { opts = append(opts, oci.WithRootFSReadonly()) } if len(args) > 0 { @@ -115,12 +191,54 @@ opts = append(opts, oci.WithTTY) } if context.Bool("privileged") { - opts = append(opts, oci.WithPrivileged) + opts = append(opts, oci.WithPrivileged, oci.WithAllDevicesAllowed, oci.WithHostDevices) } if context.Bool("net-host") { opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf) } + seccompProfile := context.String("seccomp-profile") + + if !context.Bool("seccomp") && seccompProfile != "" { + return nil, fmt.Errorf("seccomp must be set to true, if using a custom seccomp-profile") + } + + if context.Bool("seccomp") { + if seccompProfile != "" { + opts = append(opts, seccomp.WithProfile(seccompProfile)) + } else { + opts = append(opts, seccomp.WithDefaultProfile()) + } + } + + if s := context.String("apparmor-default-profile"); len(s) > 0 { + opts = append(opts, apparmor.WithDefaultProfile(s)) + } + + if s := context.String("apparmor-profile"); len(s) > 0 { + if len(context.String("apparmor-default-profile")) > 0 { + return nil, fmt.Errorf("apparmor-profile conflicts with apparmor-default-profile") + } + opts = append(opts, apparmor.WithProfile(s)) + } + + if cpus := context.Float64("cpus"); cpus > 0.0 { + var ( + period = uint64(100000) + quota = int64(cpus * 100000.0) + ) + opts = append(opts, oci.WithCPUCFS(quota, period)) + } + + quota := context.Int64("cpu-quota") + period := context.Uint64("cpu-period") + if quota != -1 || period != 0 { + if cpus := context.Float64("cpus"); cpus > 0.0 { + return nil, errors.New("cpus and quota/period should be used separately") + } + opts = append(opts, oci.WithCPUCFS(quota, period)) + } + joinNs := context.StringSlice("with-ns") for _, ns := range joinNs { parts := strings.Split(ns, ":") @@ -141,10 +259,26 @@ if context.IsSet("allow-new-privs") { opts = append(opts, oci.WithNewPrivileges) } + if context.IsSet("cgroup") { + // NOTE: can be set to "" explicitly for disabling cgroup. + opts = append(opts, oci.WithCgroup(context.String("cgroup"))) + } + limit := context.Uint64("memory-limit") + if limit != 0 { + opts = append(opts, oci.WithMemoryLimit(limit)) + } + for _, dev := range context.StringSlice("device") { + opts = append(opts, oci.WithDevices(dev, "", "rwm")) + } } - cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil)) + runtimeOpts, err := getRuntimeOptions(context) + if err != nil { + return nil, err + } + cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), runtimeOpts)) + opts = append(opts, oci.WithAnnotations(commands.LabelArgs(context.StringSlice("label")))) var s specs.Spec spec = containerd.WithSpec(&s, opts...) @@ -155,11 +289,91 @@ return client.NewContainer(ctx, id, cOpts...) } +func getRuncOptions(context *cli.Context) (*options.Options, error) { + runtimeOpts := &options.Options{} + if runcBinary := context.String("runc-binary"); runcBinary != "" { + runtimeOpts.BinaryName = runcBinary + } + if context.Bool("runc-systemd-cgroup") { + if context.String("cgroup") == "" { + // runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope" + return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"") + } + runtimeOpts.SystemdCgroup = true + } + if root := context.String("runc-root"); root != "" { + runtimeOpts.Root = root + } + + return runtimeOpts, nil +} + +func getRuntimeOptions(context *cli.Context) (interface{}, error) { + // validate first + if (context.String("runc-binary") != "" || context.Bool("runc-systemd-cgroup")) && + context.String("runtime") != "io.containerd.runc.v2" { + return nil, errors.New("specifying runc-binary and runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime") + } + + if context.String("runtime") == "io.containerd.runc.v2" { + return getRuncOptions(context) + } + + if configPath := context.String("runtime-config-path"); configPath != "" { + return &runtimeoptions.Options{ + ConfigPath: configPath, + }, nil + } + + return nil, nil +} + func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts { + var ( + tOpts []containerd.NewTaskOpts + ) if context.Bool("no-pivot") { - return []containerd.NewTaskOpts{containerd.WithNoPivotRoot} + tOpts = append(tOpts, containerd.WithNoPivotRoot) + } + if uidmap := context.String("uidmap"); uidmap != "" { + uidMap, err := parseIDMapping(uidmap) + if err != nil { + logrus.WithError(err).Warn("unable to parse uidmap; defaulting to uid 0 IO ownership") + } + tOpts = append(tOpts, containerd.WithUIDOwner(uidMap.HostID)) + } + if gidmap := context.String("gidmap"); gidmap != "" { + gidMap, err := parseIDMapping(gidmap) + if err != nil { + logrus.WithError(err).Warn("unable to parse gidmap; defaulting to gid 0 IO ownership") + } + tOpts = append(tOpts, containerd.WithGIDOwner(gidMap.HostID)) + } + return tOpts +} + +func parseIDMapping(mapping string) (specs.LinuxIDMapping, error) { + parts := strings.Split(mapping, ":") + if len(parts) != 3 { + return specs.LinuxIDMapping{}, errors.New("user namespace mappings require the format `container-id:host-id:size`") + } + cID, err := strconv.ParseUint(parts[0], 0, 32) + if err != nil { + return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid container id for user namespace remapping") + } + hID, err := strconv.ParseUint(parts[1], 0, 32) + if err != nil { + return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid host id for user namespace remapping") + } + size, err := strconv.ParseUint(parts[2], 0, 32) + if err != nil { + return specs.LinuxIDMapping{}, errors.Wrapf(err, "invalid size for user namespace remapping") } - return nil + return specs.LinuxIDMapping{ + ContainerID: uint32(cID), + HostID: uint32(hID), + Size: uint32(size), + }, nil } func validNamespace(ns string) bool { diff -Nru containerd-1.2.6/cmd/ctr/commands/run/run_windows.go containerd-1.5.9/cmd/ctr/commands/run/run_windows.go --- containerd-1.2.6/cmd/ctr/commands/run/run_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/run/run_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,16 +19,24 @@ import ( gocontext "context" + "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" "github.com/containerd/console" "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/runtime/v2/runhcs/options" specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) +var platformRunFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "isolated", + Usage: "run the container with vm isolation", + }, +} + // NewContainer creates a new container func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) { var ( @@ -43,6 +51,7 @@ if config { id = context.Args().First() opts = append(opts, oci.WithSpecFromFile(context.String("config"))) + cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label")))) } else { var ( ref = context.Args().First() @@ -57,6 +66,11 @@ opts = append(opts, oci.WithRootFSPath("")) } else { opts = append(opts, oci.WithDefaultSpec()) + opts = append(opts, oci.WithWindowNetworksAllowUnqualifiedDNSQuery()) + opts = append(opts, oci.WithWindowsIgnoreFlushesDuringBoot()) + } + if ef := context.String("env-file"); ef != "" { + opts = append(opts, oci.WithEnvFile(ef)) } opts = append(opts, oci.WithEnv(context.StringSlice("env"))) opts = append(opts, withMounts(context)) @@ -75,9 +89,13 @@ } } opts = append(opts, oci.WithImageConfig(image)) - cOpts = append(cOpts, containerd.WithImage(image)) - cOpts = append(cOpts, containerd.WithSnapshotter(snapshotter)) - cOpts = append(cOpts, containerd.WithNewSnapshot(id, image)) + labels := buildLabels(commands.LabelArgs(context.StringSlice("label")), image.Labels()) + cOpts = append(cOpts, + containerd.WithImage(image), + containerd.WithImageConfigLabels(image), + containerd.WithSnapshotter(snapshotter), + containerd.WithNewSnapshot(id, image), + containerd.WithAdditionalContainerLabels(labels)) if len(args) > 0 { opts = append(opts, oci.WithProcessArgs(args...)) @@ -95,12 +113,22 @@ } opts = append(opts, oci.WithTTYSize(int(size.Width), int(size.Height))) } + if context.Bool("net-host") { + return nil, errors.New("Cannot use host mode networking with Windows containers") + } if context.Bool("isolated") { opts = append(opts, oci.WithWindowsHyperV) } + limit := context.Uint64("memory-limit") + if limit != 0 { + opts = append(opts, oci.WithMemoryLimit(limit)) + } + ccount := context.Uint64("cpu-count") + if ccount != 0 { + opts = append(opts, oci.WithWindowsCPUCount(ccount)) + } } - cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label")))) runtime := context.String("runtime") var runtimeOpts interface{} if runtime == "io.containerd.runhcs.v1" { diff -Nru containerd-1.2.6/cmd/ctr/commands/shim/shim.go containerd-1.5.9/cmd/ctr/commands/shim/shim.go --- containerd-1.2.6/cmd/ctr/commands/shim/shim.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/shim/shim.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,9 +23,13 @@ "fmt" "io/ioutil" "net" + "path/filepath" + "strings" "github.com/containerd/console" "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/runtime/v2/shim" "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/ttrpc" "github.com/containerd/typeurl" @@ -61,8 +65,8 @@ Usage: "interact with a shim directly", Flags: []cli.Flag{ cli.StringFlag{ - Name: "socket", - Usage: "socket on which to connect to the shim", + Name: "id", + Usage: "container id", }, }, Subcommands: []cli.Command{ @@ -116,7 +120,7 @@ return err } r, err := service.State(gocontext.Background(), &task.StateRequest{ - ID: context.Args().First(), + ID: context.GlobalString("id"), }) if err != nil { return err @@ -226,20 +230,31 @@ } func getTaskService(context *cli.Context) (task.TaskService, error) { - bindSocket := context.GlobalString("socket") - if bindSocket == "" { - return nil, errors.New("socket path must be specified") + id := context.GlobalString("id") + if id == "" { + return nil, fmt.Errorf("container id must be specified") } + ns := context.GlobalString("namespace") - conn, err := net.Dial("unix", "\x00"+bindSocket) - if err != nil { - return nil, err - } + // /containerd-shim/ns/id/shim.sock is the old way to generate shim socket, + // compatible it + s1 := filepath.Join(string(filepath.Separator), "containerd-shim", ns, id, "shim.sock") + // this should not error, ctr always get a default ns + ctx := namespaces.WithNamespace(gocontext.Background(), ns) + s2, _ := shim.SocketAddress(ctx, context.GlobalString("address"), id) + s2 = strings.TrimPrefix(s2, "unix://") + + for _, socket := range []string{s2, "\x00" + s1} { + conn, err := net.Dial("unix", socket) + if err == nil { + client := ttrpc.NewClient(conn) - client := ttrpc.NewClient(conn) + // TODO(stevvooe): This actually leaks the connection. We were leaking it + // before, so may not be a huge deal. - // TODO(stevvooe): This actually leaks the connection. We were leaking it - // before, so may not be a huge deal. + return task.NewTaskClient(client), nil + } + } - return task.NewTaskClient(client), nil + return nil, fmt.Errorf("fail to connect to container %s's shim", id) } diff -Nru containerd-1.2.6/cmd/ctr/commands/signals.go containerd-1.5.9/cmd/ctr/commands/signals.go --- containerd-1.2.6/cmd/ctr/commands/signals.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/signals.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,6 +23,7 @@ "syscall" "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" "github.com/sirupsen/logrus" ) @@ -36,8 +37,16 @@ signal.Notify(sigc) go func() { for s := range sigc { + if canIgnoreSignal(s) { + logrus.Debugf("Ignoring signal %s", s) + continue + } logrus.Debug("forwarding signal ", s) if err := task.Kill(ctx, s.(syscall.Signal)); err != nil { + if errdefs.IsNotFound(err) { + logrus.WithError(err).Debugf("Not forwarding signal %s", s) + return + } logrus.WithError(err).Errorf("forward signal %s", s) } } diff -Nru containerd-1.2.6/cmd/ctr/commands/signals_linux.go containerd-1.5.9/cmd/ctr/commands/signals_linux.go --- containerd-1.2.6/cmd/ctr/commands/signals_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/signals_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func canIgnoreSignal(s os.Signal) bool { + return s == unix.SIGURG +} diff -Nru containerd-1.2.6/cmd/ctr/commands/signals_notlinux.go containerd-1.5.9/cmd/ctr/commands/signals_notlinux.go --- containerd-1.2.6/cmd/ctr/commands/signals_notlinux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/signals_notlinux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +//+build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +import "os" + +func canIgnoreSignal(_ os.Signal) bool { + return false +} diff -Nru containerd-1.2.6/cmd/ctr/commands/snapshots/snapshots.go containerd-1.5.9/cmd/ctr/commands/snapshots/snapshots.go --- containerd-1.2.6/cmd/ctr/commands/snapshots/snapshots.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/snapshots/snapshots.go 2022-01-05 17:30:58.000000000 +0000 @@ -150,18 +150,11 @@ return err } } else { - var a, b []mount.Mount - ds := client.DiffService() - - a, err = getMounts(ctx, idA, snapshotter) - if err != nil { - return err - } - b, err = getMounts(ctx, idB, snapshotter) - if err != nil { - return err - } - desc, err = ds.Compare(ctx, a, b, opts...) + desc, err = withMounts(ctx, idA, snapshotter, func(a []mount.Mount) (ocispec.Descriptor, error) { + return withMounts(ctx, idB, snapshotter, func(b []mount.Mount) (ocispec.Descriptor, error) { + return client.DiffService().Compare(ctx, a, b, opts...) + }) + }) if err != nil { return err } @@ -177,26 +170,26 @@ }, } -func getMounts(ctx gocontext.Context, id string, sn snapshots.Snapshotter) ([]mount.Mount, error) { +func withMounts(ctx gocontext.Context, id string, sn snapshots.Snapshotter, f func(mounts []mount.Mount) (ocispec.Descriptor, error)) (ocispec.Descriptor, error) { var mounts []mount.Mount info, err := sn.Stat(ctx, id) if err != nil { - return nil, err + return ocispec.Descriptor{}, err } if info.Kind == snapshots.KindActive { mounts, err = sn.Mounts(ctx, id) if err != nil { - return nil, err + return ocispec.Descriptor{}, err } } else { key := fmt.Sprintf("%s-view-key", id) mounts, err = sn.View(ctx, key, id) if err != nil { - return nil, err + return ocispec.Descriptor{}, err } defer sn.Remove(ctx, key) } - return mounts, nil + return f(mounts) } var usageCommand = cli.Command{ @@ -287,6 +280,10 @@ Name: "target, t", Usage: "mount target path, will print mount, if provided", }, + cli.BoolFlag{ + Name: "mounts", + Usage: "Print out snapshot mounts as JSON", + }, }, Action: func(context *cli.Context) error { if narg := context.NArg(); narg < 1 || narg > 2 { @@ -317,6 +314,10 @@ printMounts(target, mounts) } + if context.Bool("mounts") { + commands.PrintAsJSON(mounts) + } + return nil }, } @@ -330,6 +331,10 @@ Name: "target, t", Usage: "mount target path, will print mount, if provided", }, + cli.BoolFlag{ + Name: "mounts", + Usage: "Print out snapshot mounts as JSON", + }, }, Action: func(context *cli.Context) error { if narg := context.NArg(); narg < 1 || narg > 2 { @@ -356,6 +361,10 @@ printMounts(target, mounts) } + if context.Bool("mounts") { + commands.PrintAsJSON(mounts) + } + return nil }, } diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/checkpoint.go containerd-1.5.9/cmd/ctr/commands/tasks/checkpoint.go --- containerd-1.2.6/cmd/ctr/commands/tasks/checkpoint.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/checkpoint.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,10 +18,10 @@ import ( "fmt" - "runtime" "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime/linux/runctypes" "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/pkg/errors" @@ -38,9 +38,12 @@ Usage: "stop the container after the checkpoint", }, cli.StringFlag{ - Name: "runtime", - Usage: "runtime name", - Value: fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS), + Name: "image-path", + Usage: "path to criu image files", + }, + cli.StringFlag{ + Name: "work-path", + Usage: "path to criu work files and logs", }, }, Action: func(context *cli.Context) error { @@ -61,40 +64,59 @@ if err != nil { return err } - var opts []containerd.CheckpointTaskOpts - if context.Bool("exit") { - opts = append(opts, withExit(context.String("runtime"))) + info, err := container.Info(ctx) + if err != nil { + return err } + opts := []containerd.CheckpointTaskOpts{withCheckpointOpts(info.Runtime.Name, context)} checkpoint, err := task.Checkpoint(ctx, opts...) if err != nil { return err } - fmt.Println(checkpoint.Name()) + if context.String("image-path") == "" { + fmt.Println(checkpoint.Name()) + } return nil }, } -func withExit(rt string) containerd.CheckpointTaskOpts { +// withCheckpointOpts only suitable for runc runtime now +func withCheckpointOpts(rt string, context *cli.Context) containerd.CheckpointTaskOpts { return func(r *containerd.CheckpointTaskInfo) error { + imagePath := context.String("image-path") + workPath := context.String("work-path") + switch rt { - case "io.containerd.runc.v1": + case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2: if r.Options == nil { - r.Options = &options.CheckpointOptions{ - Exit: true, - } - } else { - opts, _ := r.Options.(*options.CheckpointOptions) + r.Options = &options.CheckpointOptions{} + } + opts, _ := r.Options.(*options.CheckpointOptions) + + if context.Bool("exit") { opts.Exit = true } - default: + if imagePath != "" { + opts.ImagePath = imagePath + } + if workPath != "" { + opts.WorkPath = workPath + } + case plugin.RuntimeLinuxV1: if r.Options == nil { - r.Options = &runctypes.CheckpointOptions{ - Exit: true, - } - } else { - opts, _ := r.Options.(*runctypes.CheckpointOptions) + r.Options = &runctypes.CheckpointOptions{} + } + opts, _ := r.Options.(*runctypes.CheckpointOptions) + + if context.Bool("exit") { opts.Exit = true } + if imagePath != "" { + opts.ImagePath = imagePath + } + if workPath != "" { + opts.WorkPath = workPath + } } return nil } diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/delete.go containerd-1.5.9/cmd/ctr/commands/tasks/delete.go --- containerd-1.2.6/cmd/ctr/commands/tasks/delete.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/delete.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,47 +17,96 @@ package tasks import ( + gocontext "context" + "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/log" "github.com/urfave/cli" ) var deleteCommand = cli.Command{ Name: "delete", - Usage: "[flags] delete a task", - ArgsUsage: "CONTAINER", + Usage: "delete one or more tasks", + ArgsUsage: "CONTAINER [CONTAINER, ...]", + Aliases: []string{"rm"}, Flags: []cli.Flag{ cli.BoolFlag{ Name: "force, f", Usage: "force delete task process", }, + cli.StringFlag{ + Name: "exec-id", + Usage: "process ID to kill", + }, }, Action: func(context *cli.Context) error { + var ( + execID = context.String("exec-id") + force = context.Bool("force") + ) client, ctx, cancel, err := commands.NewClient(context) if err != nil { return err } defer cancel() - container, err := client.LoadContainer(ctx, context.Args().First()) - if err != nil { - return err - } - task, err := container.Task(ctx, cio.Load) - if err != nil { - return err - } var opts []containerd.ProcessDeleteOpts - if context.Bool("force") { + if force { opts = append(opts, containerd.WithProcessKill) } - status, err := task.Delete(ctx, opts...) - if err != nil { - return err - } - if ec := status.ExitCode(); ec != 0 { - return cli.NewExitError("", int(ec)) + var exitErr error + if execID != "" { + task, err := loadTask(ctx, client, context.Args().First()) + if err != nil { + return err + } + p, err := task.LoadProcess(ctx, execID, nil) + if err != nil { + return err + } + status, err := p.Delete(ctx, opts...) + if err != nil { + return err + } + if ec := status.ExitCode(); ec != 0 { + return cli.NewExitError("", int(ec)) + } + } else { + for _, target := range context.Args() { + task, err := loadTask(ctx, client, target) + if err != nil { + if exitErr == nil { + exitErr = err + } + log.G(ctx).WithError(err).Errorf("failed to load task from %v", target) + continue + } + status, err := task.Delete(ctx, opts...) + if err != nil { + if exitErr == nil { + exitErr = err + } + log.G(ctx).WithError(err).Errorf("unable to delete %v", task.ID()) + continue + } + if ec := status.ExitCode(); ec != 0 { + log.G(ctx).Warnf("task %v exit with non-zero exit code %v", task.ID(), int(ec)) + } + } } - return nil + return exitErr }, } + +func loadTask(ctx gocontext.Context, client *containerd.Client, containerID string) (containerd.Task, error) { + container, err := client.LoadContainer(ctx, containerID) + if err != nil { + return nil, err + } + task, err := container.Task(ctx, cio.Load) + if err != nil { + return nil, err + } + return task, nil +} diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/exec.go containerd-1.5.9/cmd/ctr/commands/tasks/exec.go --- containerd-1.2.6/cmd/ctr/commands/tasks/exec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,19 +18,25 @@ import ( "errors" + "io" + "net/url" + "os" "github.com/containerd/console" + "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/oci" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) //TODO:(jessvalarezo) exec-id is optional here, update to required arg var execCommand = cli.Command{ - Name: "exec", - Usage: "execute additional processes in an existing container", - ArgsUsage: "[flags] CONTAINER CMD [ARG...]", + Name: "exec", + Usage: "execute additional processes in an existing container", + ArgsUsage: "[flags] CONTAINER CMD [ARG...]", + SkipArgReorder: true, Flags: []cli.Flag{ cli.StringFlag{ Name: "cwd", @@ -40,6 +46,10 @@ Name: "tty,t", Usage: "allocate a TTY for the container", }, + cli.BoolFlag{ + Name: "detach,d", + Usage: "detach from the task after it has started execution", + }, cli.StringFlag{ Name: "exec-id", Usage: "exec specific id for the process", @@ -48,12 +58,21 @@ Name: "fifo-dir", Usage: "directory used for storing IO FIFOs", }, + cli.StringFlag{ + Name: "log-uri", + Usage: "log uri for custom shim logging", + }, + cli.StringFlag{ + Name: "user", + Usage: "user id or name", + }, }, Action: func(context *cli.Context) error { var ( - id = context.Args().First() - args = context.Args().Tail() - tty = context.Bool("tty") + id = context.Args().First() + args = context.Args().Tail() + tty = context.Bool("tty") + detach = context.Bool("detach") ) if id == "" { return errors.New("container id must be provided") @@ -71,25 +90,66 @@ if err != nil { return err } - task, err := container.Task(ctx, nil) - if err != nil { - return err + if user := context.String("user"); user != "" { + c, err := container.Info(ctx) + if err != nil { + return err + } + if err := oci.WithUser(user)(ctx, client, &c, spec); err != nil { + return err + } } pspec := spec.Process pspec.Terminal = tty pspec.Args = args - cioOpts := []cio.Opt{cio.WithStdio, cio.WithFIFODir(context.String("fifo-dir"))} - if tty { - cioOpts = append(cioOpts, cio.WithTerminal) + task, err := container.Task(ctx, nil) + if err != nil { + return err } - ioCreator := cio.NewCreator(cioOpts...) + + var ( + ioCreator cio.Creator + stdinC = &stdinCloser{ + stdin: os.Stdin, + } + ) + + if logURI := context.String("log-uri"); logURI != "" { + uri, err := url.Parse(logURI) + if err != nil { + return err + } + + if dir := context.String("fifo-dir"); dir != "" { + return errors.New("can't use log-uri with fifo-dir") + } + + if tty { + return errors.New("can't use log-uri with tty") + } + + ioCreator = cio.LogURI(uri) + } else { + cioOpts := []cio.Opt{cio.WithStreams(stdinC, os.Stdout, os.Stderr), cio.WithFIFODir(context.String("fifo-dir"))} + if tty { + cioOpts = append(cioOpts, cio.WithTerminal) + } + ioCreator = cio.NewCreator(cioOpts...) + } + process, err := task.Exec(ctx, context.String("exec-id"), pspec, ioCreator) if err != nil { return err } - defer process.Delete(ctx) + stdinC.closer = func() { + process.CloseIO(ctx, containerd.WithStdinCloser) + } + // if detach, we should not call this defer + if !detach { + defer process.Delete(ctx) + } statusC, err := process.Wait(ctx) if err != nil { @@ -104,18 +164,23 @@ return err } } - if tty { - if err := HandleConsoleResize(ctx, process, con); err != nil { - logrus.WithError(err).Error("console resize") + if !detach { + if tty { + if err := HandleConsoleResize(ctx, process, con); err != nil { + logrus.WithError(err).Error("console resize") + } + } else { + sigc := commands.ForwardAllSignals(ctx, process) + defer commands.StopCatch(sigc) } - } else { - sigc := commands.ForwardAllSignals(ctx, process) - defer commands.StopCatch(sigc) } if err := process.Start(ctx); err != nil { return err } + if detach { + return nil + } status := <-statusC code, _, err := status.Result() if err != nil { @@ -127,3 +192,18 @@ return nil }, } + +type stdinCloser struct { + stdin *os.File + closer func() +} + +func (s *stdinCloser) Read(p []byte) (int, error) { + n, err := s.stdin.Read(p) + if err == io.EOF { + if s.closer != nil { + s.closer() + } + } + return n, err +} diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/metrics.go containerd-1.5.9/cmd/ctr/commands/tasks/metrics.go --- containerd-1.2.6/cmd/ctr/commands/tasks/metrics.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/metrics.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,7 +25,9 @@ "os" "text/tabwriter" - "github.com/containerd/cgroups" + wstats "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" + v1 "github.com/containerd/cgroups/stats/v1" + v2 "github.com/containerd/cgroups/v2/stats" "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/typeurl" "github.com/urfave/cli" @@ -71,15 +73,26 @@ } metric, err := task.Metrics(ctx) if err != nil { - return nil + return err } anydata, err := typeurl.UnmarshalAny(metric.Data) if err != nil { return err } - data, ok := anydata.(*cgroups.Metrics) - if !ok { - return errors.New("cannot convert metric data to cgroups.Metrics") + var ( + data *v1.Metrics + data2 *v2.Metrics + windowsStats *wstats.Statistics + ) + switch v := anydata.(type) { + case *v1.Metrics: + data = v + case *v2.Metrics: + data2 = v + case *wstats.Statistics: + windowsStats = v + default: + return errors.New("cannot convert metric data to cgroups.Metrics or windows.Statistics") } switch context.String(formatFlag) { @@ -87,24 +100,24 @@ w := tabwriter.NewWriter(os.Stdout, 1, 8, 4, ' ', 0) fmt.Fprintf(w, "ID\tTIMESTAMP\t\n") fmt.Fprintf(w, "%s\t%s\t\n\n", metric.ID, metric.Timestamp) - - fmt.Fprintf(w, "METRIC\tVALUE\t\n") - if data.Memory != nil { - fmt.Fprintf(w, "memory.usage_in_bytes\t%d\t\n", data.Memory.Usage.Usage) - fmt.Fprintf(w, "memory.limit_in_bytes\t%d\t\n", data.Memory.Usage.Limit) - fmt.Fprintf(w, "memory.stat.cache\t%d\t\n", data.Memory.TotalCache) - } - if data.CPU != nil { - fmt.Fprintf(w, "cpuacct.usage\t%d\t\n", data.CPU.Usage.Total) - fmt.Fprintf(w, "cpuacct.usage_percpu\t%v\t\n", data.CPU.Usage.PerCPU) - } - if data.Pids != nil { - fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) - fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) + if data != nil { + printCgroupMetricsTable(w, data) + } else if data2 != nil { + printCgroup2MetricsTable(w, data2) + } else { + if windowsStats.GetLinux() != nil { + printCgroupMetricsTable(w, windowsStats.GetLinux()) + } else if windowsStats.GetWindows() != nil { + printWindowsContainerStatistics(w, windowsStats.GetWindows()) + } + // Print VM stats if its isolated + if windowsStats.VM != nil { + printWindowsVMStatistics(w, windowsStats.VM) + } } return w.Flush() case formatJSON: - marshaledJSON, err := json.MarshalIndent(data, "", " ") + marshaledJSON, err := json.MarshalIndent(anydata, "", " ") if err != nil { return err } @@ -115,3 +128,83 @@ } }, } + +func printCgroupMetricsTable(w *tabwriter.Writer, data *v1.Metrics) { + fmt.Fprintf(w, "METRIC\tVALUE\t\n") + if data.Memory != nil { + fmt.Fprintf(w, "memory.usage_in_bytes\t%d\t\n", data.Memory.Usage.Usage) + fmt.Fprintf(w, "memory.limit_in_bytes\t%d\t\n", data.Memory.Usage.Limit) + fmt.Fprintf(w, "memory.stat.cache\t%d\t\n", data.Memory.TotalCache) + } + if data.CPU != nil { + fmt.Fprintf(w, "cpuacct.usage\t%d\t\n", data.CPU.Usage.Total) + fmt.Fprintf(w, "cpuacct.usage_percpu\t%v\t\n", data.CPU.Usage.PerCPU) + } + if data.Pids != nil { + fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) + fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) + } +} + +func printCgroup2MetricsTable(w *tabwriter.Writer, data *v2.Metrics) { + fmt.Fprintf(w, "METRIC\tVALUE\t\n") + if data.Pids != nil { + fmt.Fprintf(w, "pids.current\t%v\t\n", data.Pids.Current) + fmt.Fprintf(w, "pids.limit\t%v\t\n", data.Pids.Limit) + } + if data.CPU != nil { + fmt.Fprintf(w, "cpu.usage_usec\t%v\t\n", data.CPU.UsageUsec) + fmt.Fprintf(w, "cpu.user_usec\t%v\t\n", data.CPU.UserUsec) + fmt.Fprintf(w, "cpu.system_usec\t%v\t\n", data.CPU.SystemUsec) + fmt.Fprintf(w, "cpu.nr_periods\t%v\t\n", data.CPU.NrPeriods) + fmt.Fprintf(w, "cpu.nr_throttled\t%v\t\n", data.CPU.NrThrottled) + fmt.Fprintf(w, "cpu.throttled_usec\t%v\t\n", data.CPU.ThrottledUsec) + } + if data.Memory != nil { + fmt.Fprintf(w, "memory.usage\t%v\t\n", data.Memory.Usage) + fmt.Fprintf(w, "memory.usage_limit\t%v\t\n", data.Memory.UsageLimit) + fmt.Fprintf(w, "memory.swap_usage\t%v\t\n", data.Memory.SwapUsage) + fmt.Fprintf(w, "memory.swap_limit\t%v\t\n", data.Memory.SwapLimit) + } +} + +func printWindowsContainerStatistics(w *tabwriter.Writer, stats *wstats.WindowsContainerStatistics) { + fmt.Fprintf(w, "METRIC\tVALUE\t\n") + fmt.Fprintf(w, "timestamp\t%s\t\n", stats.Timestamp) + fmt.Fprintf(w, "start_time\t%s\t\n", stats.ContainerStartTime) + fmt.Fprintf(w, "uptime_ns\t%d\t\n", stats.UptimeNS) + if stats.Processor != nil { + fmt.Fprintf(w, "cpu.total_runtime_ns\t%d\t\n", stats.Processor.TotalRuntimeNS) + fmt.Fprintf(w, "cpu.runtime_user_ns\t%d\t\n", stats.Processor.RuntimeUserNS) + fmt.Fprintf(w, "cpu.runtime_kernel_ns\t%d\t\n", stats.Processor.RuntimeKernelNS) + } + if stats.Memory != nil { + fmt.Fprintf(w, "memory.commit_bytes\t%d\t\n", stats.Memory.MemoryUsageCommitBytes) + fmt.Fprintf(w, "memory.commit_peak_bytes\t%d\t\n", stats.Memory.MemoryUsageCommitPeakBytes) + fmt.Fprintf(w, "memory.private_working_set_bytes\t%d\t\n", stats.Memory.MemoryUsagePrivateWorkingSetBytes) + } + if stats.Storage != nil { + fmt.Fprintf(w, "storage.read_count_normalized\t%d\t\n", stats.Storage.ReadCountNormalized) + fmt.Fprintf(w, "storage.read_size_bytes\t%d\t\n", stats.Storage.ReadSizeBytes) + fmt.Fprintf(w, "storage.write_count_normalized\t%d\t\n", stats.Storage.WriteCountNormalized) + fmt.Fprintf(w, "storage.write_size_bytes\t%d\t\n", stats.Storage.WriteSizeBytes) + } +} + +func printWindowsVMStatistics(w *tabwriter.Writer, stats *wstats.VirtualMachineStatistics) { + fmt.Fprintf(w, "METRIC\tVALUE\t\n") + if stats.Processor != nil { + fmt.Fprintf(w, "vm.cpu.total_runtime_ns\t%d\t\n", stats.Processor.TotalRuntimeNS) + } + if stats.Memory != nil { + fmt.Fprintf(w, "vm.memory.working_set_bytes\t%d\t\n", stats.Memory.WorkingSetBytes) + fmt.Fprintf(w, "vm.memory.virtual_node_count\t%d\t\n", stats.Memory.VirtualNodeCount) + fmt.Fprintf(w, "vm.memory.available\t%d\t\n", stats.Memory.VmMemory.AvailableMemory) + fmt.Fprintf(w, "vm.memory.available_buffer\t%d\t\n", stats.Memory.VmMemory.AvailableMemoryBuffer) + fmt.Fprintf(w, "vm.memory.reserved\t%d\t\n", stats.Memory.VmMemory.ReservedMemory) + fmt.Fprintf(w, "vm.memory.assigned\t%d\t\n", stats.Memory.VmMemory.AssignedMemory) + fmt.Fprintf(w, "vm.memory.slp_active\t%t\t\n", stats.Memory.VmMemory.SlpActive) + fmt.Fprintf(w, "vm.memory.balancing_enabled\t%t\t\n", stats.Memory.VmMemory.BalancingEnabled) + fmt.Fprintf(w, "vm.memory.dm_operation_in_progress\t%t\t\n", stats.Memory.VmMemory.DmOperationInProgress) + } +} diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/start.go containerd-1.5.9/cmd/ctr/commands/tasks/start.go --- containerd-1.2.6/cmd/ctr/commands/tasks/start.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/start.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,7 +28,7 @@ var startCommand = cli.Command{ Name: "start", - Usage: "start a container that have been created", + Usage: "start a container that has been created", ArgsUsage: "CONTAINER", Flags: []cli.Flag{ cli.BoolFlag{ @@ -36,6 +36,10 @@ Usage: "send all IO to /dev/null", }, cli.StringFlag{ + Name: "log-uri", + Usage: "log uri", + }, + cli.StringFlag{ Name: "fifo-dir", Usage: "directory used for storing IO FIFOs", }, @@ -85,7 +89,7 @@ } } - task, err := NewTask(ctx, client, container, "", con, context.Bool("null-io"), ioOpts, opts...) + task, err := NewTask(ctx, client, container, "", con, context.Bool("null-io"), context.String("log-uri"), ioOpts, opts...) if err != nil { return err } diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/tasks_unix.go containerd-1.5.9/cmd/ctr/commands/tasks/tasks_unix.go --- containerd-1.2.6/cmd/ctr/commands/tasks/tasks_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/tasks_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ import ( gocontext "context" + "net/url" "os" "os/signal" @@ -67,8 +68,10 @@ } // NewTask creates a new task -func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, con console.Console, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { - stdio := cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...) +func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, checkpoint string, con console.Console, nullIO bool, logURI string, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { + stdinC := &stdinCloser{ + stdin: os.Stdin, + } if checkpoint != "" { im, err := client.GetImage(ctx, checkpoint) if err != nil { @@ -76,17 +79,31 @@ } opts = append(opts, containerd.WithTaskCheckpoint(im)) } - ioCreator := stdio + var ioCreator cio.Creator if con != nil { - ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, nil), cio.WithTerminal}, ioOpts...)...) - } - if nullIO { - if con != nil { + if nullIO { return nil, errors.New("tty and null-io cannot be used together") } + ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, nil), cio.WithTerminal}, ioOpts...)...) + } else if nullIO { ioCreator = cio.NullIO + } else if logURI != "" { + u, err := url.Parse(logURI) + if err != nil { + return nil, err + } + ioCreator = cio.LogURI(u) + } else { + ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(stdinC, os.Stdout, os.Stderr)}, ioOpts...)...) + } + t, err := container.NewTask(ctx, ioCreator, opts...) + if err != nil { + return nil, err + } + stdinC.closer = func() { + t.CloseIO(ctx, containerd.WithStdinCloser) } - return container.NewTask(ctx, ioCreator, opts...) + return t, nil } func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts { diff -Nru containerd-1.2.6/cmd/ctr/commands/tasks/tasks_windows.go containerd-1.5.9/cmd/ctr/commands/tasks/tasks_windows.go --- containerd-1.2.6/cmd/ctr/commands/tasks/tasks_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/tasks/tasks_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( gocontext "context" + "net/url" "time" "github.com/containerd/console" @@ -58,15 +59,21 @@ } // NewTask creates a new task -func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, _ string, con console.Console, nullIO bool, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { +func NewTask(ctx gocontext.Context, client *containerd.Client, container containerd.Container, _ string, con console.Console, nullIO bool, logURI string, ioOpts []cio.Opt, opts ...containerd.NewTaskOpts) (containerd.Task, error) { var ioCreator cio.Creator if con != nil { if nullIO { return nil, errors.New("tty and null-io cannot be used together") } - ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, con), cio.WithTerminal}, ioOpts...)...) + ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStreams(con, con, nil), cio.WithTerminal}, ioOpts...)...) } else if nullIO { ioCreator = cio.NullIO + } else if logURI != "" { + u, err := url.Parse(logURI) + if err != nil { + return nil, err + } + ioCreator = cio.LogURI(u) } else { ioCreator = cio.NewCreator(append([]cio.Opt{cio.WithStdio}, ioOpts...)...) } diff -Nru containerd-1.2.6/cmd/ctr/commands/utils.go containerd-1.5.9/cmd/ctr/commands/utils.go --- containerd-1.2.6/cmd/ctr/commands/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +// IntToInt32Array converts an array of int's to int32's +func IntToInt32Array(in []int) []int32 { + var ret []int32 + + for _, v := range in { + ret = append(ret, int32(v)) + } + return ret +} diff -Nru containerd-1.2.6/cmd/ctr/commands/version/version.go containerd-1.5.9/cmd/ctr/commands/version/version.go --- containerd-1.2.6/cmd/ctr/commands/version/version.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/cmd/ctr/commands/version/version.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,6 +33,7 @@ fmt.Println("Client:") fmt.Println(" Version: ", version.Version) fmt.Println(" Revision:", version.Revision) + fmt.Println(" Go version:", version.GoVersion) fmt.Println("") client, ctx, cancel, err := commands.NewClient(context) if err != nil { @@ -46,6 +47,11 @@ fmt.Println("Server:") fmt.Println(" Version: ", v.Version) fmt.Println(" Revision:", v.Revision) + di, err := client.Server(ctx) + if err != nil { + return err + } + fmt.Println(" UUID:", di.UUID) if v.Version != version.Version { fmt.Fprintln(os.Stderr, "WARNING: version mismatch") } diff -Nru containerd-1.2.6/cmd/gen-manpages/main.go containerd-1.5.9/cmd/gen-manpages/main.go --- containerd-1.2.6/cmd/gen-manpages/main.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/cmd/gen-manpages/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,70 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/containerd/containerd/cmd/containerd/command" + "github.com/containerd/containerd/cmd/ctr/app" + "github.com/urfave/cli" +) + +func main() { + if err := run(); err != nil { + fmt.Fprint(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + flag.Parse() + apps := map[string]*cli.App{ + "containerd": command.App(), + "ctr": app.New(), + } + dir := flag.Arg(1) + + parts := strings.SplitN(flag.Arg(0), ".", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid name '%s': name does not contain man page section", flag.Arg(0)) + } + name, section := parts[0], parts[1] + + appName, ok := apps[name] + if !ok { + return fmt.Errorf("invalid application '%s'", name) + } + + // clear out the usage as we use banners that do not display in man pages + appName.Usage = "" + appName.ToMan() + data, err := appName.ToMan() + if err != nil { + return err + } + _ = os.MkdirAll(dir, os.ModePerm) + if err := ioutil.WriteFile(filepath.Join(dir, fmt.Sprintf("%s.%s", name, section)), []byte(data), 0644); err != nil { + return err + } + return nil +} diff -Nru containerd-1.2.6/codecov.yml containerd-1.5.9/codecov.yml --- containerd-1.2.6/codecov.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/codecov.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +comment: false diff -Nru containerd-1.2.6/container_checkpoint_opts.go containerd-1.5.9/container_checkpoint_opts.go --- containerd-1.2.6/container_checkpoint_opts.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/container_checkpoint_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,156 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "bytes" + "context" + "fmt" + "runtime" + + tasks "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/diff" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/rootfs" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/typeurl" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +var ( + // ErrCheckpointRWUnsupported is returned if the container runtime does not support checkpoint + ErrCheckpointRWUnsupported = errors.New("rw checkpoint is only supported on v2 runtimes") + // ErrMediaTypeNotFound returns an error when a media type in the manifest is unknown + ErrMediaTypeNotFound = errors.New("media type not found") +) + +// CheckpointOpts are options to manage the checkpoint operation +type CheckpointOpts func(context.Context, *Client, *containers.Container, *imagespec.Index, *options.CheckpointOptions) error + +// WithCheckpointImage includes the container image in the checkpoint +func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { + ir, err := client.ImageService().Get(ctx, c.Image) + if err != nil { + return err + } + index.Manifests = append(index.Manifests, ir.Target) + return nil +} + +// WithCheckpointTask includes the running task +func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { + any, err := typeurl.MarshalAny(copts) + if err != nil { + return nil + } + task, err := client.TaskService().Checkpoint(ctx, &tasks.CheckpointTaskRequest{ + ContainerID: c.ID, + Options: any, + }) + if err != nil { + return err + } + for _, d := range task.Descriptors { + platformSpec := platforms.DefaultSpec() + index.Manifests = append(index.Manifests, imagespec.Descriptor{ + MediaType: d.MediaType, + Size: d.Size_, + Digest: d.Digest, + Platform: &platformSpec, + Annotations: d.Annotations, + }) + } + // save copts + data, err := any.Marshal() + if err != nil { + return err + } + r := bytes.NewReader(data) + desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointOptions, c.ID+"-checkpoint-options", r) + if err != nil { + return err + } + desc.Platform = &imagespec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, + } + index.Manifests = append(index.Manifests, desc) + return nil +} + +// WithCheckpointRuntime includes the container runtime info +func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { + if c.Runtime.Options != nil { + data, err := c.Runtime.Options.Marshal() + if err != nil { + return err + } + r := bytes.NewReader(data) + desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeOptions, c.ID+"-runtime-options", r) + if err != nil { + return err + } + desc.Platform = &imagespec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, + } + index.Manifests = append(index.Manifests, desc) + } + return nil +} + +// WithCheckpointRW includes the rw in the checkpoint +func WithCheckpointRW(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { + diffOpts := []diff.Opt{ + diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", c.SnapshotKey)), + } + rw, err := rootfs.CreateDiff(ctx, + c.SnapshotKey, + client.SnapshotService(c.Snapshotter), + client.DiffService(), + diffOpts..., + ) + if err != nil { + return err + + } + rw.Platform = &imagespec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, + } + index.Manifests = append(index.Manifests, rw) + return nil +} + +// WithCheckpointTaskExit causes the task to exit after checkpoint +func WithCheckpointTaskExit(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { + copts.Exit = true + return nil +} + +// GetIndexByMediaType returns the index in a manifest for the specified media type +func GetIndexByMediaType(index *imagespec.Index, mt string) (*imagespec.Descriptor, error) { + for _, d := range index.Manifests { + if d.MediaType == mt { + return &d, nil + } + } + return nil, ErrMediaTypeNotFound +} diff -Nru containerd-1.2.6/container_checkpoint_test.go containerd-1.5.9/container_checkpoint_test.go --- containerd-1.2.6/container_checkpoint_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container_checkpoint_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,363 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "bytes" - "fmt" - "io" - "strings" - "sync" - "syscall" - "testing" - - "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/runtime/linux/runctypes" - "github.com/containerd/containerd/runtime/v2/runc/options" -) - -func TestCheckpointRestorePTY(t *testing.T) { - if !supportsCriu { - t.Skip("system does not have criu installed") - } - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), - oci.WithProcessArgs("sh", "-c", "read A; echo z${A}z"), - oci.WithTTY)) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - direct, err := newDirectIO(ctx, true) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - checkpoint, err := task.Checkpoint(ctx, withExit(client)) - if err != nil { - t.Fatal(err) - } - - <-statusC - - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - direct.Delete() - direct, err = newDirectIO(ctx, true) - if err != nil { - t.Fatal(err) - } - - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - if task, err = container.NewTask(ctx, direct.IOCreate, - WithTaskCheckpoint(checkpoint)); err != nil { - t.Fatal(err) - } - - statusC, err = task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - direct.Stdin.Write([]byte("hello\n")) - <-statusC - wg.Wait() - - if err := direct.Close(); err != nil { - t.Error(err) - } - - out := buf.String() - if !strings.Contains(fmt.Sprintf("%#q", out), `zhelloz`) { - t.Fatalf(`expected \x00 in output: %s`, out) - } -} - -func TestCheckpointRestore(t *testing.T) { - if !supportsCriu { - t.Skip("system does not have criu installed") - } - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - checkpoint, err := task.Checkpoint(ctx, withExit(client)) - if err != nil { - t.Fatal(err) - } - - <-statusC - - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - if task, err = container.NewTask(ctx, empty(), WithTaskCheckpoint(checkpoint)); err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err = task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - <-statusC -} - -func TestCheckpointRestoreNewContainer(t *testing.T) { - if !supportsCriu { - t.Skip("system does not have criu installed") - } - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - id := t.Name() - ctx, cancel := testContext() - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - checkpoint, err := task.Checkpoint(ctx, withExit(client)) - if err != nil { - t.Fatal(err) - } - - <-statusC - - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { - t.Fatal(err) - } - if container, err = client.NewContainer(ctx, id, WithCheckpoint(checkpoint, id)); err != nil { - t.Fatal(err) - } - if task, err = container.NewTask(ctx, empty(), WithTaskCheckpoint(checkpoint)); err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err = task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - <-statusC -} - -func TestCheckpointLeaveRunning(t *testing.T) { - if testing.Short() { - t.Skip() - } - if !supportsCriu { - t.Skip("system does not have criu installed") - } - client, err := New(address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if _, err := task.Checkpoint(ctx); err != nil { - t.Fatal(err) - } - - status, err := task.Status(ctx) - if err != nil { - t.Fatal(err) - } - if status.Status != Running { - t.Fatalf("expected status %q but received %q", Running, status) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC -} - -func withExit(client *Client) CheckpointTaskOpts { - return func(r *CheckpointTaskInfo) error { - switch client.runtime { - case "io.containerd.runc.v1": - r.Options = &options.CheckpointOptions{ - Exit: true, - } - default: - r.Options = &runctypes.CheckpointOptions{ - Exit: true, - } - } - return nil - } -} diff -Nru containerd-1.2.6/containerd.service containerd-1.5.9/containerd.service --- containerd-1.2.6/containerd.service 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/containerd.service 2022-01-05 17:30:58.000000000 +0000 @@ -1,14 +1,31 @@ +# Copyright The containerd Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + [Unit] Description=containerd container runtime Documentation=https://containerd.io -After=network.target +After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd +Type=notify Delegate=yes KillMode=process +Restart=always +RestartSec=5 # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity @@ -17,6 +34,7 @@ # Comment TasksMax if your systemd version does not supports it. # Only systemd 226 and above support this version. TasksMax=infinity +OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target diff -Nru containerd-1.2.6/container.go containerd-1.5.9/container.go --- containerd-1.2.6/container.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,21 +25,34 @@ "github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/api/types" + tasktypes "github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/containers" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/fifo" "github.com/containerd/typeurl" prototypes "github.com/gogo/protobuf/types" + ver "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/opencontainers/selinux/go-selinux/label" "github.com/pkg/errors" ) +const ( + checkpointImageNameLabel = "org.opencontainers.image.ref.name" + checkpointRuntimeNameLabel = "io.containerd.checkpoint.runtime" + checkpointSnapshotterNameLabel = "io.containerd.checkpoint.snapshotter" +) + // Container is a metadata object for container resources and task creation type Container interface { // ID identifies the container ID() string // Info returns the underlying container record type - Info(context.Context) (containers.Container, error) + Info(context.Context, ...InfoOpts) (containers.Container, error) // Delete removes the container Delete(context.Context, ...DeleteOpts) error // NewTask creates a new task based on the container metadata @@ -64,20 +77,24 @@ Extensions(context.Context) (map[string]prototypes.Any, error) // Update a container Update(context.Context, ...UpdateContainerOpts) error + // Checkpoint creates a checkpoint image of the current container + Checkpoint(context.Context, string, ...CheckpointOpts) (Image, error) } func containerFromRecord(client *Client, c containers.Container) *container { return &container{ - client: client, - id: c.ID, + client: client, + id: c.ID, + metadata: c, } } var _ = (Container)(&container{}) type container struct { - client *Client - id string + client *Client + id string + metadata containers.Container } // ID returns the container's unique id @@ -85,8 +102,22 @@ return c.id } -func (c *container) Info(ctx context.Context) (containers.Container, error) { - return c.get(ctx) +func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Container, error) { + i := &InfoConfig{ + // default to refreshing the container's local metadata + Refresh: true, + } + for _, o := range opts { + o(i) + } + if i.Refresh { + metadata, err := c.get(ctx) + if err != nil { + return c.metadata, err + } + c.metadata = metadata + } + return c.metadata, nil } func (c *container) Extensions(ctx context.Context) (map[string]prototypes.Any, error) { @@ -205,11 +236,25 @@ } // get the rootfs from the snapshotter and add it to the request - mounts, err := c.client.SnapshotService(r.Snapshotter).Mounts(ctx, r.SnapshotKey) + s, err := c.client.getSnapshotter(ctx, r.Snapshotter) + if err != nil { + return nil, err + } + mounts, err := s.Mounts(ctx, r.SnapshotKey) + if err != nil { + return nil, err + } + spec, err := c.Spec(ctx) if err != nil { return nil, err } for _, m := range mounts { + if spec.Linux != nil && spec.Linux.MountLabel != "" { + context := label.FormatMountLabel("", spec.Linux.MountLabel) + if context != "" { + m.Options = append(m.Options, context) + } + } request.Rootfs = append(request.Rootfs, &types.Mount{ Type: m.Type, Source: m.Source, @@ -217,7 +262,9 @@ }) } } - var info TaskInfo + info := TaskInfo{ + runtime: r.Runtime.Name, + } for _, o := range opts { if err := o(ctx, c.client, &info); err != nil { return nil, err @@ -243,6 +290,7 @@ client: c.client, io: i, id: c.id, + c: c, } if info.Checkpoint != nil { request.Checkpoint = info.Checkpoint @@ -272,6 +320,70 @@ return nil } +func (c *container) Checkpoint(ctx context.Context, ref string, opts ...CheckpointOpts) (Image, error) { + index := &ocispec.Index{ + Versioned: ver.Versioned{ + SchemaVersion: 2, + }, + Annotations: make(map[string]string), + } + copts := &options.CheckpointOptions{ + Exit: false, + OpenTcp: false, + ExternalUnixSockets: false, + Terminal: false, + FileLocks: true, + EmptyNamespaces: nil, + } + info, err := c.Info(ctx) + if err != nil { + return nil, err + } + + img, err := c.Image(ctx) + if err != nil { + return nil, err + } + + ctx, done, err := c.client.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + // add image name to manifest + index.Annotations[checkpointImageNameLabel] = img.Name() + // add runtime info to index + index.Annotations[checkpointRuntimeNameLabel] = info.Runtime.Name + // add snapshotter info to index + index.Annotations[checkpointSnapshotterNameLabel] = info.Snapshotter + + // process remaining opts + for _, o := range opts { + if err := o(ctx, c.client, &info, index, copts); err != nil { + err = errdefs.FromGRPC(err) + if !errdefs.IsAlreadyExists(err) { + return nil, err + } + } + } + + desc, err := writeIndex(ctx, index, c.client, c.ID()+"index") + if err != nil { + return nil, err + } + i := images.Image{ + Name: ref, + Target: desc, + } + checkpoint, err := c.client.ImageService().Create(ctx, i) + if err != nil { + return nil, err + } + + return NewImage(c.client, checkpoint), nil +} + func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, error) { response, err := c.client.TaskService().Get(ctx, &tasks.GetRequest{ ContainerID: c.id, @@ -284,7 +396,9 @@ return nil, err } var i cio.IO - if ioAttach != nil { + if ioAttach != nil && response.Process.Status != tasktypes.StatusUnknown { + // Do not attach IO for task in unknown state, because there + // are no fifo paths anyway. if i, err = attachExistingIO(response, ioAttach); err != nil { return nil, err } @@ -294,6 +408,7 @@ io: i, id: response.Process.ID, pid: response.Process.Pid, + c: c, } return t, nil } @@ -310,14 +425,33 @@ // loadFifos loads the containers fifos func loadFifos(response *tasks.GetResponse) *cio.FIFOSet { - path := getFifoDir([]string{ + fifos := []string{ response.Process.Stdin, response.Process.Stdout, response.Process.Stderr, - }) + } closer := func() error { - return os.RemoveAll(path) + var ( + err error + dirs = map[string]struct{}{} + ) + for _, f := range fifos { + if isFifo, _ := fifo.IsFifo(f); isFifo { + if rerr := os.Remove(f); err == nil { + err = rerr + } + dirs[filepath.Dir(f)] = struct{}{} + } + } + for dir := range dirs { + // we ignore errors here because we don't + // want to remove the directory if it isn't + // empty + os.Remove(dir) + } + return err } + return cio.NewFIFOSet(cio.Config{ Stdin: response.Process.Stdin, Stdout: response.Process.Stdout, @@ -325,14 +459,3 @@ Terminal: response.Process.Terminal, }, closer) } - -// getFifoDir looks for any non-empty path for a stdio fifo -// and returns the dir for where it is located -func getFifoDir(paths []string) string { - for _, p := range paths { - if p != "" { - return filepath.Dir(p) - } - } - return "" -} diff -Nru containerd-1.2.6/container_linux_test.go containerd-1.5.9/container_linux_test.go --- containerd-1.2.6/container_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container_linux_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,1532 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "bytes" - "context" - "fmt" - "io" - "io/ioutil" - "os/exec" - "runtime" - "strings" - "sync" - "syscall" - "testing" - "time" - - "github.com/containerd/cgroups" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/runtime/linux/runctypes" - "github.com/containerd/containerd/runtime/v2/runc/options" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "golang.org/x/sys/unix" -) - -func TestTaskUpdate(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - limit := int64(32 * 1024 * 1024) - memory := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Linux.Resources.Memory = &specs.LinuxMemory{ - Limit: &limit, - } - return nil - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"), memory)) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - // check that the task has a limit of 32mb - cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid()))) - if err != nil { - t.Fatal(err) - } - stat, err := cgroup.Stat(cgroups.IgnoreNotExist) - if err != nil { - t.Fatal(err) - } - if int64(stat.Memory.Usage.Limit) != limit { - t.Fatalf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) - } - limit = 64 * 1024 * 1024 - if err := task.Update(ctx, WithResources(&specs.LinuxResources{ - Memory: &specs.LinuxMemory{ - Limit: &limit, - }, - })); err != nil { - t.Error(err) - } - // check that the task has a limit of 64mb - if stat, err = cgroup.Stat(cgroups.IgnoreNotExist); err != nil { - t.Fatal(err) - } - if int64(stat.Memory.Usage.Limit) != limit { - t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) - } - if err := task.Kill(ctx, unix.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC -} - -func TestShimInCgroup(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - if client.runtime == "io.containerd.runc.v1" { - t.Skip() - } - - var ( - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - // create a cgroup for the shim to use - path := "/containerd/shim" - cg, err := cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{}) - if err != nil { - t.Fatal(err) - } - defer cg.Delete() - - task, err := container.NewTask(ctx, empty(), func(_ context.Context, client *Client, r *TaskInfo) error { - r.Options = &runctypes.CreateOptions{ - ShimCgroup: path, - } - return nil - }) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - // check to see if the shim is inside the cgroup - processes, err := cg.Processes(cgroups.Devices, false) - if err != nil { - t.Fatal(err) - } - if len(processes) == 0 { - t.Errorf("created cgroup should have atleast one process inside: %d", len(processes)) - } - if err := task.Kill(ctx, unix.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC -} - -func TestDaemonRestart(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - var exitStatus ExitStatus - if err := ctrd.Restart(func() { - exitStatus = <-statusC - }); err != nil { - t.Fatal(err) - } - - if exitStatus.Error() == nil { - t.Errorf(`first task.Wait() should have failed with "transport is closing"`) - } - - waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) - serving, err := client.IsServing(waitCtx) - waitCancel() - if !serving { - t.Fatalf("containerd did not start within 2s: %v", err) - } - - statusC, err = task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC -} - -func TestContainerPTY(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithTTY, withProcessArgs("echo", "hello"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - direct, err := newDirectIO(ctx, true) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - status, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - <-status - wg.Wait() - - if err := direct.Close(); err != nil { - t.Error(err) - } - - out := buf.String() - if !strings.ContainsAny(fmt.Sprintf("%#q", out), `\x00`) { - t.Fatal(`expected \x00 in output`) - } -} - -func TestContainerAttach(t *testing.T) { - t.Parallel() - - if runtime.GOOS == "windows" { - // On windows, closing the write side of the pipe closes the read - // side, sending an EOF to it and preventing reopening it. - // Hence this test will always fails on windows - t.Skip("invalid logic on windows") - } - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat())) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - expected := "hello" + newLine - - direct, err := newDirectIO(ctx, false) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - status, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { - t.Error(err) - } - - // load the container and re-load the task - if container, err = client.LoadContainer(ctx, id); err != nil { - t.Fatal(err) - } - - if task, err = container.Task(ctx, direct.IOAttach); err != nil { - t.Fatal(err) - } - - if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { - t.Error(err) - } - - direct.Stdin.Close() - - if err := task.CloseIO(ctx, WithStdinCloser); err != nil { - t.Error(err) - } - - <-status - - wg.Wait() - if _, err := task.Delete(ctx); err != nil { - t.Error(err) - } - - output := buf.String() - - // we wrote the same thing after attach - expected = expected + expected - if output != expected { - t.Errorf("expected output %q but received %q", expected, output) - } -} - -func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) { - fifos, err := cio.NewFIFOSetInDir("", "", terminal) - if err != nil { - return nil, err - } - dio, err := cio.NewDirectIO(ctx, fifos) - if err != nil { - return nil, err - } - return &directIO{DirectIO: *dio}, nil -} - -type directIO struct { - cio.DirectIO -} - -// ioCreate returns IO available for use with task creation -func (f *directIO) IOCreate(id string) (cio.IO, error) { - return f, nil -} - -// ioAttach returns IO available for use with task attachment -func (f *directIO) IOAttach(set *cio.FIFOSet) (cio.IO, error) { - return f, nil -} - -func (f *directIO) Cancel() { - // nothing to cancel as all operations are handled externally -} - -// Close closes all open fds -func (f *directIO) Close() error { - err := f.Stdin.Close() - if err2 := f.Stdout.Close(); err == nil { - err = err2 - } - if err2 := f.Stderr.Close(); err == nil { - err = err2 - } - return err -} - -// Delete removes the underlying directory containing fifos -func (f *directIO) Delete() error { - return f.DirectIO.Close() -} - -func TestContainerUsername(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - direct, err := newDirectIO(ctx, false) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - // squid user in the alpine image has a uid of 31 - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithUsername("squid"), oci.WithProcessArgs("id", "-u")), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - <-statusC - - wg.Wait() - - output := strings.TrimSuffix(buf.String(), "\n") - if output != "31" { - t.Errorf("expected squid uid to be 31 but received %q", output) - } -} - -func TestContainerUser(t *testing.T) { - t.Parallel() - t.Run("UserNameAndGroupName", func(t *testing.T) { testContainerUser(t, "squid:squid", "31:31") }) - t.Run("UserIDAndGroupName", func(t *testing.T) { testContainerUser(t, "1001:squid", "1001:31") }) - t.Run("UserNameAndGroupID", func(t *testing.T) { testContainerUser(t, "squid:1002", "31:1002") }) - t.Run("UserIDAndGroupID", func(t *testing.T) { testContainerUser(t, "1001:1002", "1001:1002") }) -} - -func testContainerUser(t *testing.T, userstr, expectedOutput string) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = strings.Replace(t.Name(), "/", "_", -1) - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - direct, err := newDirectIO(ctx, false) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithUser(userstr), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - <-statusC - - wg.Wait() - - output := strings.TrimSuffix(buf.String(), "\n") - if output != expectedOutput { - t.Errorf("expected uid:gid to be %q, but received %q", expectedOutput, output) - } -} - -func TestContainerAttachProcess(t *testing.T) { - t.Parallel() - - if runtime.GOOS == "windows" { - // On windows, closing the write side of the pipe closes the read - // side, sending an EOF to it and preventing reopening it. - // Hence this test will always fails on windows - t.Skip("invalid logic on windows") - } - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - expected := "hello" + newLine - - // creating IO early for easy resource cleanup - direct, err := newDirectIO(ctx, false) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - status, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - processSpec := spec.Process - processSpec.Args = []string{"cat"} - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - processStatusC, err := process.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := process.Start(ctx); err != nil { - t.Fatal(err) - } - - if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { - t.Error(err) - } - - if process, err = task.LoadProcess(ctx, execID, direct.IOAttach); err != nil { - t.Fatal(err) - } - - if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { - t.Error(err) - } - - direct.Stdin.Close() - - if err := process.CloseIO(ctx, WithStdinCloser); err != nil { - t.Error(err) - } - - <-processStatusC - - wg.Wait() - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - - output := buf.String() - - // we wrote the same thing after attach - expected = expected + expected - if output != expected { - t.Errorf("expected output %q but received %q", expected, output) - } - <-status -} - -func TestContainerUserID(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - direct, err := newDirectIO(ctx, false) - if err != nil { - t.Fatal(err) - } - defer direct.Delete() - var ( - wg sync.WaitGroup - buf = bytes.NewBuffer(nil) - ) - wg.Add(1) - go func() { - defer wg.Done() - io.Copy(buf, direct.Stdout) - }() - - // adm user in the alpine image has a uid of 3 and gid of 4. - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithUserID(3), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, direct.IOCreate) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - <-statusC - - wg.Wait() - - output := strings.TrimSuffix(buf.String(), "\n") - if output != "3:4" { - t.Errorf("expected uid:gid to be 3:4, but received %q", output) - } -} - -func TestContainerKillAll(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), - withProcessArgs("sh", "-c", "top"), - oci.WithHostNamespace(specs.PIDNamespace), - ), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - stdout := bytes.NewBuffer(nil) - task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL, WithKillAll); err != nil { - t.Error(err) - } - - <-statusC - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } -} - -func TestDaemonRestartWithRunningShim(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - pid := task.Pid() - if pid < 1 { - t.Fatalf("invalid task pid %d", pid) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - var exitStatus ExitStatus - if err := ctrd.Restart(func() { - exitStatus = <-statusC - }); err != nil { - t.Fatal(err) - } - - if exitStatus.Error() == nil { - t.Errorf(`first task.Wait() should have failed with "transport is closing"`) - } - - waitCtx, cancel := context.WithTimeout(ctx, 1*time.Second) - c, err := ctrd.waitForStart(waitCtx) - cancel() - if err != nil { - t.Fatal(err) - } - c.Close() - - statusC, err = task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC - - if err := unix.Kill(int(pid), 0); err != unix.ESRCH { - t.Errorf("pid %d still exists", pid) - } -} - -func TestContainerRuntimeOptionsv1(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer( - ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), - WithRuntime("io.containerd.runtime.v1.linux", &runctypes.RuncOptions{Runtime: "no-runc"}), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err == nil { - t.Errorf("task creation should have failed") - task.Delete(ctx) - return - } - if !strings.Contains(err.Error(), `"no-runc"`) { - t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) - } -} - -func TestContainerRuntimeOptionsv2(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer( - ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), - WithRuntime("io.containerd.runc.v1", &options.Options{BinaryName: "no-runc"}), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err == nil { - t.Errorf("task creation should have failed") - task.Delete(ctx) - return - } - if !strings.Contains(err.Error(), `"no-runc"`) { - t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) - } -} - -func initContainerAndCheckChildrenDieOnKill(t *testing.T, opts ...oci.SpecOpts) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - opts = append(opts, oci.WithImageConfig(image)) - opts = append(opts, withProcessArgs("sh", "-c", "sleep 42; echo hi")) - - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(opts...), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - stdout := bytes.NewBuffer(nil) - task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - - // Give the shim time to reap the init process and kill the orphans - select { - case <-statusC: - case <-time.After(100 * time.Millisecond): - } - - b, err := exec.Command("ps", "ax").CombinedOutput() - if err != nil { - t.Fatal(err) - } - - if strings.Contains(string(b), "sleep 42") { - t.Fatalf("killing init didn't kill all its children:\n%v", string(b)) - } - - if _, err := task.Delete(ctx, WithProcessKill); err != nil { - t.Error(err) - } -} - -func TestContainerKillInitPidHost(t *testing.T) { - initContainerAndCheckChildrenDieOnKill(t, oci.WithHostNamespace(specs.PIDNamespace)) -} - -func TestContainerKillInitKillsChildWhenNotHostPid(t *testing.T) { - initContainerAndCheckChildrenDieOnKill(t) -} - -func TestUserNamespaces(t *testing.T) { - t.Parallel() - t.Run("WritableRootFS", func(t *testing.T) { testUserNamespaces(t, false) }) - // see #1373 and runc#1572 - t.Run("ReadonlyRootFS", func(t *testing.T) { testUserNamespaces(t, true) }) -} - -func checkUserNS(t *testing.T) { - cmd := exec.Command("true") - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWUSER, - } - - if err := cmd.Run(); err != nil { - t.Skip("User namespaces are unavailable") - } -} - -func testUserNamespaces(t *testing.T, readonlyRootFS bool) { - checkUserNS(t) - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = strings.Replace(t.Name(), "/", "-", -1) - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - opts := []NewContainerOpts{WithNewSpec(oci.WithImageConfig(image), - withExitStatus(7), - oci.WithUserNamespace(0, 1000, 10000), - )} - if readonlyRootFS { - opts = append([]NewContainerOpts{WithRemappedSnapshotView(id, image, 1000, 1000)}, opts...) - } else { - opts = append([]NewContainerOpts{WithRemappedSnapshot(id, image, 1000, 1000)}, opts...) - } - - container, err := client.NewContainer(ctx, id, opts...) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - var copts interface{} - if client.runtime == "io.containerd.runc.v1" { - copts = &options.Options{ - IoUid: 1000, - IoGid: 1000, - } - } else { - copts = &runctypes.CreateOptions{ - IoUid: 1000, - IoGid: 1000, - } - } - - task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio), func(_ context.Context, client *Client, r *TaskInfo) error { - r.Options = copts - return nil - }) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if pid := task.Pid(); pid < 1 { - t.Errorf("invalid task pid %d", pid) - } - if err := task.Start(ctx); err != nil { - t.Error(err) - task.Delete(ctx) - return - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 7 { - t.Errorf("expected status 7 from wait but received %d", code) - } - deleteStatus, err := task.Delete(ctx) - if err != nil { - t.Fatal(err) - } - if ec := deleteStatus.ExitCode(); ec != 7 { - t.Errorf("expected status 7 from delete but received %d", ec) - } -} - -func TestTaskResize(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - if err := task.Resize(ctx, 32, 32); err != nil { - t.Fatal(err) - } - task.Kill(ctx, syscall.SIGKILL) - <-statusC -} - -func TestContainerImage(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSpec(), WithImage(image)) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - i, err := container.Image(ctx) - if err != nil { - t.Fatal(err) - } - if i.Name() != image.Name() { - t.Fatalf("expected container image name %s but received %s", image.Name(), i.Name()) - } -} - -func TestContainerNoImage(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - container, err := client.NewContainer(ctx, id, WithNewSpec()) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - _, err = container.Image(ctx) - if err == nil { - t.Fatal("error should not be nil when container is created without an image") - } - if errors.Cause(err) != errdefs.ErrNotFound { - t.Fatalf("expected error to be %s but received %s", errdefs.ErrNotFound, err) - } -} - -func TestUIDNoGID(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - image, err := client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithUserID(1000))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - if uid := spec.Process.User.UID; uid != 1000 { - t.Fatalf("expected uid 1000 but received %d", uid) - } - if gid := spec.Process.User.GID; gid != 0 { - t.Fatalf("expected gid 0 but received %d", gid) - } -} - -func TestBindLowPortNonRoot(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000)), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 1 { - t.Errorf("expected status 1 from wait but received %d", code) - } - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } -} - -func TestBindLowPortNonOpt(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000), oci.WithAmbientCapabilities([]string{"CAP_NET_BIND_SERVICE"})), - ) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - go func() { - time.Sleep(2 * time.Second) - task.Kill(ctx, unix.SIGTERM) - }() - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - // 128 + sigterm - if code != 143 { - t.Errorf("expected status 143 from wait but received %d", code) - } - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } -} - -func TestContainerNoSTDIN(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(0))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, ioutil.Discard, ioutil.Discard))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 0 { - t.Errorf("expected status 0 from wait but received %d", code) - } -} diff -Nru containerd-1.2.6/container_opts.go containerd-1.5.9/container_opts.go --- containerd-1.2.6/container_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,14 +18,19 @@ import ( "context" + "encoding/json" + "fmt" "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/snapshots" "github.com/containerd/typeurl" "github.com/gogo/protobuf/types" "github.com/opencontainers/image-spec/identity" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -38,6 +43,15 @@ // UpdateContainerOpts allows the caller to set additional options when updating a container type UpdateContainerOpts func(ctx context.Context, client *Client, c *containers.Container) error +// InfoOpts controls how container metadata is fetched and returned +type InfoOpts func(*InfoConfig) + +// InfoConfig specifies how container metadata is fetched +type InfoConfig struct { + // Refresh will to a fetch of the latest container metadata + Refresh bool +} + // WithRuntime allows a user to specify the runtime name and additional options that should // be used to create tasks for the container func WithRuntime(name string, options interface{}) NewContainerOpts { @@ -68,7 +82,17 @@ } } -// WithContainerLabels adds the provided labels to the container +// WithImageName allows setting the image name as the base for the container +func WithImageName(n string) NewContainerOpts { + return func(ctx context.Context, _ *Client, c *containers.Container) error { + c.Image = n + return nil + } +} + +// WithContainerLabels sets the provided labels to the container. +// The existing labels are cleared. +// Use WithAdditionalContainerLabels to preserve the existing labels. func WithContainerLabels(labels map[string]string) NewContainerOpts { return func(_ context.Context, _ *Client, c *containers.Container) error { c.Labels = labels @@ -76,6 +100,54 @@ } } +// WithImageConfigLabels sets the image config labels on the container. +// The existing labels are cleared as this is expected to be the first +// operation in setting up a container's labels. Use WithAdditionalContainerLabels +// to add/overwrite the existing image config labels. +func WithImageConfigLabels(image Image) NewContainerOpts { + return func(ctx context.Context, _ *Client, c *containers.Container) error { + ic, err := image.Config(ctx) + if err != nil { + return err + } + var ( + ociimage v1.Image + config v1.ImageConfig + ) + switch ic.MediaType { + case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config: + p, err := content.ReadBlob(ctx, image.ContentStore(), ic) + if err != nil { + return err + } + + if err := json.Unmarshal(p, &ociimage); err != nil { + return err + } + config = ociimage.Config + default: + return fmt.Errorf("unknown image config media type %s", ic.MediaType) + } + c.Labels = config.Labels + return nil + } +} + +// WithAdditionalContainerLabels adds the provided labels to the container +// The existing labels are preserved as long as they do not conflict with the added labels. +func WithAdditionalContainerLabels(labels map[string]string) NewContainerOpts { + return func(_ context.Context, _ *Client, c *containers.Container) error { + if c.Labels == nil { + c.Labels = labels + return nil + } + for k, v := range labels { + c.Labels[k] = v + } + return nil + } +} + // WithImageStopSignal sets a well-known containerd label (StopSignalLabel) // on the container for storing the stop signal specified in the OCI image // config @@ -106,9 +178,17 @@ // WithSnapshot uses an existing root filesystem for the container func WithSnapshot(id string) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - setSnapshotterIfEmpty(c) // check that the snapshot exists, if not, fail on creation - if _, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, id); err != nil { + var err error + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } + s, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } + if _, err := s.Mounts(ctx, id); err != nil { return err } c.SnapshotKey = id @@ -118,15 +198,23 @@ // WithNewSnapshot allocates a new snapshot to be used by the container as the // root filesystem in read-write mode -func WithNewSnapshot(id string, i Image) NewContainerOpts { +func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) + diffIDs, err := i.RootFS(ctx) if err != nil { return err } - setSnapshotterIfEmpty(c) + parent := identity.ChainID(diffIDs).String() - if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent); err != nil { + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } + s, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } + if _, err := s.Prepare(ctx, id, parent, opts...); err != nil { return err } c.SnapshotKey = id @@ -141,22 +229,36 @@ if c.Snapshotter == "" { return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter must be set to cleanup rootfs snapshot") } - return client.SnapshotService(c.Snapshotter).Remove(ctx, c.SnapshotKey) + s, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } + if err := s.Remove(ctx, c.SnapshotKey); err != nil && !errdefs.IsNotFound(err) { + return err + } } return nil } // WithNewSnapshotView allocates a new snapshot to be used by the container as the // root filesystem in read-only mode -func WithNewSnapshotView(id string, i Image) NewContainerOpts { +func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) + diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) if err != nil { return err } - setSnapshotterIfEmpty(c) + parent := identity.ChainID(diffIDs).String() - if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent); err != nil { + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } + s, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } + if _, err := s.View(ctx, id, parent, opts...); err != nil { return err } c.SnapshotKey = id @@ -165,12 +267,6 @@ } } -func setSnapshotterIfEmpty(c *containers.Container) { - if c.Snapshotter == "" { - c.Snapshotter = DefaultSnapshotter - } -} - // WithContainerExtension appends extension data to the container object. // Use this to decorate the container object with additional data for the client // integration. @@ -185,7 +281,7 @@ any, err := typeurl.MarshalAny(extension) if err != nil { - if errors.Cause(err) == typeurl.ErrNotFound { + if errors.Is(err, typeurl.ErrNotFound) { return errors.Wrapf(err, "extension %q is not registered with the typeurl package, see `typeurl.Register`", name) } return errors.Wrap(err, "error marshalling extension") @@ -223,3 +319,8 @@ return err } } + +// WithoutRefreshedMetadata will use the current metadata attached to the container object +func WithoutRefreshedMetadata(i *InfoConfig) { + i.Refresh = false +} diff -Nru containerd-1.2.6/container_opts_unix.go containerd-1.5.9/container_opts_unix.go --- containerd-1.2.6/container_opts_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container_opts_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,81 +26,11 @@ "syscall" "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" - "github.com/gogo/protobuf/proto" - protobuf "github.com/gogo/protobuf/types" "github.com/opencontainers/image-spec/identity" - "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" ) -// WithCheckpoint allows a container to be created from the checkpointed information -// provided by the descriptor. The image, snapshot, and runtime specifications are -// restored on the container -func WithCheckpoint(im Image, snapshotKey string) NewContainerOpts { - // set image and rw, and spec - return func(ctx context.Context, client *Client, c *containers.Container) error { - var ( - desc = im.Target() - store = client.ContentStore() - ) - index, err := decodeIndex(ctx, store, desc) - if err != nil { - return err - } - var rw *v1.Descriptor - for _, m := range index.Manifests { - switch m.MediaType { - case v1.MediaTypeImageLayer: - fk := m - rw = &fk - case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList: - config, err := images.Config(ctx, store, m, platforms.Default()) - if err != nil { - return errors.Wrap(err, "unable to resolve image config") - } - diffIDs, err := images.RootFS(ctx, store, config) - if err != nil { - return errors.Wrap(err, "unable to get rootfs") - } - setSnapshotterIfEmpty(c) - if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, snapshotKey, identity.ChainID(diffIDs).String()); err != nil { - if !errdefs.IsAlreadyExists(err) { - return err - } - } - c.Image = index.Annotations["image.name"] - case images.MediaTypeContainerd1CheckpointConfig: - data, err := content.ReadBlob(ctx, store, m) - if err != nil { - return errors.Wrap(err, "unable to read checkpoint config") - } - var any protobuf.Any - if err := proto.Unmarshal(data, &any); err != nil { - return err - } - c.Spec = &any - } - } - if rw != nil { - // apply the rw snapshot to the new rw layer - mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, snapshotKey) - if err != nil { - return errors.Wrapf(err, "unable to get mounts for %s", snapshotKey) - } - if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil { - return errors.Wrap(err, "unable to apply rw diff") - } - } - c.SnapshotKey = snapshotKey - return nil - } -} - // WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the // filesystem to be used by a container with user namespaces func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts { @@ -114,18 +44,23 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) + diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) if err != nil { return err } - setSnapshotterIfEmpty(c) - var ( - snapshotter = client.SnapshotService(c.Snapshotter) - parent = identity.ChainID(diffIDs).String() - usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) + parent = identity.ChainID(diffIDs).String() + usernsID = fmt.Sprintf("%s-%d-%d", parent, uid, gid) ) + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } + snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } if _, err := snapshotter.Stat(ctx, usernsID); err == nil { if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil { c.SnapshotKey = id diff -Nru containerd-1.2.6/container_restore_opts.go containerd-1.5.9/container_restore_opts.go --- containerd-1.2.6/container_restore_opts.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/container_restore_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,149 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "context" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/gogo/protobuf/proto" + ptypes "github.com/gogo/protobuf/types" + "github.com/opencontainers/image-spec/identity" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +var ( + // ErrImageNameNotFoundInIndex is returned when the image name is not found in the index + ErrImageNameNotFoundInIndex = errors.New("image name not found in index") + // ErrRuntimeNameNotFoundInIndex is returned when the runtime is not found in the index + ErrRuntimeNameNotFoundInIndex = errors.New("runtime not found in index") + // ErrSnapshotterNameNotFoundInIndex is returned when the snapshotter is not found in the index + ErrSnapshotterNameNotFoundInIndex = errors.New("snapshotter not found in index") +) + +// RestoreOpts are options to manage the restore operation +type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) NewContainerOpts + +// WithRestoreImage restores the image for the container +func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts { + return func(ctx context.Context, client *Client, c *containers.Container) error { + name, ok := index.Annotations[checkpointImageNameLabel] + if !ok || name == "" { + return ErrRuntimeNameNotFoundInIndex + } + snapshotter, ok := index.Annotations[checkpointSnapshotterNameLabel] + if !ok || name == "" { + return ErrSnapshotterNameNotFoundInIndex + } + i, err := client.GetImage(ctx, name) + if err != nil { + return err + } + + diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) + if err != nil { + return err + } + parent := identity.ChainID(diffIDs).String() + if _, err := client.SnapshotService(snapshotter).Prepare(ctx, id, parent); err != nil { + return err + } + c.Image = i.Name() + c.SnapshotKey = id + c.Snapshotter = snapshotter + return nil + } +} + +// WithRestoreRuntime restores the runtime for the container +func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts { + return func(ctx context.Context, client *Client, c *containers.Container) error { + name, ok := index.Annotations[checkpointRuntimeNameLabel] + if !ok { + return ErrRuntimeNameNotFoundInIndex + } + + // restore options if present + m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions) + if err != nil { + if err != ErrMediaTypeNotFound { + return err + } + } + var options ptypes.Any + if m != nil { + store := client.ContentStore() + data, err := content.ReadBlob(ctx, store, *m) + if err != nil { + return errors.Wrap(err, "unable to read checkpoint runtime") + } + if err := proto.Unmarshal(data, &options); err != nil { + return err + } + } + + c.Runtime = containers.RuntimeInfo{ + Name: name, + Options: &options, + } + return nil + } +} + +// WithRestoreSpec restores the spec from the checkpoint for the container +func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts { + return func(ctx context.Context, client *Client, c *containers.Container) error { + m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig) + if err != nil { + return err + } + store := client.ContentStore() + data, err := content.ReadBlob(ctx, store, *m) + if err != nil { + return errors.Wrap(err, "unable to read checkpoint config") + } + var any ptypes.Any + if err := proto.Unmarshal(data, &any); err != nil { + return err + } + c.Spec = &any + return nil + } +} + +// WithRestoreRW restores the rw layer from the checkpoint for the container +func WithRestoreRW(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts { + return func(ctx context.Context, client *Client, c *containers.Container) error { + // apply rw layer + rw, err := GetIndexByMediaType(index, imagespec.MediaTypeImageLayerGzip) + if err != nil { + return err + } + mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, c.SnapshotKey) + if err != nil { + return err + } + + if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil { + return err + } + return nil + } +} diff -Nru containerd-1.2.6/containers/containers.go containerd-1.5.9/containers/containers.go --- containerd-1.2.6/containers/containers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/containers/containers.go 2022-01-05 17:30:58.000000000 +0000 @@ -49,7 +49,7 @@ // This property is required and immutable. Runtime RuntimeInfo - // Spec should carry the the runtime specification used to implement the + // Spec should carry the runtime specification used to implement the // container. // // This field is required but mutable. @@ -86,6 +86,10 @@ // Store interacts with the underlying container storage type Store interface { + // Get a container using the id. + // + // Container object is returned on success. If the id is not known to the + // store, an error will be returned. Get(ctx context.Context, id string) (Container, error) // List returns containers that match one or more of the provided filters. diff -Nru containerd-1.2.6/container_test.go containerd-1.5.9/container_test.go --- containerd-1.2.6/container_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/container_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,1530 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "bytes" - "context" - "io" - "io/ioutil" - "os" - "os/exec" - "runtime" - "strings" - "syscall" - "testing" - "time" - - // Register the typeurl - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" - _ "github.com/containerd/containerd/runtime" - "github.com/containerd/typeurl" - specs "github.com/opencontainers/runtime-spec/specs-go" - - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/windows/hcsshimtypes" - gogotypes "github.com/gogo/protobuf/types" -) - -func empty() cio.Creator { - // TODO (@mlaventure) windows searches for pipes - // when none are provided - if runtime.GOOS == "windows" { - return cio.NewCreator(cio.WithStdio) - } - return cio.NullIO -} - -func TestContainerList(t *testing.T) { - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - - containers, err := client.Containers(ctx) - if err != nil { - t.Fatalf("container list returned error %v", err) - } - if len(containers) != 0 { - t.Errorf("expected 0 containers but received %d", len(containers)) - } -} - -func TestNewContainer(t *testing.T) { - t.Parallel() - - id := t.Name() - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - ctx, cancel := testContext() - defer cancel() - - container, err := client.NewContainer(ctx, id, WithNewSpec()) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - if container.ID() != id { - t.Errorf("expected container id %q but received %q", id, container.ID()) - } - if _, err = container.Spec(ctx); err != nil { - t.Fatal(err) - } - if err := container.Delete(ctx); err != nil { - t.Fatal(err) - } -} - -func TestContainerStart(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if pid := task.Pid(); pid < 1 { - t.Errorf("invalid task pid %d", pid) - } - if err := task.Start(ctx); err != nil { - t.Error(err) - task.Delete(ctx) - return - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 7 { - t.Errorf("expected status 7 from wait but received %d", code) - } - - deleteStatus, err := task.Delete(ctx) - if err != nil { - t.Fatal(err) - } - if ec := deleteStatus.ExitCode(); ec != 7 { - t.Errorf("expected status 7 from delete but received %d", ec) - } -} - -func TestContainerOutput(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - expected = "kingkoye" - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("echo", expected))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - stdout := bytes.NewBuffer(nil) - task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - status := <-statusC - code, _, err := status.Result() - if code != 0 { - t.Errorf("expected status 0 but received %d: %v", code, err) - } - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - - actual := stdout.String() - // echo adds a new line - expected = expected + newLine - if actual != expected { - t.Errorf("expected output %q but received %q", expected, actual) - } -} - -func withByteBuffers(stdout io.Writer) cio.Opt { - // TODO: could this use ioutil.Discard? - return func(streams *cio.Streams) { - streams.Stdin = new(bytes.Buffer) - streams.Stdout = stdout - streams.Stderr = new(bytes.Buffer) - } -} - -func TestContainerExec(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - finishedC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - // start an exec process without running the original container process info - processSpec := spec.Process - withExecExitStatus(processSpec, 6) - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - processStatusC, err := process.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := process.Start(ctx); err != nil { - t.Fatal(err) - } - - // wait for the exec to return - status := <-processStatusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - - if code != 6 { - t.Errorf("expected exec exit code 6 but received %d", code) - } - deleteStatus, err := process.Delete(ctx) - if err != nil { - t.Fatal(err) - } - if ec := deleteStatus.ExitCode(); ec != 6 { - t.Errorf("expected delete exit code 6 but received %d", ec) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-finishedC -} -func TestContainerLargeExecArgs(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - finishedC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - processSpec := spec.Process - withExecArgs(processSpec, "echo", strings.Repeat("a", 20000)) - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - processStatusC, err := process.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := process.Start(ctx); err != nil { - t.Fatal(err) - } - - // wait for the exec to return - status := <-processStatusC - if _, _, err := status.Result(); err != nil { - t.Fatal(err) - } - if _, err := process.Delete(ctx); err != nil { - t.Fatal(err) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-finishedC -} - -func TestContainerPids(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - pid := task.Pid() - if pid < 1 { - t.Errorf("invalid task pid %d", pid) - } - processes, err := task.Pids(ctx) - if err != nil { - t.Fatal(err) - } - switch runtime.GOOS { - case "windows": - if processes[0].Info == nil { - t.Error("expected additional process information but received nil") - } else { - var details hcsshimtypes.ProcessDetails - if err := details.Unmarshal(processes[0].Info.Value); err != nil { - t.Errorf("expected Windows info type hcsshimtypes.ProcessDetails %v", err) - } - } - default: - if l := len(processes); l != 1 { - t.Errorf("expected 1 process but received %d", l) - } - if len(processes) > 0 { - actual := processes[0].Pid - if pid != actual { - t.Errorf("expected pid %d but received %d", pid, actual) - } - } - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-statusC -} - -func TestContainerCloseIO(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat())) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - stdout := bytes.NewBuffer(nil) - - r, w, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - - task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(r, stdout, ioutil.Discard))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - w.Close() - if err := task.CloseIO(ctx, WithStdinCloser); err != nil { - t.Error(err) - } - - <-statusC -} - -func TestDeleteRunningContainer(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - err = container.Delete(ctx, WithSnapshotCleanup) - if err == nil { - t.Error("delete did not error with running task") - } - if !errdefs.IsFailedPrecondition(err) { - t.Errorf("expected error %q but received %q", errdefs.ErrFailedPrecondition, err) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - <-statusC -} - -func TestContainerKill(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "10"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - <-statusC - - err = task.Kill(ctx, syscall.SIGTERM) - if err == nil { - t.Fatal("second call to kill should return an error") - } - if !errdefs.IsNotFound(err) { - t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err) - } -} - -func TestContainerNoBinaryExists(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("nothing"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - switch runtime.GOOS { - case "windows": - if err != nil { - t.Fatalf("failed to create task %v", err) - } - defer task.Delete(ctx, WithProcessKill) - if err := task.Start(ctx); err == nil { - t.Error("task.Start() should return an error when binary does not exist") - } - default: - if err == nil { - t.Error("NewTask should return an error when binary does not exist") - task.Delete(ctx) - } - } -} - -func TestContainerExecNoBinaryExists(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - finishedC, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - // start an exec process without running the original container process - processSpec := spec.Process - processSpec.Args = []string{ - "none", - } - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - defer process.Delete(ctx) - if err := process.Start(ctx); err == nil { - t.Error("Process.Start should fail when process does not exist") - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-finishedC -} - -func TestWaitStoppedTask(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if pid := task.Pid(); pid < 1 { - t.Errorf("invalid task pid %d", pid) - } - if err := task.Start(ctx); err != nil { - t.Error(err) - task.Delete(ctx) - return - } - - // wait for the task to stop then call wait again - <-statusC - statusC, err = task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 7 { - t.Errorf("exit status from stopped task should be 7 but received %d", code) - } -} - -func TestWaitStoppedProcess(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - finishedC, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - // start an exec process without running the original container process info - processSpec := spec.Process - withExecExitStatus(processSpec, 6) - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - defer process.Delete(ctx) - - statusC, err := process.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := process.Start(ctx); err != nil { - t.Fatal(err) - } - - // wait for the exec to return - <-statusC - - // try to wait on the process after it has stopped - statusC, err = process.Wait(ctx) - if err != nil { - t.Fatal(err) - } - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 6 { - t.Errorf("exit status from stopped process should be 6 but received %d", code) - } - - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-finishedC -} - -func TestTaskForceDelete(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - if _, err := task.Delete(ctx); err == nil { - t.Error("task.Delete of a running task should create an error") - } - if _, err := task.Delete(ctx, WithProcessKill); err != nil { - t.Fatal(err) - } -} - -func TestProcessForceDelete(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - // task must be started on windows - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - processSpec := spec.Process - withExecArgs(processSpec, "sleep", "20") - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - if err := process.Start(ctx); err != nil { - t.Fatal(err) - } - if _, err := process.Delete(ctx); err == nil { - t.Error("process.Delete should return an error when process is running") - } - if _, err := process.Delete(ctx, WithProcessKill); err != nil { - t.Error(err) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - <-statusC -} - -func TestContainerHostname(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - expected = "myhostname" - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), - withProcessArgs("hostname"), - oci.WithHostname(expected), - )) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - stdout := bytes.NewBuffer(nil) - task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - status := <-statusC - code, _, err := status.Result() - if err != nil { - t.Fatal(err) - } - if code != 0 { - t.Errorf("expected status 0 but received %d", code) - } - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - cutset := "\n" - if runtime.GOOS == "windows" { - cutset = "\r\n" - } - - actual := strings.TrimSuffix(stdout.String(), cutset) - if actual != expected { - t.Errorf("expected output %q but received %q", expected, actual) - } -} - -func TestContainerExitedAtSet(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withTrue())) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - startTime := time.Now() - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - status := <-statusC - code, _, err := status.Result() - if code != 0 { - t.Errorf("expected status 0 but received %d (err: %v)", code, err) - } - - if s, err := task.Status(ctx); err != nil { - t.Errorf("failed to retrieve status: %v", err) - } else if s.ExitTime.After(startTime) == false { - t.Errorf("exit time is not after start time: %v <= %v", startTime, s.ExitTime) - } - - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } -} - -func TestDeleteContainerExecCreated(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - finished, err := task.Wait(ctx) - if err != nil { - t.Error(err) - } - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - // start an exec process without running the original container process info - processSpec := spec.Process - withExecExitStatus(processSpec, 6) - execID := t.Name() + "_exec" - process, err := task.Exec(ctx, execID, processSpec, empty()) - if err != nil { - t.Fatal(err) - } - deleteStatus, err := process.Delete(ctx) - if err != nil { - t.Fatal(err) - } - if ec := deleteStatus.ExitCode(); ec != 0 { - t.Errorf("expected delete exit code 0 but received %d", ec) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-finished -} - -func TestContainerMetrics(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("metrics are currently not supported on windows") - } - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30"))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx, WithProcessKill) - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - metric, err := task.Metrics(ctx) - if err != nil { - t.Error(err) - return - } - if metric.ID != id { - t.Errorf("expected metric id %q but received %q", id, metric.ID) - } - if err := task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Fatal(err) - } - - <-statusC -} - -func TestDeletedContainerMetrics(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("metrics are currently not supported on windows") - } - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - container, err := client.NewContainer(ctx, id, - WithNewSnapshot(id, image), - WithNewSpec(oci.WithImageConfig(image), withExitStatus(0))) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - if err := task.Start(ctx); err != nil { - t.Fatal(err) - } - - statusC, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - <-statusC - - if _, err := task.Delete(ctx); err != nil { - t.Fatal(err) - } - - if _, err := task.Metrics(ctx); err == nil { - t.Errorf("Getting metrics of deleted task should have failed") - } -} - -func TestContainerExtensions(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - ext := gogotypes.Any{TypeUrl: "test.ext.url", Value: []byte("hello")} - container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerExtension("hello", &ext)) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - checkExt := func(container Container) { - cExts, err := container.Extensions(ctx) - if err != nil { - t.Fatal(err) - } - if len(cExts) != 1 { - t.Errorf("expected 1 container extension") - } - if cExts["hello"].TypeUrl != ext.TypeUrl { - t.Errorf("got unexpected type url for extension: %s", cExts["hello"].TypeUrl) - } - if !bytes.Equal(cExts["hello"].Value, ext.Value) { - t.Errorf("expected extension value %q, got: %q", ext.Value, cExts["hello"].Value) - } - } - - checkExt(container) - - container, err = client.LoadContainer(ctx, container.ID()) - if err != nil { - t.Fatal(err) - } - checkExt(container) -} - -func TestContainerUpdate(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - container, err := client.NewContainer(ctx, id, WithNewSpec()) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - spec, err := container.Spec(ctx) - if err != nil { - t.Fatal(err) - } - - const hostname = "updated-hostname" - spec.Hostname = hostname - - if err := container.Update(ctx, func(ctx context.Context, client *Client, c *containers.Container) error { - a, err := typeurl.MarshalAny(spec) - if err != nil { - return err - } - c.Spec = a - return nil - }); err != nil { - t.Fatal(err) - } - if spec, err = container.Spec(ctx); err != nil { - t.Fatal(err) - } - if spec.Hostname != hostname { - t.Errorf("hostname %q != %q", spec.Hostname, hostname) - } -} - -func TestContainerInfo(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - container, err := client.NewContainer(ctx, id, WithNewSpec()) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - info, err := container.Info(ctx) - if err != nil { - t.Fatal(err) - } - if info.ID != container.ID() { - t.Fatalf("info.ID=%s != container.ID()=%s", info.ID, container.ID()) - } -} - -func TestContainerLabels(t *testing.T) { - t.Parallel() - - ctx, cancel := testContext() - defer cancel() - id := t.Name() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerLabels(map[string]string{ - "test": "yes", - })) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx) - - labels, err := container.Labels(ctx) - if err != nil { - t.Fatal(err) - } - if labels["test"] != "yes" { - t.Fatalf("expected label \"test\" to be \"yes\"") - } - labels["test"] = "no" - if labels, err = container.SetLabels(ctx, labels); err != nil { - t.Fatal(err) - } - if labels["test"] != "no" { - t.Fatalf("expected label \"test\" to be \"no\"") - } -} - -func TestContainerHook(t *testing.T) { - t.Parallel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - var ( - image Image - ctx, cancel = testContext() - id = t.Name() - ) - defer cancel() - - image, err = client.GetImage(ctx, testImage) - if err != nil { - t.Fatal(err) - } - hook := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - if s.Hooks == nil { - s.Hooks = &specs.Hooks{} - } - path, err := exec.LookPath("containerd") - if err != nil { - return err - } - psPath, err := exec.LookPath("ps") - if err != nil { - return err - } - s.Hooks.Prestart = []specs.Hook{ - { - Path: path, - Args: []string{ - "containerd", - "oci-hook", "--", - psPath, "--pid", "{{pid}}", - }, - Env: os.Environ(), - }, - } - return nil - } - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), hook)) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx, WithProcessKill) -} diff -Nru containerd-1.2.6/content/adaptor.go containerd-1.5.9/content/adaptor.go --- containerd-1.2.6/content/adaptor.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/content/adaptor.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package content + +import ( + "strings" + + "github.com/containerd/containerd/filters" +) + +// AdaptInfo returns `filters.Adaptor` that handles `content.Info`. +func AdaptInfo(info Info) filters.Adaptor { + return filters.AdapterFunc(func(fieldpath []string) (string, bool) { + if len(fieldpath) == 0 { + return "", false + } + + switch fieldpath[0] { + case "digest": + return info.Digest.String(), true + case "size": + // TODO: support size based filtering + case "labels": + return checkMap(fieldpath[1:], info.Labels) + } + + return "", false + }) +} + +func checkMap(fieldpath []string, m map[string]string) (string, bool) { + if len(m) == 0 { + return "", false + } + + value, ok := m[strings.Join(fieldpath, ".")] + return value, ok +} diff -Nru containerd-1.2.6/content/content.go containerd-1.5.9/content/content.go --- containerd-1.2.6/content/content.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/content.go 2022-01-05 17:30:58.000000000 +0000 @@ -37,7 +37,7 @@ // ReaderAt only requires desc.Digest to be set. // Other fields in the descriptor may be used internally for resolving // the location of the actual data. - ReaderAt(ctx context.Context, dec ocispec.Descriptor) (ReaderAt, error) + ReaderAt(ctx context.Context, desc ocispec.Descriptor) (ReaderAt, error) } // Ingester writes content diff -Nru containerd-1.2.6/content/helpers.go containerd-1.5.9/content/helpers.go --- containerd-1.2.6/content/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -55,7 +55,14 @@ p := make([]byte, ra.Size()) - _, err = ra.ReadAt(p, 0) + n, err := ra.ReadAt(p, 0) + if err == io.EOF { + if int64(n) != ra.Size() { + err = io.ErrUnexpectedEOF + } else { + err = nil + } + } return p, err } @@ -137,9 +144,14 @@ } } - if _, err := copyWithBuffer(cw, r); err != nil { + copied, err := copyWithBuffer(cw, r) + if err != nil { return errors.Wrap(err, "failed to copy") } + if size != 0 && copied < size-ws.Offset { + // Short writes would return its own error, this indicates a read failure + return errors.Wrapf(io.ErrUnexpectedEOF, "failed to read expected number of bytes") + } if err := cw.Commit(ctx, size, expected, opts...); err != nil { if !errdefs.IsAlreadyExists(err) { @@ -158,8 +170,37 @@ return err } - _, err = copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n)) - return err + copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n)) + if err != nil { + return errors.Wrap(err, "failed to copy") + } + if copied < n { + // Short writes would return its own error, this indicates a read failure + return errors.Wrap(io.ErrUnexpectedEOF, "failed to read expected number of bytes") + } + return nil +} + +// CopyReader copies to a writer from a given reader, returning +// the number of bytes copied. +// Note: if the writer has a non-zero offset, the total number +// of bytes read may be greater than those copied if the reader +// is not an io.Seeker. +// This copy does not commit the writer. +func CopyReader(cw Writer, r io.Reader) (int64, error) { + ws, err := cw.Status() + if err != nil { + return 0, errors.Wrap(err, "failed to get status") + } + + if ws.Offset > 0 { + r, err = seekReader(r, ws.Offset, 0) + if err != nil { + return 0, errors.Wrapf(err, "unable to resume write to %v", ws.Ref) + } + } + + return copyWithBuffer(cw, r) } // seekReader attempts to seek the reader to the given offset, either by @@ -200,9 +241,47 @@ return r, nil } +// copyWithBuffer is very similar to io.CopyBuffer https://golang.org/pkg/io/#CopyBuffer +// but instead of using Read to read from the src, we use ReadAtLeast to make sure we have +// a full buffer before we do a write operation to dst to reduce overheads associated +// with the write operations of small buffers. func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) { - buf := bufPool.Get().(*[]byte) - written, err = io.CopyBuffer(dst, src, *buf) - bufPool.Put(buf) + // If the reader has a WriteTo method, use it to do the copy. + // Avoids an allocation and a copy. + if wt, ok := src.(io.WriterTo); ok { + return wt.WriteTo(dst) + } + // Similarly, if the writer has a ReadFrom method, use it to do the copy. + if rt, ok := dst.(io.ReaderFrom); ok { + return rt.ReadFrom(src) + } + bufRef := bufPool.Get().(*[]byte) + defer bufPool.Put(bufRef) + buf := *bufRef + for { + nr, er := io.ReadAtLeast(src, buf, len(buf)) + if nr > 0 { + nw, ew := dst.Write(buf[0:nr]) + if nw > 0 { + written += int64(nw) + } + if ew != nil { + err = ew + break + } + if nr != nw { + err = io.ErrShortWrite + break + } + } + if er != nil { + // If an EOF happens after reading fewer than the requested bytes, + // ReadAtLeast returns ErrUnexpectedEOF. + if er != io.EOF && er != io.ErrUnexpectedEOF { + err = er + } + break + } + } return } diff -Nru containerd-1.2.6/content/helpers_test.go containerd-1.5.9/content/helpers_test.go --- containerd-1.2.6/content/helpers_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/helpers_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,8 +26,8 @@ "github.com/containerd/containerd/errdefs" "github.com/opencontainers/go-digest" - "gotest.tools/assert" - is "gotest.tools/assert/cmp" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) type copySource struct { @@ -65,10 +65,11 @@ }, { name: "commit already exists", - source: defaultSource, + source: newCopySource("this already exists"), writer: fakeWriter{commitFunc: func() error { return errdefs.ErrAlreadyExists }}, + expected: "this already exists", }, } @@ -81,7 +82,7 @@ testcase.source.digest) assert.NilError(t, err) - assert.Check(t, is.Equal(testcase.source.digest, testcase.writer.commitedDigest)) + assert.Check(t, is.Equal(testcase.source.digest, testcase.writer.committedDigest)) assert.Check(t, is.Equal(testcase.expected, testcase.writer.String())) }) } @@ -97,9 +98,9 @@ type fakeWriter struct { bytes.Buffer - commitedDigest digest.Digest - status Status - commitFunc func() error + committedDigest digest.Digest + status Status + commitFunc func() error } func (f *fakeWriter) Close() error { @@ -108,7 +109,7 @@ } func (f *fakeWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error { - f.commitedDigest = expected + f.committedDigest = expected if f.commitFunc == nil { return nil } @@ -116,7 +117,7 @@ } func (f *fakeWriter) Digest() digest.Digest { - return f.commitedDigest + return f.committedDigest } func (f *fakeWriter) Status() (Status, error) { diff -Nru containerd-1.2.6/content/local/locks.go containerd-1.5.9/content/local/locks.go --- containerd-1.2.6/content/local/locks.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/locks.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "sync" + "time" "github.com/containerd/containerd/errdefs" "github.com/pkg/errors" @@ -25,9 +26,13 @@ // Handles locking references +type lock struct { + since time.Time +} + var ( // locks lets us lock in process - locks = map[string]struct{}{} + locks = make(map[string]*lock) locksMu sync.Mutex ) @@ -35,11 +40,11 @@ locksMu.Lock() defer locksMu.Unlock() - if _, ok := locks[ref]; ok { - return errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked", ref) + if v, ok := locks[ref]; ok { + return errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked since %s", ref, v.since) } - locks[ref] = struct{}{} + locks[ref] = &lock{time.Now()} return nil } diff -Nru containerd-1.2.6/content/local/locks_test.go containerd-1.5.9/content/local/locks_test.go --- containerd-1.2.6/content/local/locks_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/content/local/locks_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,32 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package local + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestTryLock(t *testing.T) { + err := tryLock("testref") + assert.NilError(t, err) + defer unlock("testref") + + err = tryLock("testref") + assert.ErrorContains(t, err, "ref testref locked since ") +} diff -Nru containerd-1.2.6/content/local/readerat.go containerd-1.5.9/content/local/readerat.go --- containerd-1.2.6/content/local/readerat.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/readerat.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,11 @@ import ( "os" + + "github.com/pkg/errors" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" ) // readerat implements io.ReaderAt in a completely stateless manner by opening @@ -27,6 +32,29 @@ fp *os.File } +// OpenReader creates ReaderAt from a file +func OpenReader(p string) (content.ReaderAt, error) { + fi, err := os.Stat(p) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + + return nil, errors.Wrap(errdefs.ErrNotFound, "blob not found") + } + + fp, err := os.Open(p) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + + return nil, errors.Wrap(errdefs.ErrNotFound, "blob not found") + } + + return sizeReaderAt{size: fi.Size(), fp: fp}, nil +} + func (ra sizeReaderAt) ReadAt(p []byte, offset int64) (int, error) { return ra.fp.ReadAt(p, offset) } diff -Nru containerd-1.2.6/content/local/store_bsd.go containerd-1.5.9/content/local/store_bsd.go --- containerd-1.2.6/content/local/store_bsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/content/local/store_bsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +// +build darwin freebsd netbsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package local + +import ( + "os" + "syscall" + "time" +) + +func getATime(fi os.FileInfo) time.Time { + if st, ok := fi.Sys().(*syscall.Stat_t); ok { + return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) //nolint: unconvert // int64 conversions ensure the line compiles for 32-bit systems as well. + } + + return fi.ModTime() +} diff -Nru containerd-1.2.6/content/local/store.go containerd-1.5.9/content/local/store.go --- containerd-1.2.6/content/local/store.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/store.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,8 +33,8 @@ "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/log" + "github.com/sirupsen/logrus" - "github.com/containerd/continuity" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -92,7 +92,11 @@ } func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { - p := s.blobPath(dgst) + p, err := s.blobPath(dgst) + if err != nil { + return content.Info{}, errors.Wrapf(err, "calculating blob info path") + } + fi, err := os.Stat(p) if err != nil { if os.IsNotExist(err) { @@ -123,26 +127,17 @@ // ReaderAt returns an io.ReaderAt for the blob. func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) { - p := s.blobPath(desc.Digest) - fi, err := os.Stat(p) + p, err := s.blobPath(desc.Digest) if err != nil { - if !os.IsNotExist(err) { - return nil, err - } - - return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p) + return nil, errors.Wrapf(err, "calculating blob path for ReaderAt") } - fp, err := os.Open(p) + reader, err := OpenReader(p) if err != nil { - if !os.IsNotExist(err) { - return nil, err - } - - return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p) + return nil, errors.Wrapf(err, "blob %s expected at %s", desc.Digest, p) } - return sizeReaderAt{size: fi.Size(), fp: fp}, nil + return reader, nil } // Delete removes a blob by its digest. @@ -150,7 +145,12 @@ // While this is safe to do concurrently, safe exist-removal logic must hold // some global lock on the store. func (s *store) Delete(ctx context.Context, dgst digest.Digest) error { - if err := os.RemoveAll(s.blobPath(dgst)); err != nil { + bp, err := s.blobPath(dgst) + if err != nil { + return errors.Wrapf(err, "calculating blob path for delete") + } + + if err := os.RemoveAll(bp); err != nil { if !os.IsNotExist(err) { return err } @@ -166,7 +166,11 @@ return content.Info{}, errors.Wrapf(errdefs.ErrFailedPrecondition, "update not supported on immutable content store") } - p := s.blobPath(info.Digest) + p, err := s.blobPath(info.Digest) + if err != nil { + return content.Info{}, errors.Wrapf(err, "calculating blob path for update") + } + fi, err := os.Stat(p) if err != nil { if os.IsNotExist(err) { @@ -224,9 +228,14 @@ return info, nil } -func (s *store) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error { - // TODO: Support filters +func (s *store) Walk(ctx context.Context, fn content.WalkFunc, fs ...string) error { root := filepath.Join(s.root, "blobs") + + filter, err := filters.ParseAll(fs...) + if err != nil { + return err + } + var alg digest.Algorithm return filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { if err != nil { @@ -270,7 +279,12 @@ return err } } - return fn(s.info(dgst, fi, labels)) + + info := s.info(dgst, fi, labels) + if !filter.Match(content.AdaptInfo(info)) { + return nil + } + return fn(info) }) } @@ -451,7 +465,6 @@ } var lockErr error for count := uint64(0); count < 10; count++ { - time.Sleep(time.Millisecond * time.Duration(rand.Intn(1< 0 && status.Total > 0 && total != status.Total { + return status, errors.Errorf("provided total differs from status: %v != %v", total, status.Total) + } + + // TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes + fp, err := os.Open(data) + if err != nil { + return status, err + } + + p := bufPool.Get().(*[]byte) + status.Offset, err = io.CopyBuffer(digester.Hash(), fp, *p) + bufPool.Put(p) + fp.Close() + return status, err +} + // writer provides the main implementation of the Writer method. The caller // must hold the lock correctly and release on error if there is a problem. func (s *store) writer(ctx context.Context, ref string, total int64, expected digest.Digest) (content.Writer, error) { // TODO(stevvooe): Need to actually store expected here. We have // code in the service that shouldn't be dealing with this. if expected != "" { - p := s.blobPath(expected) + p, err := s.blobPath(expected) + if err != nil { + return nil, errors.Wrap(err, "calculating expected blob path for writer") + } if _, err := os.Stat(p); err == nil { return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected) } @@ -498,45 +544,25 @@ updatedAt time.Time ) + foundValidIngest := false // ensure that the ingest path has been created. if err := os.Mkdir(path, 0755); err != nil { if !os.IsExist(err) { return nil, err } - - status, err := s.status(path) - if err != nil { - return nil, errors.Wrap(err, "failed reading status of resume write") - } - - if ref != status.Ref { - // NOTE(stevvooe): This is fairly catastrophic. Either we have some - // layout corruption or a hash collision for the ref key. - return nil, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref) - } - - if total > 0 && status.Total > 0 && total != status.Total { - return nil, errors.Errorf("provided total differs from status: %v != %v", total, status.Total) - } - - // TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes - fp, err := os.Open(data) - if err != nil { - return nil, err - } - - p := bufPool.Get().(*[]byte) - offset, err = io.CopyBuffer(digester.Hash(), fp, *p) - bufPool.Put(p) - fp.Close() - if err != nil { - return nil, err + status, err := s.resumeStatus(ref, total, digester) + if err == nil { + foundValidIngest = true + updatedAt = status.UpdatedAt + startedAt = status.StartedAt + total = status.Total + offset = status.Offset + } else { + logrus.Infof("failed to resume the status from path %s: %s. will recreate them", path, err.Error()) } + } - updatedAt = status.UpdatedAt - startedAt = status.StartedAt - total = status.Total - } else { + if !foundValidIngest { startedAt = time.Now() updatedAt = startedAt @@ -546,11 +572,11 @@ return nil, err } - if writeTimestampFile(filepath.Join(path, "startedat"), startedAt); err != nil { + if err := writeTimestampFile(filepath.Join(path, "startedat"), startedAt); err != nil { return nil, err } - if writeTimestampFile(filepath.Join(path, "updatedat"), startedAt); err != nil { + if err := writeTimestampFile(filepath.Join(path, "updatedat"), startedAt); err != nil { return nil, err } @@ -598,11 +624,17 @@ return nil } -func (s *store) blobPath(dgst digest.Digest) string { - return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex()) +func (s *store) blobPath(dgst digest.Digest) (string, error) { + if err := dgst.Validate(); err != nil { + return "", errors.Wrapf(errdefs.ErrInvalidArgument, "cannot calculate blob path from invalid digest: %v", err) + } + + return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex()), nil } func (s *store) ingestRoot(ref string) string { + // we take a digest of the ref to keep the ingest paths constant length. + // Note that this is not the current or potential digest of incoming content. dgst := digest.FromString(ref) return filepath.Join(s.root, "ingest", dgst.Hex()) } @@ -651,6 +683,19 @@ if err != nil { return err } + return atomicWrite(p, b, 0666) +} - return continuity.AtomicWriteFile(p, b, 0666) +func atomicWrite(path string, data []byte, mode os.FileMode) error { + tmp := fmt.Sprintf("%s.tmp", path) + f, err := os.OpenFile(tmp, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_SYNC, mode) + if err != nil { + return errors.Wrap(err, "create tmp file") + } + _, err = f.Write(data) + f.Close() + if err != nil { + return errors.Wrap(err, "write atomic data") + } + return os.Rename(tmp, path) } diff -Nru containerd-1.2.6/content/local/store_openbsd.go containerd-1.5.9/content/local/store_openbsd.go --- containerd-1.2.6/content/local/store_openbsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/content/local/store_openbsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +// +build openbsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package local + +import ( + "os" + "syscall" + "time" +) + +func getATime(fi os.FileInfo) time.Time { + if st, ok := fi.Sys().(*syscall.Stat_t); ok { + return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) //nolint: unconvert // int64 conversions ensure the line compiles for 32-bit systems as well. + } + + return fi.ModTime() +} diff -Nru containerd-1.2.6/content/local/store_test.go containerd-1.5.9/content/local/store_test.go --- containerd-1.2.6/content/local/store_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/store_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -40,7 +40,7 @@ "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) type memoryLabelStore struct { @@ -329,7 +329,10 @@ } func checkBlobPath(t *testing.T, cs content.Store, dgst digest.Digest) string { - path := cs.(*store).blobPath(dgst) + path, err := cs.(*store).blobPath(dgst) + if err != nil { + t.Fatalf("failed to calculate blob path: %v", err) + } if path != filepath.Join(cs.(*store).root, "blobs", dgst.Algorithm().String(), dgst.Hex()) { t.Fatalf("unexpected path: %q", path) diff -Nru containerd-1.2.6/content/local/store_unix.go containerd-1.5.9/content/local/store_unix.go --- containerd-1.2.6/content/local/store_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/store_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build linux solaris darwin freebsd +// +build linux solaris /* Copyright The containerd Authors. @@ -22,13 +22,11 @@ "os" "syscall" "time" - - "github.com/containerd/containerd/sys" ) func getATime(fi os.FileInfo) time.Time { if st, ok := fi.Sys().(*syscall.Stat_t); ok { - return sys.StatATimeAsTime(st) + return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) //nolint: unconvert // int64 conversions ensure the line compiles for 32-bit systems as well. } return fi.ModTime() diff -Nru containerd-1.2.6/content/local/writer.go containerd-1.5.9/content/local/writer.go --- containerd-1.2.6/content/local/writer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/local/writer.go 2022-01-05 17:30:58.000000000 +0000 @@ -74,6 +74,9 @@ } func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { + // Ensure even on error the writer is fully closed + defer unlock(w.ref) + var base content.Info for _, opt := range opts { if err := opt(&base); err != nil { @@ -81,8 +84,6 @@ } } - // Ensure even on error the writer is fully closed - defer unlock(w.ref) fp := w.fp w.fp = nil @@ -114,8 +115,8 @@ } var ( - ingest = filepath.Join(w.path, "data") - target = w.s.blobPath(dgst) + ingest = filepath.Join(w.path, "data") + target, _ = w.s.blobPath(dgst) // ignore error because we calculated this dgst ) // make sure parent directories of blob exist diff -Nru containerd-1.2.6/content/proxy/content_reader.go containerd-1.5.9/content/proxy/content_reader.go --- containerd-1.2.6/content/proxy/content_reader.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/proxy/content_reader.go 2022-01-05 17:30:58.000000000 +0000 @@ -40,7 +40,13 @@ Offset: off, Size_: int64(len(p)), } - rc, err := ra.client.Read(ra.ctx, rr) + // we need a child context with cancel, or the eventually called + // grpc.NewStream will leak the goroutine until the whole thing is cleared. + // See comment at https://godoc.org/google.golang.org/grpc#ClientConn.NewStream + childCtx, cancel := context.WithCancel(ra.ctx) + // we MUST cancel the child context; see comment above + defer cancel() + rc, err := ra.client.Read(childCtx, rr) if err != nil { return 0, err } diff -Nru containerd-1.2.6/content/proxy/content_writer.go containerd-1.5.9/content/proxy/content_writer.go --- containerd-1.2.6/content/proxy/content_writer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/proxy/content_writer.go 2022-01-05 17:30:58.000000000 +0000 @@ -97,7 +97,14 @@ return } -func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { +func (rw *remoteWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) (err error) { + defer func() { + err1 := rw.Close() + if err == nil { + err = err1 + } + }() + var base content.Info for _, opt := range opts { if err := opt(&base); err != nil { diff -Nru containerd-1.2.6/content/testsuite/testsuite.go containerd-1.5.9/content/testsuite/testsuite.go --- containerd-1.2.6/content/testsuite/testsuite.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content/testsuite/testsuite.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,15 +31,24 @@ "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log/logtest" "github.com/containerd/containerd/pkg/testutil" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) +const ( + emptyDigest = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +) + +// StoreInitFn initializes content store with given root and returns a function for +// destroying the content store +type StoreInitFn func(ctx context.Context, root string) (context.Context, content.Store, func() error, error) + // ContentSuite runs a test suite on the content store given a factory function. -func ContentSuite(t *testing.T, name string, storeFn func(ctx context.Context, root string) (context.Context, content.Store, func() error, error)) { +func ContentSuite(t *testing.T, name string, storeFn StoreInitFn) { t.Run("Writer", makeTest(t, name, storeFn, checkContentStoreWriter)) t.Run("UpdateStatus", makeTest(t, name, storeFn, checkUpdateStatus)) t.Run("CommitExists", makeTest(t, name, storeFn, checkCommitExists)) @@ -52,10 +61,18 @@ t.Run("SmallBlob", makeTest(t, name, storeFn, checkSmallBlob)) t.Run("Labels", makeTest(t, name, storeFn, checkLabels)) + t.Run("CommitErrorState", makeTest(t, name, storeFn, checkCommitErrorState)) +} + +// ContentCrossNSSharedSuite runs a test suite under shared content policy +func ContentCrossNSSharedSuite(t *testing.T, name string, storeFn StoreInitFn) { t.Run("CrossNamespaceAppend", makeTest(t, name, storeFn, checkCrossNSAppend)) t.Run("CrossNamespaceShare", makeTest(t, name, storeFn, checkCrossNSShare)) +} - t.Run("CommitErrorState", makeTest(t, name, storeFn, checkCommitErrorState)) +// ContentCrossNSIsolatedSuite runs a test suite under isolated content policy +func ContentCrossNSIsolatedSuite(t *testing.T, name string, storeFn StoreInitFn) { + t.Run("CrossNamespaceIsolate", makeTest(t, name, storeFn, checkCrossNSIsolate)) } // ContextWrapper is used to decorate new context used inside the test @@ -85,6 +102,7 @@ func makeTest(t *testing.T, name string, storeFn func(ctx context.Context, root string) (context.Context, content.Store, func() error, error), fn func(ctx context.Context, t *testing.T, cs content.Store)) func(t *testing.T) { return func(t *testing.T) { ctx := context.WithValue(context.Background(), nameKey{}, name) + ctx = logtest.WithT(ctx, t) tmpDir, err := ioutil.TempDir("", "content-suite-"+name+"-") if err != nil { @@ -322,7 +340,7 @@ w, err := cs.Writer(ctx, content.WithRef(ref)) if err == nil { - w.Close() + defer w.Close() t.Fatal("writer created with ref, expected to be in use") } if !errdefs.IsUnavailable(err) { @@ -386,6 +404,7 @@ } t.Fatalf("Unexpected error: %+v", err) } + w.Close() w, err = cs.Writer(ctx, content.WithRef(ref)) if err != nil { @@ -409,6 +428,7 @@ t.Errorf("Unexpected error: %+v", err) } + w.Close() w, err = cs.Writer(ctx, content.WithRef(ref)) if err != nil { t.Fatal(err) @@ -424,6 +444,7 @@ t.Errorf("Unexpected error: %+v", err) } + w.Close() w, err = cs.Writer(ctx, content.WithRef(ref)) if err != nil { t.Fatal(err) @@ -439,6 +460,7 @@ t.Fatalf("Failed to commit: %+v", err) } + w.Close() // Create another writer with same reference w, err = cs.Writer(ctx, content.WithRef(ref)) if err != nil { @@ -465,6 +487,7 @@ t.Fatalf("Unexpected error: %+v", err) } + w.Close() w, err = cs.Writer(ctx, content.WithRef(ref)) if err != nil { t.Fatal(err) @@ -890,6 +913,38 @@ } +func checkCrossNSIsolate(ctx context.Context, t *testing.T, cs content.Store) { + wrap, ok := ctx.Value(wrapperKey{}).(ContextWrapper) + if !ok { + t.Skip("multiple contexts not supported") + } + + var size int64 = 1000 + b, d := createContent(size) + ref := fmt.Sprintf("ref-%d", size) + t1 := time.Now() + + if err := content.WriteBlob(ctx, cs, ref, bytes.NewReader(b), ocispec.Descriptor{Size: size, Digest: d}); err != nil { + t.Fatal(err) + } + t2 := time.Now() + + ctx2, done, err := wrap(context.Background()) + if err != nil { + t.Fatal(err) + } + defer done(ctx2) + + t3 := time.Now() + w, err := cs.Writer(ctx2, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: size, Digest: d})) + if err != nil { + t.Fatal(err) + } + t4 := time.Now() + + checkNewlyCreated(t, w, t1, t2, t3, t4) +} + func checkStatus(t *testing.T, w content.Writer, expected content.Status, d digest.Digest, preStart, postStart, preUpdate, postUpdate time.Time) { t.Helper() st, err := w.Status() @@ -934,6 +989,29 @@ } } +func checkNewlyCreated(t *testing.T, w content.Writer, preStart, postStart, preUpdate, postUpdate time.Time) { + t.Helper() + st, err := w.Status() + if err != nil { + t.Fatalf("failed to get status: %v", err) + } + + wd := w.Digest() + if wd != emptyDigest { + t.Fatalf("unexpected digest %v, expected %v", wd, emptyDigest) + } + + if st.Offset != 0 { + t.Fatalf("unexpected offset %v", st.Offset) + } + + if runtime.GOOS != "windows" { + if st.StartedAt.After(postUpdate) || st.StartedAt.Before(postStart) { + t.Fatalf("unexpected started at time %s, expected between %s and %s", st.StartedAt, postStart, postUpdate) + } + } +} + func checkInfo(ctx context.Context, cs content.Store, d digest.Digest, expected content.Info, c1, c2, u1, u2 time.Time) error { info, err := cs.Info(ctx, d) if err != nil { @@ -997,7 +1075,7 @@ func createContent(size int64) ([]byte, digest.Digest) { // each time we call this, we want to get a different seed, but it should - // be related to the intitialization order and fairly consistent between + // be related to the initialization order and fairly consistent between // test runs. An atomic integer works just good enough for this. seed := atomic.AddInt64(&contentSeed, 1) diff -Nru containerd-1.2.6/content_test.go containerd-1.5.9/content_test.go --- containerd-1.2.6/content_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/content_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "fmt" - "sync/atomic" - "testing" - - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/content/testsuite" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/namespaces" - "github.com/pkg/errors" -) - -func newContentStore(ctx context.Context, root string) (context.Context, content.Store, func() error, error) { - client, err := New(address) - if err != nil { - return nil, nil, nil, err - } - - var ( - count uint64 - cs = client.ContentStore() - name = testsuite.Name(ctx) - ) - - wrap := func(ctx context.Context) (context.Context, func(context.Context) error, error) { - n := atomic.AddUint64(&count, 1) - ctx = namespaces.WithNamespace(ctx, fmt.Sprintf("%s-n%d", name, n)) - return client.WithLease(ctx) - } - - ctx = testsuite.SetContextWrapper(ctx, wrap) - - return ctx, cs, func() error { - for i := uint64(1); i <= count; i++ { - ctx = namespaces.WithNamespace(ctx, fmt.Sprintf("%s-n%d", name, i)) - statuses, err := cs.ListStatuses(ctx) - if err != nil { - return err - } - for _, st := range statuses { - if err := cs.Abort(ctx, st.Ref); err != nil { - return errors.Wrapf(err, "failed to abort %s", st.Ref) - } - } - err = cs.Walk(ctx, func(info content.Info) error { - if err := cs.Delete(ctx, info.Digest); err != nil { - if errdefs.IsNotFound(err) { - return nil - } - - return err - } - return nil - }) - if err != nil { - return err - } - } - return nil - - }, nil -} - -func TestContentClient(t *testing.T) { - if testing.Short() { - t.Skip() - } - testsuite.ContentSuite(t, "ContentClient", newContentStore) -} diff -Nru containerd-1.2.6/contrib/ansible/cri-containerd.yaml containerd-1.5.9/contrib/ansible/cri-containerd.yaml --- containerd-1.2.6/contrib/ansible/cri-containerd.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/cri-containerd.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,66 @@ +--- +- hosts: all + become: true + tasks: + - include_vars: vars/vars.yaml # Contains tasks variables for installer + - include_tasks: tasks/bootstrap_ubuntu.yaml # Contains tasks bootstrap components for ubuntu systems + when: ansible_distribution == "Ubuntu" + - include_tasks: tasks/bootstrap_centos.yaml # Contains tasks bootstrap components for centos systems + when: ansible_distribution == "CentOS" + - include_tasks: tasks/k8s.yaml # Contains tasks kubernetes component installation + - include_tasks: tasks/binaries.yaml # Contains tasks for pulling containerd components + + - name: "Create a directory for containerd config" + file: path=/etc/containerd state=directory + + - name: "Start Containerd" + systemd: name=containerd daemon_reload=yes state=started enabled=yes + + - name: "Load br_netfilter kernel module" + modprobe: + name: br_netfilter + state: present + + - name: "Set bridge-nf-call-iptables" + sysctl: + name: net.bridge.bridge-nf-call-iptables + value: 1 + + - name: "Set ip_forward" + sysctl: + name: net.ipv4.ip_forward + value: 1 + + - name: "Check kubelet args in kubelet config (Ubuntu)" + shell: grep "^Environment=\"KUBELET_EXTRA_ARGS=" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf || true + register: check_args + when: ansible_distribution == "Ubuntu" + + - name: "Add runtime args in kubelet conf (Ubuntu)" + lineinfile: + dest: "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + line: "Environment=\"KUBELET_EXTRA_ARGS= --runtime-cgroups=/system.slice/containerd.service --container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock\"" + insertafter: '\[Service\]' + when: ansible_distribution == "Ubuntu" and check_args.stdout == "" + + - name: "Check kubelet args in kubelet config (CentOS)" + shell: grep "^Environment=\"KUBELET_EXTRA_ARGS=" /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf || true + register: check_args + when: ansible_distribution == "CentOS" + + - name: "Add runtime args in kubelet conf (CentOS)" + lineinfile: + dest: "/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf" + line: "Environment=\"KUBELET_EXTRA_ARGS= --runtime-cgroups=/system.slice/containerd.service --container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock\"" + insertafter: '\[Service\]' + when: ansible_distribution == "CentOS" and check_args.stdout == "" + + - name: "Start Kubelet" + systemd: name=kubelet daemon_reload=yes state=started enabled=yes + + # TODO This needs to be removed once we have consistent concurrent pull results + - name: "Pre-pull pause container image" + shell: | + /usr/local/bin/ctr pull k8s.gcr.io/pause:3.5 + /usr/local/bin/crictl --runtime-endpoint unix:///run/containerd/containerd.sock \ + pull k8s.gcr.io/pause:3.5 diff -Nru containerd-1.2.6/contrib/ansible/README.md containerd-1.5.9/contrib/ansible/README.md --- containerd-1.2.6/contrib/ansible/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,122 @@ +# Kubernetes Cluster with Containerd +

+ + +

+ + +This document provides the steps to bring up a Kubernetes cluster using ansible and kubeadm tools. + +### Prerequisites: +- **OS**: Ubuntu 16.04 (will be updated with additional distros after testing) +- **Python**: 2.7+ +- **Ansible**: 2.4+ + +## Step 0: +- Install Ansible on the host where you will provision the cluster. This host may be one of the nodes you plan to include in your cluster. Installation instructions for Ansible are found [here](http://docs.ansible.com/ansible/latest/intro_installation.html). +- Create a hosts file and include the IP addresses of the hosts that need to be provisioned by Ansible. +```console +$ cat hosts +172.31.7.230 +172.31.13.159 +172.31.1.227 +``` +- Setup passwordless SSH access from the host where you are running Ansible to all the hosts in the hosts file. The instructions can be found in [here](http://www.linuxproblem.org/art_9.html) + +## Step 1: +At this point, the ansible playbook should be able to ssh into the machines in the hosts file. +```console +git clone https://github.com/containerd/cri +cd ./cri/contrib/ansible +ansible-playbook -i hosts cri-containerd.yaml +``` +A typical cloud login might have a username and private key file, in which case the following can be used: +```console +ansible-playbook -i hosts -u --private-key cri-containerd.yaml + ``` +For more options ansible config file (/etc/ansible/ansible.cfg) can be used to set defaults. Please refer to [Ansible options](http://docs.ansible.com/ansible/latest/intro_configuration.html) for advanced ansible configurations. + +At the end of this step, you will have the required software installed in the hosts to bringup a kubernetes cluster. +```console +PLAY RECAP *************************************************************************************************************************************************************** +172.31.1.227 : ok=21 changed=7 unreachable=0 failed=0 +172.31.13.159 : ok=21 changed=7 unreachable=0 failed=0 +172.31.7.230 : ok=21 changed=7 unreachable=0 failed=0 +``` + +## Step 2: +Use [kubeadm](https://kubernetes.io/docs/setup/independent/install-kubeadm/) to bring up a Kubernetes Cluster. Depending on what third-party provider you choose, you might have to set the ```--pod-network-cidr``` to something provider-specific. +Initialize the cluster from one of the nodes (Note: This node will be the master node): +```console +$sudo kubeadm init --skip-preflight-checks +[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters. +[init] Using Kubernetes version: v1.7.6 +[init] Using Authorization modes: [Node RBAC] +[preflight] Skipping pre-flight checks +[kubeadm] WARNING: starting in 1.8, tokens expire after 24 hours by default (if you require a non-expiring token use --token-ttl 0) +[certificates] Generated CA certificate and key. +[certificates] Generated API server certificate and key. +[certificates] API Server serving cert is signed for DNS names [abhi-k8-ubuntu-1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.31.7.230] +[certificates] Generated API server kubelet client certificate and key. +[certificates] Generated service account token signing key and public key. +[certificates] Generated front-proxy CA certificate and key. +[certificates] Generated front-proxy client certificate and key. +[certificates] Valid certificates and keys now exist in "/etc/kubernetes/pki" +[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf" +[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf" +[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf" +[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf" +[apiclient] Created API client, waiting for the control plane to become ready +[apiclient] All control plane components are healthy after 42.002391 seconds +[token] Using token: 43a25d.420ff2e06336e4c1 +[apiconfig] Created RBAC rules +[addons] Applied essential addon: kube-proxy +[addons] Applied essential addon: kube-dns + +Your Kubernetes master has initialized successfully! + +To start using your cluster, you need to run (as a regular user): + + mkdir -p $HOME/.kube + sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config + sudo chown $(id -u):$(id -g) $HOME/.kube/config + +You should now deploy a pod network to the cluster. +Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: + http://kubernetes.io/docs/admin/addons/ + +You can now join any number of machines by running the following on each node +as root: + + kubeadm join --token 43a25d.420ff2e06336e4c1 172.31.7.230:6443 + +``` +## Step 3: +Use kubeadm join to add each of the remaining nodes to your cluster. (Note: Uses token that was generated during cluster init.) +```console +$sudo kubeadm join --token 43a25d.420ff2e06336e4c1 172.31.7.230:6443 --skip-preflight-checks +[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters. +[preflight] Skipping pre-flight checks +[discovery] Trying to connect to API Server "172.31.7.230:6443" +[discovery] Created cluster-info discovery client, requesting info from "https://172.31.7.230:6443" +[discovery] Cluster info signature and contents are valid, will use API Server "https://172.31.7.230:6443" +[discovery] Successfully established connection with API Server "172.31.7.230:6443" +[bootstrap] Detected server version: v1.7.6 +[bootstrap] The server supports the Certificates API (certificates.k8s.io/v1beta1) +[csr] Created API client to obtain unique certificate for this node, generating keys and certificate signing request +[csr] Received signed certificate from the API server, generating KubeConfig... +[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf" + +Node join complete: +* Certificate signing request sent to master and response + received. +* Kubelet informed of new secure connection details. + +Run 'kubectl get nodes' on the master to see this machine join. +``` +At the end of Step 3 you should have a kubernetes cluster up and running and ready for deployment. + +## Step 4: +Please follow the instructions [here](https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/#pod-network) to deploy CNI network plugins and start a demo app. + +We are constantly striving to improve the installer. Please feel free to open issues and provide suggestions to make the installer fast and easy to use. We are open to receiving help in validating and improving the installer on different distros. diff -Nru containerd-1.2.6/contrib/ansible/tasks/binaries.yaml containerd-1.5.9/contrib/ansible/tasks/binaries.yaml --- containerd-1.2.6/contrib/ansible/tasks/binaries.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/tasks/binaries.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +--- +- name: "Get Containerd" + unarchive: + src: "https://github.com/containerd/containerd/releases/download/v{{ containerd_release_version }}/cri-containerd-cni-{{ containerd_release_version }}-linux-amd64.tar.gz" + dest: "/" + remote_src: yes + +- name: "Create a directory for cni binary" + file: path={{ cni_bin_dir }} state=directory + +- name: "Create a directory for cni config files" + file: path={{ cni_conf_dir }} state=directory diff -Nru containerd-1.2.6/contrib/ansible/tasks/bootstrap_centos.yaml containerd-1.5.9/contrib/ansible/tasks/bootstrap_centos.yaml --- containerd-1.2.6/contrib/ansible/tasks/bootstrap_centos.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/tasks/bootstrap_centos.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +--- +- name: "Install required packages on CentOS " + yum: + name: "{{ item }}" + state: latest + with_items: + - unzip + - tar + - btrfs-progs + - libseccomp + - util-linux + - libselinux-python diff -Nru containerd-1.2.6/contrib/ansible/tasks/bootstrap_ubuntu.yaml containerd-1.5.9/contrib/ansible/tasks/bootstrap_ubuntu.yaml --- containerd-1.2.6/contrib/ansible/tasks/bootstrap_ubuntu.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/tasks/bootstrap_ubuntu.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +--- +- name: "Install required packages on Ubuntu" + package: + name: "{{ item }}" + state: latest + with_items: + - unzip + - tar + - apt-transport-https + - btrfs-tools + - libseccomp2 + - util-linux diff -Nru containerd-1.2.6/contrib/ansible/tasks/k8s.yaml containerd-1.5.9/contrib/ansible/tasks/k8s.yaml --- containerd-1.2.6/contrib/ansible/tasks/k8s.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/tasks/k8s.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +--- +- name: "Add gpg key (Ubuntu)" + apt_key: + url: https://packages.cloud.google.com/apt/doc/apt-key.gpg + state: present + when: ansible_distribution == "Ubuntu" + +- name: "Add kubernetes source list (Ubuntu)" + apt_repository: + repo: "deb http://apt.kubernetes.io/ kubernetes-{{ ansible_distribution_release }} main" + state: present + filename: "kubernetes" + when: ansible_distribution == "Ubuntu" + +- name: "Update the repository cache (Ubuntu)" + apt: + update_cache: yes + when: ansible_distribution == "Ubuntu" + +- name: "Add Kubernetes repository and install gpg key (CentOS)" + yum_repository: + name: kubernetes + description: Kubernetes repository + baseurl: https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 + gpgcheck: yes + enabled: yes + repo_gpgcheck: yes + gpgkey: + - https://packages.cloud.google.com/yum/doc/yum-key.gpg + - https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg + when: ansible_distribution == "CentOS" + +- name: "Disable SELinux (CentOS)" + selinux: + state: disabled + when: ansible_distribution == "CentOS" + +- name: "Install kubelet,kubeadm,kubectl (CentOS)" + yum: state=present name={{ item }} + with_items: + - kubelet + - kubeadm + - kubectl + when: ansible_distribution == "CentOS" + +- name: "Install kubelet, kubeadm, kubectl (Ubuntu)" + apt: name={{item}} state=installed + with_items: + - kubelet + - kubeadm + - kubectl + when: ansible_distribution == "Ubuntu" diff -Nru containerd-1.2.6/contrib/ansible/vars/vars.yaml containerd-1.5.9/contrib/ansible/vars/vars.yaml --- containerd-1.2.6/contrib/ansible/vars/vars.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/ansible/vars/vars.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,4 @@ +--- +containerd_release_version: 1.3.0 +cni_bin_dir: /opt/cni/bin/ +cni_conf_dir: /etc/cni/net.d/ diff -Nru containerd-1.2.6/contrib/apparmor/apparmor.go containerd-1.5.9/contrib/apparmor/apparmor.go --- containerd-1.2.6/contrib/apparmor/apparmor.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/apparmor/apparmor.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,7 @@ package apparmor import ( + "bytes" "context" "io/ioutil" "os" @@ -41,33 +42,55 @@ // for the container. It is only generated if a profile under that name does not exist. func WithDefaultProfile(name string) oci.SpecOpts { return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - yes, err := isLoaded(name) - if err != nil { + if err := LoadDefaultProfile(name); err != nil { return err } - if yes { - s.Process.ApparmorProfile = name - return nil - } - p, err := loadData(name) - if err != nil { - return err - } - f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), p.Name) - if err != nil { - return err - } - defer f.Close() - path := f.Name() - defer os.Remove(path) - - if err := generate(p, f); err != nil { - return err - } - if err := load(path); err != nil { - return errors.Wrapf(err, "load apparmor profile %s", path) - } s.Process.ApparmorProfile = name return nil } } + +// LoadDefaultProfile ensures the default profile to be loaded with the given name. +// Returns nil error if the profile is already loaded. +func LoadDefaultProfile(name string) error { + yes, err := isLoaded(name) + if err != nil { + return err + } + if yes { + return nil + } + p, err := loadData(name) + if err != nil { + return err + } + f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), p.Name) + if err != nil { + return err + } + defer f.Close() + path := f.Name() + defer os.Remove(path) + + if err := generate(p, f); err != nil { + return err + } + if err := load(path); err != nil { + return errors.Wrapf(err, "load apparmor profile %s", path) + } + return nil +} + +// DumpDefaultProfile dumps the default profile with the given name. +func DumpDefaultProfile(name string) (string, error) { + p, err := loadData(name) + if err != nil { + return "", err + } + + var buf bytes.Buffer + if err := generate(p, &buf); err != nil { + return "", err + } + return buf.String(), nil +} diff -Nru containerd-1.2.6/contrib/apparmor/apparmor_test.go containerd-1.5.9/contrib/apparmor/apparmor_test.go --- containerd-1.2.6/contrib/apparmor/apparmor_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/apparmor/apparmor_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,119 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +import ( + "testing" +) + +type versionExpected struct { + output string + version int +} + +func TestParseVersion(t *testing.T) { + versions := []versionExpected{ + { + output: `AppArmor parser version 2.10 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 210000, + }, + { + output: `AppArmor parser version 2.8 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 208000, + }, + { + output: `AppArmor parser version 2.20 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 220000, + }, + { + output: `AppArmor parser version 2.05 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 205000, + }, + { + output: `AppArmor parser version 2.9.95 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 209095, + }, + { + output: `AppArmor parser version 3.14.159 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2012 Canonical Ltd. +`, + version: 314159, + }, + { + output: `AppArmor parser version 3.0.0-beta1 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2018 Canonical Ltd. +`, + version: 300000, + }, + { + output: `AppArmor parser version 3.0.0-beta1-foo-bar +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2018 Canonical Ltd. +`, + version: 300000, + }, + { + output: `AppArmor parser version 2.7.0~rc2 +Copyright (C) 1999-2008 Novell Inc. +Copyright 2009-2018 Canonical Ltd. +`, + version: 207000, + }, + } + + for _, v := range versions { + version, err := parseVersion(v.output) + if err != nil { + t.Fatalf("expected error to be nil for %#v, got: %v", v, err) + } + if version != v.version { + t.Fatalf("expected version to be %d, was %d, for: %#v\n", v.version, version, v) + } + } +} + +func TestDumpDefaultProfile(t *testing.T) { + if _, err := getVersion(); err != nil { + t.Skipf("AppArmor not available: %+v", err) + } + name := "test-dump-default-profile" + prof, err := DumpDefaultProfile(name) + if err != nil { + t.Fatal(err) + } + t.Logf("Generated profile %q", name) + t.Log(prof) +} diff -Nru containerd-1.2.6/contrib/apparmor/apparmor_unsupported.go containerd-1.5.9/contrib/apparmor/apparmor_unsupported.go --- containerd-1.2.6/contrib/apparmor/apparmor_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/apparmor/apparmor_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,43 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +import ( + "context" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +// WithProfile sets the provided apparmor profile to the spec +func WithProfile(profile string) oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + return errors.New("apparmor is not supported") + } +} + +// WithDefaultProfile will generate a default apparmor profile under the provided name +// for the container. It is only generated if a profile under that name does not exist. +func WithDefaultProfile(name string) oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + return errors.New("apparmor is not supported") + } +} diff -Nru containerd-1.2.6/contrib/apparmor/template.go containerd-1.5.9/contrib/apparmor/template.go --- containerd-1.2.6/contrib/apparmor/template.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/apparmor/template.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,8 @@ // +build linux /* + Copyright The docker Authors. + Copyright The Moby Authors. Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +24,7 @@ "bufio" "fmt" "io" + "io/ioutil" "os" "os/exec" "path" @@ -32,6 +35,10 @@ "github.com/pkg/errors" ) +// NOTE: This code is copied from . +// If you plan to make any changes, please make sure they are also sent +// upstream. + const dir = "/etc/apparmor.d" const defaultTemplate = ` @@ -48,6 +55,14 @@ capability, file, umount, +{{if ge .Version 208096}} + # Host (privileged) processes may send signals to container processes. + signal (receive) peer=unconfined, + # Manager may send signals to container processes. + signal (receive) peer={{.DaemonProfile}}, + # Container processes may send signals amongst themselves. + signal (send,receive) peer={{.Name}}, +{{end}} deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) # deny write to files not in /proc//** or /proc/sys/** @@ -76,10 +91,23 @@ ` type data struct { - Name string - Imports []string - InnerImports []string - Version int + Name string + Imports []string + InnerImports []string + DaemonProfile string + Version int +} + +func cleanProfileName(profile string) string { + // Normally profiles are suffixed by " (enforce)". AppArmor profiles cannot + // contain spaces so this doesn't restrict daemon profile names. + if parts := strings.SplitN(profile, " ", 2); len(parts) >= 1 { + profile = parts[0] + } + if profile == "" { + profile = "unconfined" + } + return profile } func loadData(name string) (*data, error) { @@ -100,6 +128,16 @@ return nil, errors.Wrap(err, "get apparmor_parser version") } p.Version = ver + + // Figure out the daemon profile. + currentProfile, err := ioutil.ReadFile("/proc/self/attr/current") + if err != nil { + // If we couldn't get the daemon profile, assume we are running + // unconfined which is generally the default. + currentProfile = nil + } + p.DaemonProfile = cleanProfileName(string(currentProfile)) + return &p, nil } @@ -154,6 +192,11 @@ words := strings.Split(lines[0], " ") version := words[len(words)-1] + // trim "-beta1" suffix from version="3.0.0-beta1" if exists + version = strings.SplitN(version, "-", 2)[0] + // also trim tilde + version = strings.SplitN(version, "~", 2)[0] + // split by major minor version v := strings.Split(version, ".") if len(v) == 0 || len(v) > 3 { diff -Nru containerd-1.2.6/contrib/apparmor/template_test.go containerd-1.5.9/contrib/apparmor/template_test.go --- containerd-1.2.6/contrib/apparmor/template_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/apparmor/template_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +// +build linux + +package apparmor + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestCleanProfileName(t *testing.T) { + assert.Equal(t, cleanProfileName(""), "unconfined") + assert.Equal(t, cleanProfileName("unconfined"), "unconfined") + assert.Equal(t, cleanProfileName("unconfined (enforce)"), "unconfined") + assert.Equal(t, cleanProfileName("docker-default"), "docker-default") + assert.Equal(t, cleanProfileName("foo"), "foo") + assert.Equal(t, cleanProfileName("foo (enforce)"), "foo") +} diff -Nru containerd-1.2.6/contrib/autocomplete/ctr containerd-1.5.9/contrib/autocomplete/ctr --- containerd-1.2.6/contrib/autocomplete/ctr 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/autocomplete/ctr 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,22 @@ +#! /bin/bash +## This file is a direct copy of https://github.com/urfave/cli/blob/d04c0883fcc8860836ab30ade0fd29afa194ab23/autocomplete/bash_autocomplete + +: ${PROG:=$(basename ${BASH_SOURCE})} + +_cli_bash_autocomplete() { + if [[ "${COMP_WORDS[0]}" != "source" ]]; then + local cur opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ "$cur" == "-"* ]]; then + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion ) + else + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) + fi + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi +} + +complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG +unset PROG diff -Nru containerd-1.2.6/contrib/autocomplete/zsh_autocomplete containerd-1.5.9/contrib/autocomplete/zsh_autocomplete --- containerd-1.2.6/contrib/autocomplete/zsh_autocomplete 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/autocomplete/zsh_autocomplete 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +#compdef ctr +# This file is a direct copy of https://github.com/urfave/cli/blob/d04c0883fcc8860836ab30ade0fd29afa194ab23/autocomplete/zsh_autocomplete +# With $PROG changed to ctr + +_cli_zsh_autocomplete() { + + local -a opts + local cur + cur=${words[-1]} + if [[ "$cur" == "-"* ]]; then + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") + else + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}") + fi + + if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts + fi + + return +} + +compdef _cli_zsh_autocomplete ctr diff -Nru containerd-1.2.6/contrib/aws/snapshotter_bench_cf.yml containerd-1.5.9/contrib/aws/snapshotter_bench_cf.yml --- containerd-1.2.6/contrib/aws/snapshotter_bench_cf.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/aws/snapshotter_bench_cf.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,144 @@ +AWSTemplateFormatVersion: "2010-09-09" + +Description: > + This templates spin ups an EC2 instance with EBS volumes suitable for containerd snapshotters benchmarking. + The template will create EBS volumes for benchmarking (/dev/sdb, /dev/sdc, and /dev/sdd) with same performance characteristics. + /dev/sde volume will be created and used for device mapper thin-pool device. + +Parameters: + Key: + Type: AWS::EC2::KeyPair::KeyName + Description: SSH key to use + + AMI: + Type: AWS::EC2::Image::Id + Description: AMI ID to use for the EC2 instance. Must be Amazon Linux 2. + Default: "ami-032509850cf9ee54e" + + SecurityGroups: + Type: List + Description: List of security groups to add to EC2 instance + + InstanceType: + Type: String + Default: m4.xlarge + Description: EC2 instance type to use + + VolumesIOPS: + Type: Number + Default: 1000 + MinValue: 100 + MaxValue: 20000 + Description: The number of I/O operations per second (IOPS) to reserve for EBS volumes. + + VolumesSize: + Type: Number + Default: 20 + MinValue: 4 + MaxValue: 16384 + Description: EBS volumes size, in gibibytes (GiB) + + VolumeType: + Type: String + Default: io1 + AllowedValues: + - io1 + - gp2 + - sc1 + - st1 + Description: > + Volume type to use for EBS volumes (io1 is recommended). + More information on volume types https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html + + ContainerStorageSetup: + Type: String + Default: https://github.com/projectatomic/container-storage-setup/archive/v0.6.0.tar.gz + Description: container-storage-setup tool version to install (more details at https://github.com/projectatomic/container-storage-setup) + +Resources: + Instance: + Type: AWS::EC2::Instance + Properties: + EbsOptimized: true + InstanceType: !Ref InstanceType + KeyName: !Ref Key + ImageId: !Ref AMI + SecurityGroupIds: !Ref SecurityGroups + BlockDeviceMappings: + - DeviceName: "/dev/xvda" # Root volume + Ebs: + VolumeSize: 64 + VolumeType: io1 + Iops: 1000 + DeleteOnTermination: true + - DeviceName: "/dev/sdb" + Ebs: + VolumeSize: !Ref VolumesSize + VolumeType: !Ref VolumeType + Iops: !Ref VolumesIOPS + DeleteOnTermination: true + - DeviceName: "/dev/sdc" + Ebs: + VolumeSize: !Ref VolumesSize + VolumeType: !Ref VolumeType + Iops: !Ref VolumesIOPS + DeleteOnTermination: true + - DeviceName: "/dev/sdd" + Ebs: + VolumeSize: !Ref VolumesSize + VolumeType: !Ref VolumeType + Iops: !Ref VolumesIOPS + DeleteOnTermination: true + - DeviceName: "/dev/sde" + Ebs: + VolumeSize: !Ref VolumesSize + VolumeType: !Ref VolumeType + Iops: !Ref VolumesIOPS + DeleteOnTermination: true + + UserData: + Fn::Base64: + !Sub | + #!/bin/bash + + set -ex + + yum install -y \ + gcc \ + git \ + btrfs-progs-devel \ + libseccomp-devel + + amazon-linux-extras install -y golang1.11 + + # Install container-storage-setup + mkdir -p /tmp/container-storage-setup/unpacked/ + cd /tmp/container-storage-setup/ + curl -sL ${ContainerStorageSetup} -o archive.tar.gz + tar -xzf archive.tar.gz -C unpacked --strip 1 + cd unpacked/ + make install-core + rm -rf /tmp/container-storage-setup/ + + # Prepare EBS volumes + mkdir -p /mnt/{disk1,disk2,disk3} + + mkfs.ext4 /dev/sdb + mount /dev/sdb /mnt/disk1/ + + mkfs.ext4 /dev/sdc + mount /dev/sdc /mnt/disk2/ + + mkfs.ext4 /dev/sdd + mount /dev/sdd /mnt/disk3 + + chgrp -R wheel /mnt/disk1/ /mnt/disk2/ /mnt/disk3/ + chmod -R 2775 /mnt/disk1/ /mnt/disk2/ /mnt/disk3/ + + # Prepare thin-pool device + touch /etc/sysconfig/docker-storage-setup + echo DEVS=/dev/sde >> /etc/sysconfig/docker-storage-setup + echo VG=bench >> /etc/sysconfig/docker-storage-setup + container-storage-setup + + echo "Done" diff -Nru containerd-1.2.6/contrib/aws/snapshotter_bench_readme.md containerd-1.5.9/contrib/aws/snapshotter_bench_readme.md --- containerd-1.2.6/contrib/aws/snapshotter_bench_readme.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/aws/snapshotter_bench_readme.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +## Requirements + +### Running +Due to its dependency on `dmsetup`, executing the snapshotter process in an environment where a udev +daemon is not accessible (such as a container) may result in unexpected behavior. In this case, try executing the +snapshotter with the `DM_DISABLE_UDEV=1` environment variable, which tells `dmsetup` to ignore udev and manage devices +itself. See [lvm(8)](http://man7.org/linux/man-pages/man8/lvm.8.html) and +[dmsetup(8)](http://man7.org/linux/man-pages/man8/dmsetup.8.html) for more information. + +## How to run snapshotters benchmark + +- `containerd` project contains AWS CloudFormation template to run an EC2 instance suitable for benchmarking. +It installs dependencies, prepares EBS volumes with same performance characteristics, and creates thin-pool device. +You can make stack with the following command (note: there is a charge for using AWS resources): + +```bash +aws cloudformation create-stack \ + --stack-name benchmark-instance \ + --template-body file://benchmark_aws.yml \ + --parameters \ + ParameterKey=Key,ParameterValue=SSH_KEY \ + ParameterKey=SecurityGroups,ParameterValue=sg-XXXXXXXX \ + ParameterKey=VolumesSize,ParameterValue=20 \ + ParameterKey=VolumesIOPS,ParameterValue=1000 +``` + +- You can find an IP address of newly created EC2 instance in AWS Console or via AWS CLI: + +```bash +$ aws ec2 describe-instances \ + --instance-ids $(aws cloudformation describe-stack-resources --stack-name benchmark-instance --query 'StackResources[*].PhysicalResourceId' --output text) \ + --query 'Reservations[*].Instances[*].PublicIpAddress' \ + --output text +``` + +- SSH to an instance and prepare `containerd`: + +```bash +ssh -i SSH_KEY ec2-user@IP +mkdir /mnt/disk1/data /mnt/disk2/data /mnt/disk3/data +go get github.com/containerd/containerd +cd $(go env GOPATH)/src/github.com/containerd/containerd +make +``` + +- Now you're ready to run the benchmark: + +```bash +sudo su - +cd snapshots/benchsuite/ +go test -bench . \ + -dm.thinPoolDev=bench-docker--pool \ + -dm.rootPath=/mnt/disk1/data \ + -overlay.rootPath=/mnt/disk2/data \ + -native.rootPath=/mnt/disk3/data +``` + +- The output will look like: + +```bash +goos: linux +goarch: amd64 +pkg: github.com/containerd/containerd/snapshots/testsuite + +BenchmarkOverlay/run-4 1 1019730210 ns/op 164.53 MB/s +BenchmarkOverlay/prepare 1 26799447 ns/op +BenchmarkOverlay/write 1 968200363 ns/op +BenchmarkOverlay/commit 1 24582560 ns/op + +BenchmarkDeviceMapper/run-4 1 3139232730 ns/op 53.44 MB/s +BenchmarkDeviceMapper/prepare 1 1758640440 ns/op +BenchmarkDeviceMapper/write 1 1356705388 ns/op +BenchmarkDeviceMapper/commit 1 23720367 ns/op + +PASS +ok github.com/containerd/containerd/snapshots/testsuite 185.204s +``` + +- Don't forget to tear down the stack so it does not continue to incur charges: + +```bash +aws cloudformation delete-stack --stack-name benchmark-instance +``` diff -Nru containerd-1.2.6/contrib/Dockerfile.test containerd-1.5.9/contrib/Dockerfile.test --- containerd-1.2.6/contrib/Dockerfile.test 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/Dockerfile.test 2022-01-05 17:30:58.000000000 +0000 @@ -5,27 +5,56 @@ # 2.) docker run -it --privileged -v /tmp:/tmp --tmpfs /var/lib/containerd-test containerd-test bash # 3.) $ make binaries install test # +# Use the RUNC_VERSION build-arg to build with a custom version of runc, for example, +# to build runc v1.0.0-rc93, use: +# +# docker build -t containerd-test --build-arg RUNC_VERSION=v1.0.0-rc93 -f Dockerfile.test ../ + +ARG GOLANG_VERSION=1.16.12 + +FROM golang:${GOLANG_VERSION} AS golang-base +RUN mkdir -p /go/src/github.com/containerd/containerd +WORKDIR /go/src/github.com/containerd/containerd # Install proto3 -FROM golang:1.11 AS proto3 -RUN apt-get update && apt-get install -y autoconf automake g++ libtool unzip +FROM golang-base AS proto3 +RUN apt-get update && apt-get install -y \ + autoconf \ + automake \ + g++ \ + libtool \ + unzip \ + --no-install-recommends + COPY script/setup/install-protobuf install-protobuf RUN ./install-protobuf # Install runc -FROM golang:1.11 AS runc -RUN apt-get update && apt-get install -y curl libseccomp-dev -COPY vendor.conf /go/src/github.com/containerd/containerd/vendor.conf -COPY script/setup/install-runc install-runc +FROM golang-base AS runc +RUN apt-get update && apt-get install -y \ + curl \ + libseccomp-dev \ + --no-install-recommends + +COPY script/setup/runc-version script/setup/install-runc ./ +# Allow overriding the version of runc to install through build-args +ARG RUNC_VERSION +ARG GOPROXY=direct RUN ./install-runc -FROM golang:1.11 -RUN apt-get update && apt-get install -y btrfs-tools gcc git libseccomp-dev make xfsprogs +FROM golang-base AS dev +RUN apt-get update && apt-get install -y \ + libbtrfs-dev \ + btrfs-progs \ + gcc \ + git \ + libseccomp-dev \ + make \ + xfsprogs \ + --no-install-recommends -COPY --from=proto3 /usr/local/bin/protoc /usr/local/bin/protoc +COPY --from=proto3 /usr/local/bin/protoc /usr/local/bin/protoc COPY --from=proto3 /usr/local/include/google /usr/local/include/google +COPY --from=runc /usr/local/sbin/runc /usr/local/go/bin/runc -COPY --from=runc /usr/local/sbin/runc /usr/local/go/bin/runc -COPY . /go/src/github.com/containerd/containerd - -WORKDIR /go/src/github.com/containerd/containerd +COPY . . diff -Nru containerd-1.2.6/contrib/fuzz/filters_fuzzers.go containerd-1.5.9/contrib/fuzz/filters_fuzzers.go --- containerd-1.2.6/contrib/fuzz/filters_fuzzers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/fuzz/filters_fuzzers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build gofuzz + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fuzz + +import ( + "github.com/containerd/containerd/filters" +) + +func FuzzFiltersParse(data []byte) int { + _, err := filters.Parse(string(data)) + if err != nil { + return 0 + } + return 1 +} diff -Nru containerd-1.2.6/contrib/fuzz/platforms_fuzzers.go containerd-1.5.9/contrib/fuzz/platforms_fuzzers.go --- containerd-1.2.6/contrib/fuzz/platforms_fuzzers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/fuzz/platforms_fuzzers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build gofuzz + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fuzz + +import ( + "github.com/containerd/containerd/platforms" +) + +func FuzzPlatformsParse(data []byte) int { + _, err := platforms.Parse(string(data)) + if err != nil { + return 0 + } + return 1 +} diff -Nru containerd-1.2.6/contrib/gce/cloud-init/master.yaml containerd-1.5.9/contrib/gce/cloud-init/master.yaml --- containerd-1.2.6/contrib/gce/cloud-init/master.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/gce/cloud-init/master.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,199 @@ +#cloud-config + +users: +- name: etcd + homedir: /var/etcd + lock_passwd: true + ssh_redirect_user: true + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-master-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-master-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes master + After=kube-master-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-master-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-master-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-master-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-master-installation.service + - systemctl enable kube-master-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/contrib/gce/cloud-init/node.yaml containerd-1.5.9/contrib/gce/cloud-init/node.yaml --- containerd-1.2.6/contrib/gce/cloud-init/node.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/gce/cloud-init/node.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,193 @@ +#cloud-config + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-node-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-node-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes node + After=kube-node-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-node-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-node-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-node-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-node-installation.service + - systemctl enable kube-node-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/contrib/gce/cni.template containerd-1.5.9/contrib/gce/cni.template --- containerd-1.2.6/contrib/gce/cni.template 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/gce/cni.template 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +{ + "name": "k8s-pod-network", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "ptp", + "mtu": 1460, + "ipam": { + "type": "host-local", + "ranges": [{{range $i, $range := .PodCIDRRanges}}{{if $i}}, {{end}}[{"subnet": "{{$range}}"}]{{end}}], + "routes": [{{range $i, $route := .Routes}}{{if $i}}, {{end}}{"dst": "{{$route}}"}{{end}}] + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] +} diff -Nru containerd-1.2.6/contrib/gce/configure.sh containerd-1.5.9/contrib/gce/configure.sh --- containerd-1.2.6/contrib/gce/configure.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/gce/configure.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,239 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o xtrace +set -o errexit +set -o nounset +set -o pipefail + +if [[ "$(python -V 2>&1)" =~ "Python 2" ]]; then + # found python2, just use that + PYTHON="python" +elif [[ -f "/usr/bin/python2.7" ]]; then + # System python not defaulted to python 2 but using 2.7 during migration + PYTHON="/usr/bin/python2.7" +else + # No python2 either by default, let's see if we can find python3 + PYTHON="python3" + if ! command -v ${PYTHON} >/dev/null 2>&1; then + echo "ERROR Python not found. Aborting." + exit 2 + fi +fi +echo "Version : " $(${PYTHON} -V 2>&1) + +# CONTAINERD_HOME is the directory for containerd. +CONTAINERD_HOME="/home/containerd" +cd "${CONTAINERD_HOME}" +# KUBE_HOME is the directory for kubernetes. +KUBE_HOME="/home/kubernetes" + +# fetch_metadata fetches metadata from GCE metadata server. +# Var set: +# 1. Metadata key: key of the metadata. +fetch_metadata() { + local -r key=$1 + local -r attributes="http://metadata.google.internal/computeMetadata/v1/instance/attributes" + if curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" "${attributes}/" | \ + grep -q "^${key}$"; then + curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" \ + "${attributes}/${key}" + fi +} + +# fetch_env fetches environment variables from GCE metadata server +# and generate a env file under ${CONTAINERD_HOME}. It assumes that +# the environment variables in metadata are in yaml format. +fetch_env() { + local -r env_file_name=$1 + ( + umask 077; + local -r tmp_env_file="/tmp/${env_file_name}.yaml" + tmp_env_content=$(fetch_metadata "${env_file_name}") + if [ -z "${tmp_env_content}" ]; then + echo "No environment variable is specified in ${env_file_name}" + return + fi + echo "${tmp_env_content}" > "${tmp_env_file}" + # Convert the yaml format file into a shell-style file. + eval $(${PYTHON} -c ''' +import pipes,sys,yaml +# check version of python and call methods appropriate for that version +if sys.version_info[0] < 3: + items = yaml.load(sys.stdin).iteritems() +else: + items = yaml.load(sys.stdin, Loader=yaml.BaseLoader).items() +for k,v in items: + print("readonly {var}={value}".format(var = k, value = pipes.quote(str(v)))) +''' < "${tmp_env_file}" > "${CONTAINERD_HOME}/${env_file_name}") + rm -f "${tmp_env_file}" + ) +} + +# is_preloaded checks whether a package has been preloaded in the image. +is_preloaded() { + local -r tar=$1 + local -r sha1=$2 + grep -qs "${tar},${sha1}" "${KUBE_HOME}/preload_info" +} + +# KUBE_ENV_METADATA is the metadata key for kubernetes envs. +KUBE_ENV_METADATA="kube-env" +fetch_env ${KUBE_ENV_METADATA} +if [ -f "${CONTAINERD_HOME}/${KUBE_ENV_METADATA}" ]; then + source "${CONTAINERD_HOME}/${KUBE_ENV_METADATA}" +fi + +# CONTAINERD_ENV_METADATA is the metadata key for containerd envs. +CONTAINERD_ENV_METADATA="containerd-env" +fetch_env ${CONTAINERD_ENV_METADATA} +if [ -f "${CONTAINERD_HOME}/${CONTAINERD_ENV_METADATA}" ]; then + source "${CONTAINERD_HOME}/${CONTAINERD_ENV_METADATA}" +fi + +# CONTAINERD_PKG_PREFIX is the prefix of the cri-containerd tarball name. +# By default use the release tarball with cni built in. +pkg_prefix=${CONTAINERD_PKG_PREFIX:-"cri-containerd-cni"} +# Behave differently for test and production. +if [ "${CONTAINERD_TEST:-"false"}" != "true" ]; then + # CONTAINERD_DEPLOY_PATH is the gcs path where cri-containerd tarball is stored. + deploy_path=${CONTAINERD_DEPLOY_PATH:-"cri-containerd-release"} + # CONTAINERD_VERSION is the cri-containerd version to use. + version=${CONTAINERD_VERSION:-""} +else + deploy_path=${CONTAINERD_DEPLOY_PATH:-"cri-containerd-staging"} + + # PULL_REFS_METADATA is the metadata key of PULL_REFS from prow. + PULL_REFS_METADATA="PULL_REFS" + pull_refs=$(fetch_metadata "${PULL_REFS_METADATA}") + if [ ! -z "${pull_refs}" ]; then + deploy_dir=$(echo "${pull_refs}" | sha1sum | awk '{print $1}') + deploy_path="${deploy_path}/containerd/${deploy_dir}" + fi + + # TODO(random-liu): Put version into the metadata instead of + # deciding it in cloud init. This may cause issue to reboot test. + version=$(curl -f --ipv4 --retry 6 --retry-delay 3 --silent --show-error \ + https://storage.googleapis.com/${deploy_path}/latest) +fi + +TARBALL_GCS_NAME="${pkg_prefix}-${version}.linux-amd64.tar.gz" +# TARBALL_GCS_PATH is the path to download cri-containerd tarball for node e2e. +TARBALL_GCS_PATH="https://storage.googleapis.com/${deploy_path}/${TARBALL_GCS_NAME}" +# TARBALL is the name of the tarball after being downloaded. +TARBALL="containerd.tar.gz" +# CONTAINERD_TAR_SHA1 is the sha1sum of containerd tarball. +tar_sha1="${CONTAINERD_TAR_SHA1:-""}" + +if [ -z "${version}" ]; then + # Try using preloaded containerd if version is not specified. + tarball_gcs_pattern="${pkg_prefix}-.*.linux-amd64.tar.gz" + if is_preloaded "${tarball_gcs_pattern}" "${tar_sha1}"; then + echo "CONTAINERD_VERSION is not set, use preloaded containerd" + else + echo "CONTAINERD_VERSION is not set, and containerd is not preloaded" + exit 1 + fi +else + if is_preloaded "${TARBALL_GCS_NAME}" "${tar_sha1}"; then + echo "${TARBALL_GCS_NAME} is preloaded" + else + # Download and untar the release tar ball. + curl -f --ipv4 -Lo "${TARBALL}" --connect-timeout 20 --max-time 300 --retry 6 --retry-delay 10 "${TARBALL_GCS_PATH}" + tar xvf "${TARBALL}" + rm -f "${TARBALL}" + fi +fi + +# Remove crictl shipped with containerd, use crictl installed +# by kube-up.sh. +rm -f "${CONTAINERD_HOME}/usr/local/bin/crictl" +rm -f "${CONTAINERD_HOME}/etc/crictl.yaml" + +# Generate containerd config +config_path="${CONTAINERD_CONFIG_PATH:-"/etc/containerd/config.toml"}" +mkdir -p $(dirname ${config_path}) +cni_bin_dir="${CONTAINERD_HOME}/opt/cni/bin" +cni_template_path="${CONTAINERD_HOME}/opt/containerd/cluster/gce/cni.template" +if [ "${KUBERNETES_MASTER:-}" != "true" ]; then + if [ "${NETWORK_POLICY_PROVIDER:-"none"}" != "none" ] || [ "${ENABLE_NETD:-}" == "true" ]; then + # Use Kubernetes cni daemonset on node if network policy provider is specified + # or netd is enabled. + cni_bin_dir="${KUBE_HOME}/bin" + cni_template_path="" + fi +fi +log_level="${CONTAINERD_LOG_LEVEL:-"info"}" +max_container_log_line="${CONTAINERD_MAX_CONTAINER_LOG_LINE:-16384}" +cat > ${config_path} <> ${config_path} < \ + /etc/profile.d/containerd_env.sh + +# Run extra init script for test. +if [ "${CONTAINERD_TEST:-"false"}" == "true" ]; then + # EXTRA_INIT_SCRIPT is the name of the extra init script after being downloaded. + EXTRA_INIT_SCRIPT="containerd-extra-init.sh" + # EXTRA_INIT_SCRIPT_METADATA is the metadata key of init script. + EXTRA_INIT_SCRIPT_METADATA="containerd-extra-init-sh" + extra_init=$(fetch_metadata "${EXTRA_INIT_SCRIPT_METADATA}") + # Return if containerd-extra-init-sh is not set. + if [ -z "${extra_init}" ]; then + exit 0 + fi + echo "${extra_init}" > "${EXTRA_INIT_SCRIPT}" + chmod 544 "${EXTRA_INIT_SCRIPT}" + ./${EXTRA_INIT_SCRIPT} +fi diff -Nru containerd-1.2.6/contrib/gce/env containerd-1.5.9/contrib/gce/env --- containerd-1.2.6/contrib/gce/env 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/gce/env 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,20 @@ +#!/bin/bash +GCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# TODO(random-liu): Upload release tarball to user's own GCS, and use it. We should +# not let all nodes of all users download tarball from cri-containerd-release. +version_file=${GCE_DIR}/../version +if [ ! -f "${version_file}" ]; then + echo "version file does not exist" + exit 1 +fi +export KUBE_MASTER_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/master.yaml,containerd-configure-sh=${GCE_DIR}/configure.sh,containerd-env=${version_file}" +export KUBE_NODE_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/node.yaml,containerd-configure-sh=${GCE_DIR}/configure.sh,containerd-env=${version_file}" +export KUBE_CONTAINER_RUNTIME="remote" +export KUBE_CONTAINER_RUNTIME_ENDPOINT="unix:///run/containerd/containerd.sock" +export KUBE_CONTAINER_RUNTIME_NAME=containerd +export KUBE_LOAD_IMAGE_COMMAND="/home/containerd/usr/local/bin/ctr -n=k8s.io images import" +export NETWORK_PROVIDER="" +export NON_MASQUERADE_CIDR="0.0.0.0/0" +export KUBE_KUBELET_EXTRA_ARGS="--runtime-cgroups=/system.slice/containerd.service" +export KUBE_FEATURE_GATES="ExperimentalCriticalPodAnnotation=true,CRIContainerLogRotation=true" diff -Nru containerd-1.2.6/contrib/linuxkit/README.md containerd-1.5.9/contrib/linuxkit/README.md --- containerd-1.2.6/contrib/linuxkit/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/linuxkit/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,8 @@ +# LinuxKit Kubernetes project + +The [LinuxKit](https://github.com/linuxkit/kubernetes) is a project for building os images for kubernetes master and worker node virtual machines. + +When the images are built with cri-containerd as the `KUBE_RUNTIME` option they will use `cri-containerd` as their execution backend. +``` +make all KUBE_RUNTIME=cri-containerd +``` diff -Nru containerd-1.2.6/contrib/nvidia/nvidia.go containerd-1.5.9/contrib/nvidia/nvidia.go --- containerd-1.2.6/contrib/nvidia/nvidia.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/nvidia/nvidia.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,7 +29,8 @@ specs "github.com/opencontainers/runtime-spec/specs-go" ) -const nvidiaCLI = "nvidia-container-cli" +// NvidiaCLI is the path to the Nvidia helper binary +const NvidiaCLI = "nvidia-container-cli" // Capability specifies capabilities for the gpu inside the container // Detailed explanation of options can be found: @@ -51,13 +52,16 @@ Display Capability = "display" ) -var allCaps = []Capability{ - Compute, - Compat32, - Graphics, - Utility, - Video, - Display, +// AllCaps returns the complete list of supported Nvidia capabilities. +func AllCaps() []Capability { + return []Capability{ + Compute, + Compat32, + Graphics, + Utility, + Video, + Display, + } } // WithGPUs adds NVIDIA gpu support to a container @@ -76,7 +80,7 @@ } c.OCIHookPath = path } - nvidiaPath, err := exec.LookPath(nvidiaCLI) + nvidiaPath, err := exec.LookPath(NvidiaCLI) if err != nil { return err } @@ -90,6 +94,8 @@ "oci-hook", "--", nvidiaPath, + // ensures the required kernel modules are properly loaded + "--load-kmods", }, c.args()...), Env: os.Environ(), }) @@ -164,7 +170,7 @@ // WithAllCapabilities adds all capabilities to the container for the gpus func WithAllCapabilities(c *config) error { - c.Capabilities = allCaps + c.Capabilities = AllCaps() return nil } diff -Nru containerd-1.2.6/contrib/seccomp/seccomp_default.go containerd-1.5.9/contrib/seccomp/seccomp_default.go --- containerd-1.2.6/contrib/seccomp/seccomp_default.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/seccomp/seccomp_default.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,8 @@ import ( "runtime" - "syscall" + + "golang.org/x/sys/unix" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -46,15 +47,16 @@ } } -// DefaultProfile defines the whitelist for the default seccomp profile. +// DefaultProfile defines the allowed syscalls for the default seccomp profile. func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp { + nosys := uint(unix.ENOSYS) syscalls := []specs.LinuxSyscall{ { Names: []string{ "accept", "accept4", "access", - "alarm", + "adjtimex", "alarm", "bind", "brk", @@ -64,10 +66,16 @@ "chmod", "chown", "chown32", + "clock_adjtime", + "clock_adjtime64", "clock_getres", + "clock_getres_time64", "clock_gettime", + "clock_gettime64", "clock_nanosleep", + "clock_nanosleep_time64", "close", + "close_range", "connect", "copy_file_range", "creat", @@ -79,6 +87,7 @@ "epoll_ctl", "epoll_ctl_old", "epoll_pwait", + "epoll_pwait2", "epoll_wait", "epoll_wait_old", "eventfd", @@ -88,6 +97,7 @@ "exit", "exit_group", "faccessat", + "faccessat2", "fadvise64", "fadvise64_64", "fallocate", @@ -116,6 +126,7 @@ "ftruncate", "ftruncate64", "futex", + "futex_time64", "futimesat", "getcpu", "getcwd", @@ -162,10 +173,14 @@ "io_destroy", "io_getevents", "io_pgetevents", + "io_pgetevents_time64", "ioprio_get", "ioprio_set", "io_setup", "io_submit", + "io_uring_enter", + "io_uring_register", + "io_uring_setup", "ipc", "kill", "lchown", @@ -183,6 +198,7 @@ "lstat", "lstat64", "madvise", + "membarrier", "memfd_create", "mincore", "mkdir", @@ -199,7 +215,9 @@ "mq_notify", "mq_open", "mq_timedreceive", + "mq_timedreceive_time64", "mq_timedsend", + "mq_timedsend_time64", "mq_unlink", "mremap", "msgctl", @@ -215,18 +233,25 @@ "_newselect", "open", "openat", + "openat2", "pause", + "pidfd_open", + "pidfd_send_signal", "pipe", "pipe2", "poll", "ppoll", + "ppoll_time64", "prctl", "pread64", "preadv", + "preadv2", "prlimit64", "pselect6", + "pselect6_time64", "pwrite64", "pwritev", + "pwritev2", "read", "readahead", "readlink", @@ -235,6 +260,7 @@ "recv", "recvfrom", "recvmmsg", + "recvmmsg_time64", "recvmsg", "remap_file_pages", "removexattr", @@ -243,6 +269,7 @@ "renameat2", "restart_syscall", "rmdir", + "rseq", "rt_sigaction", "rt_sigpending", "rt_sigprocmask", @@ -250,6 +277,7 @@ "rt_sigreturn", "rt_sigsuspend", "rt_sigtimedwait", + "rt_sigtimedwait_time64", "rt_tgsigqueueinfo", "sched_getaffinity", "sched_getattr", @@ -258,6 +286,7 @@ "sched_get_priority_min", "sched_getscheduler", "sched_rr_get_interval", + "sched_rr_get_interval_time64", "sched_setaffinity", "sched_setattr", "sched_setparam", @@ -269,6 +298,7 @@ "semget", "semop", "semtimedop", + "semtimedop_time64", "send", "sendfile", "sendfile64", @@ -311,6 +341,7 @@ "sigaltstack", "signalfd", "signalfd4", + "sigprocmask", "sigreturn", "socket", "socketcall", @@ -327,18 +358,21 @@ "sync_file_range", "syncfs", "sysinfo", - "syslog", "tee", "tgkill", "time", "timer_create", "timer_delete", - "timerfd_create", - "timerfd_gettime", - "timerfd_settime", "timer_getoverrun", "timer_gettime", + "timer_gettime64", "timer_settime", + "timer_settime64", + "timerfd_create", + "timerfd_gettime", + "timerfd_gettime64", + "timerfd_settime", + "timerfd_settime64", "times", "tkill", "truncate", @@ -350,6 +384,7 @@ "unlinkat", "utime", "utimensat", + "utimensat_time64", "utimes", "vfork", "vmsplice", @@ -390,6 +425,28 @@ Args: []specs.LinuxSeccompArg{ { Index: 0, + Value: 0x20000, + Op: specs.OpEqualTo, + }, + }, + }, + { + Names: []string{"personality"}, + Action: specs.ActAllow, + Args: []specs.LinuxSeccompArg{ + { + Index: 0, + Value: 0x20008, + Op: specs.OpEqualTo, + }, + }, + }, + { + Names: []string{"personality"}, + Action: specs.ActAllow, + Args: []specs.LinuxSeccompArg{ + { + Index: 0, Value: 0xffffffff, Op: specs.OpEqualTo, }, @@ -405,11 +462,20 @@ // include by arch switch runtime.GOARCH { + case "ppc64le": + s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ + Names: []string{ + "sync_file_range2", + }, + Action: specs.ActAllow, + Args: []specs.LinuxSeccompArg{}, + }) case "arm", "arm64": s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ Names: []string{ "arm_fadvise64_64", "arm_sync_file_range", + "sync_file_range2", "breakpoint", "cacheflush", "set_tls", @@ -461,14 +527,23 @@ Names: []string{ "bpf", "clone", + "clone3", "fanotify_init", + "fsconfig", + "fsmount", + "fsopen", + "fspick", "lookup_dcookie", "mount", + "move_mount", "name_to_handle_at", + "open_tree", "perf_event_open", + "quotactl", "setdomainname", "sethostname", "setns", + "syslog", "umount", "umount2", "unshare", @@ -494,7 +569,6 @@ "delete_module", "init_module", "finit_module", - "query_module", }, Action: specs.ActAllow, Args: []specs.LinuxSeccompArg{}, @@ -509,6 +583,8 @@ s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ Names: []string{ "kcmp", + "pidfd_getfd", + "process_madvise", "process_vm_readv", "process_vm_writev", "ptrace", @@ -530,7 +606,7 @@ Names: []string{ "settimeofday", "stime", - "adjtimex", + "clock_settime", }, Action: specs.ActAllow, Args: []specs.LinuxSeccompArg{}, @@ -541,6 +617,12 @@ Action: specs.ActAllow, Args: []specs.LinuxSeccompArg{}, }) + case "CAP_SYSLOG": + s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ + Names: []string{"syslog"}, + Action: specs.ActAllow, + Args: []specs.LinuxSeccompArg{}, + }) } } @@ -555,7 +637,7 @@ Args: []specs.LinuxSeccompArg{ { Index: 1, - Value: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET, + Value: unix.CLONE_NEWNS | unix.CLONE_NEWUTS | unix.CLONE_NEWIPC | unix.CLONE_NEWUSER | unix.CLONE_NEWPID | unix.CLONE_NEWNET | unix.CLONE_NEWCGROUP, ValueTwo: 0, Op: specs.OpMaskedEqual, }, @@ -570,13 +652,22 @@ Args: []specs.LinuxSeccompArg{ { Index: 0, - Value: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET, + Value: unix.CLONE_NEWNS | unix.CLONE_NEWUTS | unix.CLONE_NEWIPC | unix.CLONE_NEWUSER | unix.CLONE_NEWPID | unix.CLONE_NEWNET | unix.CLONE_NEWCGROUP, ValueTwo: 0, Op: specs.OpMaskedEqual, }, }, }) } + // clone3 is explicitly requested to give ENOSYS instead of the default EPERM, when CAP_SYS_ADMIN is unset + // https://github.com/moby/moby/pull/42681 + s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ + Names: []string{ + "clone3", + }, + Action: specs.ActErrno, + ErrnoRet: &nosys, + }) } return s diff -Nru containerd-1.2.6/contrib/seccomp/seccomp_default_unsupported.go containerd-1.5.9/contrib/seccomp/seccomp_default_unsupported.go --- containerd-1.2.6/contrib/seccomp/seccomp_default_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/contrib/seccomp/seccomp_default_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package seccomp + +import specs "github.com/opencontainers/runtime-spec/specs-go" + +// DefaultProfile defines the allowed syscalls for the default seccomp profile. +func DefaultProfile(sp *specs.Spec) *specs.LinuxSeccomp { + return &specs.LinuxSeccomp{} +} diff -Nru containerd-1.2.6/contrib/seccomp/seccomp.go containerd-1.5.9/contrib/seccomp/seccomp.go --- containerd-1.2.6/contrib/seccomp/seccomp.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/seccomp/seccomp.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,3 @@ -// +build linux - /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/contrib/snapshotservice/service.go containerd-1.5.9/contrib/snapshotservice/service.go --- containerd-1.2.6/contrib/snapshotservice/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/contrib/snapshotservice/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -136,7 +136,7 @@ } return nil - }) + }, sr.Filters...) if err != nil { return err } @@ -163,6 +163,19 @@ }, nil } +func (s service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) { + c, ok := s.sn.(snapshots.Cleaner) + if !ok { + return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method") + } + + if err := c.Cleanup(ctx); err != nil { + return nil, errdefs.ToGRPC(err) + } + + return empty, nil +} + func fromKind(kind snapshots.Kind) snapshotsapi.Kind { if kind == snapshots.KindActive { return snapshotsapi.KindActive diff -Nru containerd-1.2.6/daemon_config_linux_test.go containerd-1.5.9/daemon_config_linux_test.go --- containerd-1.2.6/daemon_config_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/daemon_config_linux_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "bytes" - "context" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "syscall" - "testing" - "time" - - "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/pkg/testutil" - "github.com/containerd/containerd/runtime/v2/runc/options" - srvconfig "github.com/containerd/containerd/services/server/config" -) - -// the following nolint is for shutting up gometalinter on non-linux. -// nolint: unused -func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) { - if testing.Short() { - t.Skip() - } - testutil.RequiresRoot(t) - var ( - ctrd = daemon{} - configTOMLDecoded srvconfig.Config - buf = bytes.NewBuffer(nil) - ) - - tempDir, err := ioutil.TempDir("", "containerd-test-new-daemon-with-config") - if err != nil { - t.Fatal(err) - } - defer func() { - if err != nil { - os.RemoveAll(tempDir) - } - }() - - configTOMLFile := filepath.Join(tempDir, "config.toml") - if err = ioutil.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil { - t.Fatal(err) - } - - if err = srvconfig.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil { - t.Fatal(err) - } - - address := configTOMLDecoded.GRPC.Address - if address == "" { - address = filepath.Join(tempDir, "containerd.sock") - } - args := []string{"-c", configTOMLFile} - if configTOMLDecoded.Root == "" { - args = append(args, "--root", filepath.Join(tempDir, "root")) - } - if configTOMLDecoded.State == "" { - args = append(args, "--state", filepath.Join(tempDir, "state")) - } - if err = ctrd.start("containerd", address, args, buf, buf); err != nil { - t.Fatalf("%v: %s", err, buf.String()) - } - - waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second) - client, err := ctrd.waitForStart(waitCtx) - waitCancel() - if err != nil { - ctrd.Kill() - ctrd.Wait() - t.Fatalf("%v: %s", err, buf.String()) - } - - cleanup := func() { - if err := client.Close(); err != nil { - t.Fatalf("failed to close client: %v", err) - } - if err := ctrd.Stop(); err != nil { - if err := ctrd.Kill(); err != nil { - t.Fatalf("failed to signal containerd: %v", err) - } - } - if err := ctrd.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); !ok { - t.Fatalf("failed to wait for: %v", err) - } - } - if err := os.RemoveAll(tempDir); err != nil { - t.Fatalf("failed to remove %s: %v", tempDir, err) - } - // cleaning config-specific resources is up to the caller - } - return client, &ctrd, cleanup -} - -// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored -func TestDaemonRuntimeRoot(t *testing.T) { - runtimeRoot, err := ioutil.TempDir("", "containerd-test-runtime-root") - if err != nil { - t.Fatal(err) - } - defer func() { - if err != nil { - os.RemoveAll(runtimeRoot) - } - }() - configTOML := ` -[plugins] - [plugins.cri] - stream_server_port = "0" -` - - client, _, cleanup := newDaemonWithConfig(t, configTOML) - defer cleanup() - - ctx, cancel := testContext() - defer cancel() - // FIXME(AkihiroSuda): import locally frozen image? - image, err := client.Pull(ctx, testImage, WithPullUnpack) - if err != nil { - t.Fatal(err) - } - - id := t.Name() - container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithRuntime("io.containerd.runc.v1", &options.Options{ - Root: runtimeRoot, - })) - if err != nil { - t.Fatal(err) - } - defer container.Delete(ctx, WithSnapshotCleanup) - - task, err := container.NewTask(ctx, empty()) - if err != nil { - t.Fatal(err) - } - defer task.Delete(ctx) - - status, err := task.Wait(ctx) - if err != nil { - t.Fatal(err) - } - - stateJSONPath := filepath.Join(runtimeRoot, testNamespace, id, "state.json") - if _, err = os.Stat(stateJSONPath); err != nil { - t.Errorf("error while getting stat for %s: %v", stateJSONPath, err) - } - - if err = task.Kill(ctx, syscall.SIGKILL); err != nil { - t.Error(err) - } - <-status -} diff -Nru containerd-1.2.6/daemon_test.go containerd-1.5.9/daemon_test.go --- containerd-1.2.6/daemon_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/daemon_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "io" - "os/exec" - "sync" - "syscall" - - "github.com/pkg/errors" -) - -type daemon struct { - sync.Mutex - addr string - cmd *exec.Cmd -} - -func (d *daemon) start(name, address string, args []string, stdout, stderr io.Writer) error { - d.Lock() - defer d.Unlock() - if d.cmd != nil { - return errors.New("daemon is already running") - } - args = append(args, []string{"--address", address}...) - cmd := exec.Command(name, args...) - cmd.Stdout = stdout - cmd.Stderr = stderr - if err := cmd.Start(); err != nil { - cmd.Wait() - return errors.Wrap(err, "failed to start daemon") - } - d.addr = address - d.cmd = cmd - return nil -} - -func (d *daemon) waitForStart(ctx context.Context) (*Client, error) { - var ( - client *Client - serving bool - err error - ) - - client, err = New(d.addr) - if err != nil { - return nil, err - } - serving, err = client.IsServing(ctx) - if !serving { - client.Close() - if err == nil { - err = errors.New("connection was successful but service is not available") - } - return nil, err - } - return client, err -} - -func (d *daemon) Stop() error { - d.Lock() - defer d.Unlock() - if d.cmd == nil { - return errors.New("daemon is not running") - } - return d.cmd.Process.Signal(syscall.SIGTERM) -} - -func (d *daemon) Kill() error { - d.Lock() - defer d.Unlock() - if d.cmd == nil { - return errors.New("daemon is not running") - } - return d.cmd.Process.Kill() -} - -func (d *daemon) Wait() error { - d.Lock() - defer d.Unlock() - if d.cmd == nil { - return errors.New("daemon is not running") - } - err := d.cmd.Wait() - d.cmd = nil - return err -} - -func (d *daemon) Restart(stopCb func()) error { - d.Lock() - defer d.Unlock() - if d.cmd == nil { - return errors.New("daemon is not running") - } - - var err error - if err = d.cmd.Process.Signal(syscall.SIGTERM); err != nil { - return errors.Wrap(err, "failed to signal daemon") - } - - d.cmd.Wait() - - if stopCb != nil { - stopCb() - } - - cmd := exec.Command(d.cmd.Path, d.cmd.Args[1:]...) - cmd.Stdout = d.cmd.Stdout - cmd.Stderr = d.cmd.Stderr - if err := cmd.Start(); err != nil { - cmd.Wait() - return errors.Wrap(err, "failed to start new daemon instance") - } - d.cmd = cmd - - return nil -} diff -Nru containerd-1.2.6/debian/changelog containerd-1.5.9/debian/changelog --- containerd-1.2.6/debian/changelog 2019-07-03 12:06:30.000000000 +0000 +++ containerd-1.5.9/debian/changelog 2022-12-12 15:33:42.000000000 +0000 @@ -1,15 +1,246 @@ -containerd (1.2.6-0ubuntu1~18.04.2) bionic-security; urgency=medium +containerd (1.5.9-0ubuntu1~18.04.2) bionic-security; urgency=medium - * No change rebuild for the -security pocket + * SECURITY UPDATE: Memory exhaustion through Exec + - debian/patches/CVE-2022-23471.patch: Prevent goroutine leak in Exec + in pkg/cri/streaming/remotecommand/httpstream.go. + - CVE-2022-23471 + * SECURITY UPDATE: Privilege escalation by inheritable file capabilities. + - debian/patches/CVE-2022-24769.patch: Unassign the Inheritable + capability in oci/spec.go and oci/spec_opts.go. + - CVE-2022-24769 + * SECURITY UPDATE: Improper access to images due to imgcrypt. + - debian/patches/CVE-2022-24778.patch: perform proper + authentication by adding platforms in + vendor/github.com/containerd/imgcrypt/images/ + encryption/encryption.go. + - CVE-2022-24778 + * SECURITY UPDATE: Memory exhaustion through ExecSync. + - debian/patches/CVE-2022-31030.patch: limit the response size + of ExecSync in pkg/cri/server/container_execsync.go. + - CVE-2022-31030 - -- Mike Salvatore Wed, 03 Jul 2019 08:06:30 -0400 + -- David Fernandez Gonzalez Mon, 12 Dec 2022 16:33:42 +0100 -containerd (1.2.6-0ubuntu1~18.04.1) bionic; urgency=medium +containerd (1.5.9-0ubuntu1~18.04.1) bionic; urgency=medium - * Backport to Bionic. (LP: #1824461) - * Add Breaks: docker.io (<= 18.09.3~) + * Backport version 1.5.9-0ubuntu1 from Jammy (LP: #1955413, #1960449). + - d/control: do not b-d on libbtrfs-dev, it is not available in Bionic. + - d/control: b-d on golang-1.13-go instead of golang-go. + - d/rules: set GO111MODULE to off, to avoid Internet connection during the + build. - -- Michael Hudson-Doyle Tue, 16 Apr 2019 13:47:19 +1200 + -- Lucas Kanashiro Wed, 09 Feb 2022 17:38:58 -0300 + +containerd (1.5.9-0ubuntu1) jammy; urgency=medium + + * New upstream release (LP: #1946851, #1955413). + * Remove patches applied by upstream. + + -- Lucas Kanashiro Mon, 10 Jan 2022 16:27:26 -0300 + +containerd (1.5.5-0ubuntu3) impish; urgency=medium + + * SECURITY UPDATE: insufficiently restricted directory permissions + - debian/patches/1.5-reduce-directory-permissions.patch: reduce + permissions for bundle dir in runtime/v1/linux/bundle.go, + runtime/v1/linux/bundle_test.go, runtime/v2/bundle.go, + runtime/v2/bundle_default.go, runtime/v2/bundle_linux.go, + runtime/v2/bundle_linux_test.go, runtime/v2/bundle_test.go, + snapshots/btrfs/btrfs.go. + - CVE-2021-41103 + + -- Marc Deslauriers Wed, 06 Oct 2021 09:13:26 -0400 + +containerd (1.5.5-0ubuntu2) impish; urgency=medium + + * d/p/seccomp-support-clone3-syscall.patch: clone3 is explicitly requested + to give ENOSYS instead of the default EPERM, when CAP_SYS_ADMIN is unset. + (LP: #1943049). + + -- Lucas Kanashiro Tue, 14 Sep 2021 11:45:36 -0300 + +containerd (1.5.5-0ubuntu1) impish; urgency=medium + + * New upstream release. + * Bump debhelper compatibility level to 11. + - d/rules: remove the unneeded --with=systemd from the dh call. + - d/rules: override dh_installsystemd instead of dh_installinit. + + -- Lucas Kanashiro Wed, 04 Aug 2021 17:37:16 -0300 + +containerd (1.5.2-0ubuntu1) impish; urgency=medium + + * New upstream release. + * d/p/skip-tests-with-privilege.patch: add a patch to skip tests which + require a certain level of privilege not achievable in the build + environment. + + -- Lucas Kanashiro Thu, 20 May 2021 15:55:04 -0300 + +containerd (1.4.4-0ubuntu1) hirsute; urgency=medium + + * New upstream release. + - It contains a fix for CVE-2021-21334 along with various other minor + issues. + * Refresh preserve-debug-info.patch + * d/rules: set GO111MODULE to auto. In Go 1.16, which is the default in + Hirsute now, the packages are built in module-aware mode. Since containerd + does not have a go.mod file in its source tree it FTBFS. Setting GO111MODULE + to auto we can have the previous behavior which is enable module-aware mode + only if the go.mod file exists. + + -- Lucas Kanashiro Tue, 10 Mar 2021 11:45:18 -0300 + +containerd (1.4.3-0ubuntu1) hirsute; urgency=medium + + * New upstream release. + * Drop patches applied by upstream. + - d/p/4134-update-etcd-bbolt.patch + - d/p/4277-fix-build-on-riscv64.patch + - d/p/e859b8a-gc-increase-sleep-time-in-test.patch + - d/p/CVE-2020-15257.patch + * Update the copyright file. + * Build depend on default Golang version in all architectures. + + -- Lucas Kanashiro Tue, 12 Jan 2021 18:45:18 -0300 + +containerd (1.3.7-0ubuntu5) hirsute; urgency=medium + + * d/control: add a Breaks for docker.io lower than 19.03.13-0ubuntu4. + See LP #1870514. The previous versions stop the docker daemon when a + containerd update is performed, this Breaks statement will make sure we + have a newer version which has the appropriate fix. + + -- Lucas Kanashiro Mon, 07 Dec 2020 16:33:03 -0300 + +containerd (1.3.7-0ubuntu4) hirsute; urgency=medium + + * SECURITY UPDATE: Elevation of privilege vulnerability + - debian/patches/CVE-2020-15257.patch: Use path based unix socket for shims + and use path-based unix socket for containerd-shim. + - CVE-2020-15257 + + -- Paulo Flabiano Smorigo Thu, 26 Nov 2020 17:35:23 +0000 + +containerd (1.3.7-0ubuntu3) groovy; urgency=medium + + * Build with Go 1.14 on riscv64 as 1.13 does not exist here. Adventurous + riscv64 users can deal with any breakage :) + + -- Michael Hudson-Doyle Tue, 13 Oct 2020 12:14:27 +1300 + +containerd (1.3.7-0ubuntu2) groovy; urgency=medium + + [ Tianon Gravi ] + * Build using Go 1.13 (per upstream) + * Use dh-golang to generate appropriate Built-Using + + -- Michael Hudson-Doyle Thu, 08 Oct 2020 10:51:47 +1300 + +containerd (1.3.7-0ubuntu1) groovy; urgency=medium + + * New upstream release. + + -- Michael Hudson-Doyle Thu, 17 Sep 2020 09:10:52 +1200 + +containerd (1.3.6-0ubuntu1) groovy; urgency=medium + + * New upstream release. + * d/rules: remove vendor directory from the library package + + -- Lucas Kanashiro Sat, 11 Jul 2020 11:20:49 -0300 + +containerd (1.3.4-0ubuntu6) groovy; urgency=medium + + * d/control: remove the golang-race-detector-runtime build dependency as the + package is no longer built from source with latest golang. + + -- Åukasz 'sil2100' Zemczak Tue, 16 Jun 2020 10:12:13 +0200 + +containerd (1.3.4-0ubuntu5) groovy; urgency=medium + + * Rename install file to match the new binary package name + + -- Lucas Kanashiro Mon, 01 Jun 2020 09:51:41 -0300 + +containerd (1.3.4-0ubuntu4) groovy; urgency=medium + + * d/control: rename binary package with dev files and update + XS-Go-Import-Path. Now it is called + golang-github-containerd-containerd-dev instead of + golang-github-docker-containerd-dev. + + -- Lucas Kanashiro Thu, 28 May 2020 17:05:30 -0300 + +containerd (1.3.4-0ubuntu3) groovy; urgency=medium + + * Add a patch to fix the gc/scheduler flaky test on riscv64 + + -- Lucas Kanashiro Thu, 21 May 2020 18:48:48 -0300 + +containerd (1.3.4-0ubuntu2) groovy; urgency=medium + + * Add a patch to not use -buildmode=pie on riscv64 + * d/rules: check for DEB_BUILD_ARCH to set variables to build on riscv64 + + -- Lucas Kanashiro Wed, 20 May 2020 19:19:41 -0300 + +containerd (1.3.4-0ubuntu1) groovy; urgency=medium + + * New upstream release. + * d/p/0001-Improve-host-fallback-behaviour-in-docker-remote.patch: drop + patch applied by upstream. + * debian/control: update Vcs-{Git,Broswer} to point to the Github repository. + * d/p/update_go.etcd.io_bbolt_to_v1.3.4.patch: update go.etcd.io/bbolt to + version 1.3.4 to fix a FTBFS against Go 1.14. + * d/rules: disable btrfs plugin on riscv64, it needs cgo and riscv64 doesn't + support. + + -- Lucas Kanashiro Fri, 15 May 2020 10:36:37 -0300 + +containerd (1.3.3-0ubuntu2) focal; urgency=high + + * d/p/0001-Improve-host-fallback-behaviour-in-docker-remote.patch: + Fixes regression introduced in 1.3.3 update, LP: #1867398. + + -- Jorge Niedbalski Thu, 26 Mar 2020 21:24:48 -0300 + +containerd (1.3.3-0ubuntu1) focal; urgency=medium + + * New upstream version. + + -- Michael Hudson-Doyle Wed, 12 Feb 2020 14:18:29 +1300 + +containerd (1.3.2-0ubuntu1) focal; urgency=medium + + [ Tianon Gravi ] + * Use "sed" to adjust upstream's service file ExecStart value + * Update to 1.3.2 upstream release + + [ Michael Hudson-Doyle ] + * d/patches/preserve-debug-info.patch: generate binaries with debug info in + them so we still get ddebs. + + -- Michael Hudson-Doyle Tue, 11 Feb 2020 12:29:51 +1300 + +containerd (1.3.1-0ubuntu1) focal; urgency=medium + + * Update to 1.3.1 upstream release (LP: #1854841) + + -- Tianon Gravi Tue, 03 Dec 2019 15:24:58 +1300 + +containerd (1.2.10-0ubuntu1) eoan; urgency=medium + + * New upstream release. + + -- Michael Hudson-Doyle Mon, 30 Sep 2019 11:31:16 +1300 + +containerd (1.2.9-0ubuntu1) eoan; urgency=medium + + * New upstream release. + * Set GOCACHE to a safely-writeable directory during build. + + -- Michael Hudson-Doyle Wed, 18 Sep 2019 09:46:57 +0200 containerd (1.2.6-0ubuntu1) disco; urgency=medium diff -Nru containerd-1.2.6/debian/clean containerd-1.5.9/debian/clean --- containerd-1.2.6/debian/clean 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/clean 2022-02-09 20:38:58.000000000 +0000 @@ -0,0 +1,3 @@ +.gocache/ +.gopath/ +man/ diff -Nru containerd-1.2.6/debian/compat containerd-1.5.9/debian/compat --- containerd-1.2.6/debian/compat 2019-01-30 21:27:00.000000000 +0000 +++ containerd-1.5.9/debian/compat 2022-02-09 20:38:58.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru containerd-1.2.6/debian/containerd.service containerd-1.5.9/debian/containerd.service --- containerd-1.2.6/debian/containerd.service 2019-01-30 21:27:00.000000000 +0000 +++ containerd-1.5.9/debian/containerd.service 2022-01-05 17:30:58.000000000 +0000 @@ -1,14 +1,31 @@ +# Copyright The containerd Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + [Unit] Description=containerd container runtime Documentation=https://containerd.io -After=network.target +After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay -ExecStart=/usr/bin/containerd +ExecStart=/usr/local/bin/containerd +Type=notify Delegate=yes KillMode=process +Restart=always +RestartSec=5 # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity @@ -17,6 +34,7 @@ # Comment TasksMax if your systemd version does not supports it. # Only systemd 226 and above support this version. TasksMax=infinity +OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target diff -Nru containerd-1.2.6/debian/control containerd-1.5.9/debian/control --- containerd-1.2.6/debian/control 2019-04-16 01:45:59.000000000 +0000 +++ containerd-1.5.9/debian/control 2022-02-09 20:38:58.000000000 +0000 @@ -4,23 +4,23 @@ Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Debian Go Packaging Team Uploaders: Tianon Gravi -Build-Depends: debhelper (>= 9), +Build-Depends: debhelper (>= 11), + dh-golang, go-md2man, - golang-go (>= 2:1.10~), - golang-race-detector-runtime [amd64], - libbtrfs-dev | btrfs-progs (<< 4.16.1~), + golang-1.13-go, + btrfs-progs (<< 4.16.1~), libseccomp-dev, pkg-config Standards-Version: 3.9.7 Homepage: https://containerd.io -Vcs-Git: https://anonscm.debian.org/git/pkg-go/packages/containerd.git -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-go/packages/containerd.git -XS-Go-Import-Path: github.com/docker/containerd +Vcs-Git: https://github.com/tianon/debian-containerd.git -b ubuntu +Vcs-Browser: https://github.com/tianon/debian-containerd/tree/ubuntu +XS-Go-Import-Path: github.com/containerd/containerd Package: containerd Architecture: linux-any Depends: runc (>= 1.0.0~rc2~), ${misc:Depends}, ${shlibs:Depends} -Breaks: docker.io (<= 18.09.3~) +Breaks: docker.io (<< 19.03.13-0ubuntu4) Built-Using: ${misc:Built-Using} Description: daemon to control runC Containerd is a daemon to control runC, built for performance and density. @@ -30,7 +30,7 @@ . This package contains the binaries. -Package: golang-github-docker-containerd-dev +Package: golang-github-containerd-containerd-dev Architecture: all Depends: ${misc:Depends} Description: runC develpoment files diff -Nru containerd-1.2.6/debian/copyright containerd-1.5.9/debian/copyright --- containerd-1.2.6/debian/copyright 2019-01-30 21:27:00.000000000 +0000 +++ containerd-1.5.9/debian/copyright 2022-02-09 20:38:58.000000000 +0000 @@ -1,8 +1,10 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://github.com/docker/containerd +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: containerd +Source: https://github.com/containerd/containerd Files: * Copyright: 2013-2016 Docker, Inc. + The containerd Authors. License: Apache-2.0 Files: docs/* @@ -13,89 +15,286 @@ Copyright: 2016 Tianon Gravi License: Apache-2.0 -Files: vendor/src/github.com/codegangsta/cli/* -Copyright: 2013-2015 Jeremy Saenz +Files: protobuf/plugin/fieldpath.proto +Copyright: 2013 The GoGo Authors. +License: BSD-2-clause + +Files: vendor/go.opencensus.io/* +Copyright: 2017-2019 OpenCensus Authors +License: Apache-2.0 + +Files: vendor/go.etcd.io/bbolt/* +Copyright: 2013 Ben Johnson License: Expat -Files: vendor/src/github.com/docker/docker/* -Copyright: 2012-2014 Docker, Inc. +Files: vendor/google.golang.org/grpc/* +Copyright: 2014-2019 gRPC authors. License: Apache-2.0 -Files: vendor/src/github.com/docker/docker/pkg/mflag/* -Copyright: 2014 The Docker & Go Authors +Files: vendor/gopkg.in/inf.v0/* +Copyright: 2012 Péter Surányi + 2009 The Go Authors. License: BSD-3-clause-Google -Files: vendor/src/github.com/opencontainers/runtime-spec/* -Copyright: 2015 The Linux Foundation +Files: vendor/gopkg.in/yaml.v2/LICENSE.libyaml + vendor/gopkg.in/yaml.v2/apic.go + vendor/gopkg.in/yaml.v2/emitterc.go + vendor/gopkg.in/yaml.v2/parserc.go + vendor/gopkg.in/yaml.v2/scannerc.go + vendor/gopkg.in/yaml.v2/writerc.go + vendor/gopkg.in/yaml.v2/yamlh.go + vendor/gopkg.in/yaml.v2/yamlprivateh.go +Copyright: 2006 Kirill Simonov +License: Expat + +Files: vendor/gopkg.in/yaml.v2/* +Copyright: 2011-2016 Canonical Ltd. License: Apache-2.0 -Files: vendor/src/github.com/Sirupsen/logrus/* -Copyright: 2014 Simon Eskildsen +Files: vendor/gotest.tools/v3/* +Copyright: 2018 gotest.tools authors +License: Apache-2.0 + +Files: vendor/gotest.tools/v3/internal/difflib/* +Copyright: 2013 Patrick Mezard +License: BSD-3-clause-Google + +Files: vendor/sigs.k8s.io/yaml/* +Copyright: 2014 Sam Ghods + 2013 The Go Authors. +License: Expat and BSD-3-clause-Google + +Files: vendor/sigs.k8s.io/* +Copyright: 2018-2020 The Kubernetes Authors. +License: Apache-2.0 + +Files: vendor/github.com/BurntSushi/toml/* +Copyright: 2013 TOML authors License: Expat -Files: vendor/src/github.com/golang/protobuf/* -Copyright: 2008-2016, The Go Authors. - 2008 Google Inc. +Files: vendor/github.com/BurntSushi/toml/type_fields.go +Copyright: 2010 The Go Authors. License: BSD-3-clause-Google -Files: vendor/src/github.com/cloudfoundry/gosigar/* -Copyright: 2009-2012 VMware, Inc. +Files: vendor/github.com/Microsoft/* +Copyright: 2015-2018 Microsoft Corp. +License: Expat + +Files: vendor/github.com/beorn7/perks/* +Copyright: 2013 Blake Mizerany +License: Expat + +Files: vendor/github.com/cilium/ebpf/* +Copyright: 2019 Authors of Cilium + 2018-2019 Cloudflare + 2017 Nathan Sweet +License: Expat + +Files: vendor/github.com/containers/ocicrypt/* +Copyright: The ocicrypt Authors. License: Apache-2.0 -Files: vendor/src/github.com/cyberdelia/go-metrics-graphite/* -Copyright: 2015 Timothée Peignier -License: BSD-2-clause +Files: vendor/github.com/davecgh/go-spew/* +Copyright: 2012-2016 Dave Collins +License: ISC + +Files: vendor/github.com/docker/spdystream/* +Copyright: 2014-2015 Docker, Inc. + 2011-2013 The Go Authors. +License: Apache-2.0 + +Files: vendor/github.com/docker/* +Copyright: 2012-2018 Docker, Inc. +License: Apache-2.0 + +Files: vendor/github.com/emicklei/go-restful/* +Copyright: 2012-2018 Ernest Micklei +License: Expat + +Files: vendor/github.com/fsnotify/fsnotify/* +Copyright: 2012-2019 fsnotify Authors. + 2010-2015 The Go Authors. +License: BSD-3-clause-Google + +Files: vendor/github.com/fullsailor/pkcs7/x509.go +Copyright: 2009 The Go Authors. +License: BSD-3-clause-Google + +Files: vendor/github.com/fullsailor/pkcs7/* +Copyright: 2015 Andrew Smith +License: Expat -Files: vendor/src/github.com/opencontainers/runc/* -Copyright: Copyright 2014 Docker, Inc. +Files: vendor/github.com/go-logr/logr/* +Copyright: 2019 The logr Authors. License: Apache-2.0 -Files: vendor/src/golang.org/x/net/* -Copyright: 2011-2015 The Go Authors +Files: vendor/github.com/gogo/googleapis/* +Copyright: 2018 GoGo Authors + 2015-2017 Google Inc +License: Apache-2.0 + +Files: vendor/github.com/gogo/protobuf/proto/clone.go +Copyright: 2011 The Go Authors. +License: BSD-3-clause-Google + +Files: vendor/github.com/gogo/protobuf/* +Copyright: 2010-2018 The GoGo Authors. +License: BSD-3-clause-Google or BSD-2-clause + +Files: vendor/github.com/golang/protobuf/* +Copyright: 2010-2018 The Go Authors. License: BSD-3-clause-Google -Files: vendor/src/google.golang.org/grpc/* -Copyright: 2014-2015 Google Inc. +Files: vendor/github.com/google/go-cmp/* +Copyright: 2017 The Go Authors. License: BSD-3-clause-Google -Files: vendor/src/github.com/coreos/go-systemd/* -Copyright: - 2013-2015 CoreOS Inc. - 2015 RedHat, Inc. +Files: vendor/github.com/google/gofuzz/* +Copyright: 2014 Google Inc. License: Apache-2.0 -Files: vendor/src/github.com/docker/go-units/* -Copyright: 2015 Docker, Inc. +Files: vendor/github.com/google/uuid/* +Copyright: 2009-2018 Google Inc. +License: BSD-3-clause-Google + +Files: vendor/github.com/grpc-ecosystem/go-grpc-prometheus/* +Copyright: 2016 Michal Witkowski. License: Apache-2.0 -Files: vendor/src/github.com/godbus/dbus/* -Copyright: - 2013 Georg Reinke - 2013 Google -License: BSD-2-clause +Files: vendor/github.com/hashicorp/* +Copyright: Hashicorp +License: MPL-2.0 + +Files: vendor/github.com/imdario/mergo/* +Copyright: 2013-2014 Dario Castañé + 2012 The Go Authors +License: BSD-3-clause-Google -Files: vendor/src/github.com/Azure/go-ansiterm/* -Copyright: 2015 Microsoft Corporation +Files: vendor/github.com/json-iterator/go/* +Copyright: 2016 json-iterator License: Expat -Files: vendor/src/github.com/go-check/check/* -Copyright: 2010-2013 Gustavo Niemeyer +Files: vendor/github.com/konsorten/go-windows-terminal-sequences/* +Copyright: 2017-2018 marvin + konsorten GmbH +License: Expat + +Files: vendor/github.com/matttproud/golang_protobuf_extensions/* +Copyright: 2012-2013 Matt T. Proud +License: Apache-2.0 + +Files: vendor/github.com/mistifyio/go-zfs/* +Copyright: 2014 OmniTI Computer Consulting, Inc. +License: Apache-2.0 + +Files: vendor/github.com/opencontainers/go-digest/* +Copyright: 2019-2020 OCI Contributors + 2016-2017 Docker, Inc. +License: Apache-2.0 + +Files: vendor/github.com/opencontainers/image-spec/* +Copyright: 2004-2016 The Linux Foundation and its contributors. +License: Apache-2.0 + +Files: vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go +Copyright: 2016-2017 SUSE LLC +License: Apache-2.0 + +Files: vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c +Copyright: 2019 SUSE LLC + 2019 Aleksa Sarai +License: LGPL-2.1+ + +Files: vendor/github.com/opencontainers/runc/* +Copyright: 2012-2015 Docker, Inc. +License: Apache-2.0 + +Files: vendor/github.com/opencontainers/runtime-spec/* +Copyright: 2015 The Linux Foundation. +License: Apache-2.0 + +Files: vendor/github.com/pkg/errors/* +Copyright: 2015 Dave Cheney License: BSD-2-clause -Files: vendor/src/github.com/rcrowley/go-metrics/* -Copyright: 2012 Richard Crowley -License: BSD-2-clause-rcrowley - -Files: vendor/src/github.com/seccomp/libseccomp-golang/* -Copyright: - 2015 Matthew Heon - 2015 Paul Moore +Files: vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/* +Copyright: 2011 Open Knowledge Foundation Ltd. +License: BSD-3-clause-Google + +Files: vendor/github.com/prometheus/* +Copyright: 2012-2020 The Prometheus Authors +License: Apache-2.0 + +Files: vendor/github.com/shurcooL/sanitized_anchor_name/* +Copyright: 2015 Dmitri Shuralyov +License: Expat + +Files: vendor/github.com/sirupsen/logrus/alt_exit.go +Copyright: 2012 Miki Tebeka +License: Expat + +Files: vendor/github.com/sirupsen/logrus/* +Copyright: 2014 Simon Eskildsen +License: Expat + +Files: vendor/github.com/syndtr/gocapability/* +Copyright: 2013 Suryandaru Triandana License: BSD-2-clause -Files: vendor/src/github.com/vdemeester/shakers/* -Copyright: 2015-2016 Vincent Demeester +Files: vendor/github.com/tchap/go-patricia/* +Copyright: 2014 The AUTHORS +License: Expat + +Files: vendor/github.com/urfave/cli/* +Copyright: 2016 Jeremy Saenz & Contributors +License: Expat + +Files: vendor/github.com/willf/bitset/* +Copyright: 2014 Will Fitzgerald +License: BSD-3-clause-Google + +Files: vendor/golang.org/x/* +Copyright: 2009-2020 The Go Authors. +License: BSD-3-clause-Google + +Files: vendor/gopkg.in/square/go-jose.v2/* +Copyright: 2014-2018 Square Inc. + 2010-2011 The Go Authors. +License: Apache-2.0 + +Files: vendor/k8s.io/klog/v2/* +Copyright: 2013 Google Inc. +License: Apache-2.0 + +Files: vendor/k8s.io/* +Copyright: 2014-2020 The Kubernetes Authors. +License: Apache-2.0 + +Files: vendor/github.com/cespare/xxhash/* +Copyright: 2016 Caleb Spare +License: Expat + +Files: vendor/github.com/containernetworking/* +Copyright: 2015-2017 CNI authors +License: Apache-2.0 + +Files: vendor/github.com/coreos/go-systemd/* +Copyright: 2015-2018 CoreOS, Inc + 2014 Docker, Inc. License: Apache-2.0 +Files: vendor/github.com/cpuguy83/go-md2man/* +Copyright: 2014 Brian Goff +License: Expat + +Files: vendor/github.com/godbus/dbus/* +Copyright: 2013 Georg Reinke + 2013 Google +License: BSD-2-clause + +Files: vendor/github.com/russross/blackfriday/* +Copyright: 2011 Russ Ross +License: BSD-2-clause + License: Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -148,7 +347,7 @@ material not subject to the license. This includes other CC- licensed material, or material used under an exception or limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors + wiki.creativecommons.org/Considerations_for_licensors . Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the @@ -165,7 +364,7 @@ Although not required by our licenses, you are encouraged to respect those requests where reasonable. More_considerations for the public: - wiki.creativecommons.org/Considerations_for_licensees + wiki.creativecommons.org/Considerations_for_licensees . ======================================================================= . @@ -607,31 +806,400 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: BSD-2-clause-rcrowley - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: +License: ISC + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + +License: MPL-2.0 + Mozilla Public License Version 2.0 + ================================== + . + 1. Definitions + -------------- + . + 1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + . + 1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + . + 1.3. "Contribution" + means Covered Software of a particular Contributor. + . + 1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + . + 1.5. "Incompatible With Secondary Licenses" + means + . + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + . + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + . + 1.6. "Executable Form" + means any form of the work other than Source Code Form. + . + 1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + . + 1.8. "License" + means this document. + . + 1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + . + 1.10. "Modifications" + means any of the following: + . + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + . + (b) any new file in Source Code Form that contains any Covered + Software. + . + 1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + . + 1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + . + 1.13. "Source Code Form" + means the form of the work preferred for making modifications. + . + 1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + . + 2. License Grants and Conditions + -------------------------------- + . + 2.1. Grants + . + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + . + (a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + . + (b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + . + 2.2. Effective Date + . + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + . + 2.3. Limitations on Grant Scope + . + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + . + (a) for any code that a Contributor has removed from Covered Software; + or + . + (b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + . + (c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + . + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + . + 2.4. Subsequent Licenses + . + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + . + 2.5. Representation + . + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights + to grant the rights to its Contributions conveyed by this License. + . + 2.6. Fair Use + . + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + . + 2.7. Conditions + . + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted + in Section 2.1. + . + 3. Responsibilities + ------------------- + . + 3.1. Distribution of Source Form + . + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + . + 3.2. Distribution of Executable Form + . + If You distribute Covered Software in Executable Form then: + . + (a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + . + (b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + . + 3.3. Distribution of a Larger Work + . + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + . + 3.4. Notices + . + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, + or limitations of liability) contained within the Source Code Form of + the Covered Software, except that You may alter any license notices to + the extent required to remedy known factual inaccuracies. + . + 3.5. Application of Additional Terms + . + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + . + 4. Inability to Comply Due to Statute or Regulation + --------------------------------------------------- + . + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Software due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description must + be placed in a text file included with all distributions of the Covered + Software under this License. Except to the extent prohibited by statute + or regulation, such description must be sufficiently detailed for a + recipient of ordinary skill to be able to understand it. + . + 5. Termination + -------------- + . + 5.1. The rights granted under this License will terminate automatically + if You fail to comply with any of its terms. However, if You become + compliant, then the rights granted under this License from a particular + Contributor are reinstated (a) provisionally, unless and until such + Contributor explicitly and finally terminates Your grants, and (b) on an + ongoing basis, if such Contributor fails to notify You of the + non-compliance by some reasonable means prior to 60 days after You have + come back into compliance. Moreover, Your grants from a particular + Contributor are reinstated on an ongoing basis if such Contributor + notifies You of the non-compliance by some reasonable means, this is the + first time You have received notice of non-compliance with this License + from such Contributor, and You become compliant prior to 30 days after + Your receipt of the notice. + . + 5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + . + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all + end user license agreements (excluding distributors and resellers) which + have been validly granted by You or Your distributors under this License + prior to termination shall survive termination. + . + 6. Disclaimer of Warranty + ------------------------- + . + Covered Software is provided under this License on an "as is" + basis, without warranty of any kind, either expressed, implied, or + statutory, including, without limitation, warranties that the + Covered Software is free of defects, merchantable, fit for a + particular purpose or non-infringing. The entire risk as to the + quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You + (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an + essential part of this License. No use of any Covered Software is + authorized under this License except under this disclaimer. + . + 7. Limitation of Liability + -------------------------- + . + Under no circumstances and under no legal theory, whether tort + (including negligence), contract, or otherwise, shall any + Contributor, or anyone who distributes Covered Software as + permitted above, be liable to You for any direct, indirect, + special, incidental, or consequential damages of any character + including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any + and all other commercial damages or losses, even if such party + shall have been informed of the possibility of such damages. This + limitation of liability shall not apply to liability for death or + personal injury resulting from such party's negligence to the + extent applicable law prohibits such limitation. Some + jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and + limitation may not apply to You. + . + 8. Litigation + ------------- + . + Any litigation relating to this License may be brought only in the + courts of a jurisdiction where the defendant maintains its principal + place of business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. + Nothing in this Section shall prevent a party's ability to bring + cross-claims or counter-claims. + . + 9. Miscellaneous + ---------------- + . + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides + that the language of a contract shall be construed against the drafter + shall not be used to construe this License against a Contributor. + . + 10. Versions of the License + --------------------------- + . + 10.1. New Versions + . + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + . + 10.2. Effect of New Versions + . + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + . + 10.3. Modified Versions + . + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + . + 10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses + . + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + . + Exhibit A - Source Code Form License Notice + ------------------------------------------- + . + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + . + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to look + for such a notice. + . + You may add additional accurate notices of copyright ownership. + . + Exhibit B - "Incompatible With Secondary Licenses" Notice + --------------------------------------------------------- + . + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +License: LGPL-2.1+ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) + any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - . - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - . - THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL RICHARD CROWLEY OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - THE POSSIBILITY OF SUCH DAMAGE. - . - The views and conclusions contained in the software and documentation - are those of the authors and should not be interpreted as representing - official policies, either expressed or implied, of Richard Crowley. + On Debian systems, the complete text of the GNU Lesser General Public + License version 2.1 can be found in ‘/usr/share/common-licenses/LGPL-2.1’. diff -Nru containerd-1.2.6/debian/golang-github-containerd-containerd-dev.install containerd-1.5.9/debian/golang-github-containerd-containerd-dev.install --- containerd-1.2.6/debian/golang-github-containerd-containerd-dev.install 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/golang-github-containerd-containerd-dev.install 2022-02-09 20:38:58.000000000 +0000 @@ -0,0 +1 @@ +usr/share/gocode/src diff -Nru containerd-1.2.6/debian/golang-github-docker-containerd-dev.install containerd-1.5.9/debian/golang-github-docker-containerd-dev.install --- containerd-1.2.6/debian/golang-github-docker-containerd-dev.install 2019-01-30 21:27:00.000000000 +0000 +++ containerd-1.5.9/debian/golang-github-docker-containerd-dev.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/share/gocode/src diff -Nru containerd-1.2.6/debian/patches/CVE-2022-23471.patch containerd-1.5.9/debian/patches/CVE-2022-23471.patch --- containerd-1.2.6/debian/patches/CVE-2022-23471.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/CVE-2022-23471.patch 2022-12-12 10:25:11.000000000 +0000 @@ -0,0 +1,71 @@ +From f012617edfd887a29345888d65640a7ccd7c72ce Mon Sep 17 00:00:00 2001 +From: Danny Canter +Date: Mon, 28 Nov 2022 14:45:34 -0800 +Subject: [PATCH] CRI stream server: Fix goroutine leak in Exec + +In the CRI streaming server, a goroutine (`handleResizeEvents`) is launched +to handle terminal resize events if a TTY is asked for with an exec; this +is the sender of terminal resize events. Another goroutine is launched +shortly after successful process startup to actually do something with +these events, however the issue arises if the exec process fails to start +for any reason that would have `process.Start` return non-nil. The receiver +goroutine never gets launched so the sender is stuck blocked on a channel send +infinitely. + +This could be used in a malicious manner by repeatedly launching execs +with a command that doesn't exist in the image, as a single goroutine +will get leaked on every invocation which will slowly grow containerd's +memory usage. + +Signed-off-by: Danny Canter +--- + pkg/cri/streaming/remotecommand/httpstream.go | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/pkg/cri/streaming/remotecommand/httpstream.go b/pkg/cri/streaming/remotecommand/httpstream.go +index 0417a1a9e66..9177fa794d2 100644 +--- a/pkg/cri/streaming/remotecommand/httpstream.go ++++ b/pkg/cri/streaming/remotecommand/httpstream.go +@@ -33,6 +33,7 @@ limitations under the License. + package remotecommand + + import ( ++ gocontext "context" + "encoding/json" + "errors" + "fmt" +@@ -132,7 +133,7 @@ func createStreams(req *http.Request, w http.ResponseWriter, opts *Options, supp + + if ctx.resizeStream != nil { + ctx.resizeChan = make(chan remotecommand.TerminalSize) +- go handleResizeEvents(ctx.resizeStream, ctx.resizeChan) ++ go handleResizeEvents(req.Context(), ctx.resizeStream, ctx.resizeChan) + } + + return ctx, true +@@ -425,7 +426,7 @@ WaitForStreams: + // supportsTerminalResizing returns false because v1ProtocolHandler doesn't support it. + func (*v1ProtocolHandler) supportsTerminalResizing() bool { return false } + +-func handleResizeEvents(stream io.Reader, channel chan<- remotecommand.TerminalSize) { ++func handleResizeEvents(ctx gocontext.Context, stream io.Reader, channel chan<- remotecommand.TerminalSize) { + defer runtime.HandleCrash() + defer close(channel) + +@@ -435,7 +436,15 @@ func handleResizeEvents(stream io.Reader, channel chan<- remotecommand.TerminalS + if err := decoder.Decode(&size); err != nil { + break + } +- channel <- size ++ ++ select { ++ case channel <- size: ++ case <-ctx.Done(): ++ // To avoid leaking this routine, exit if the http request finishes. This path ++ // would generally be hit if starting the process fails and nothing is started to ++ // ingest these resize events. ++ return ++ } + } + } + diff -Nru containerd-1.2.6/debian/patches/CVE-2022-23648.patch containerd-1.5.9/debian/patches/CVE-2022-23648.patch --- containerd-1.2.6/debian/patches/CVE-2022-23648.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/CVE-2022-23648.patch 2022-02-09 20:38:58.000000000 +0000 @@ -0,0 +1,32 @@ +From d1d905b2fe66cb5c6f888256731ede6a918bb7c3 Mon Sep 17 00:00:00 2001 +From: ruiwen-zhao +Date: Fri, 11 Feb 2022 04:21:58 +0000 +Subject: [PATCH] Use fs.RootPath when mounting volumes + +Signed-off-by: Ruiwen Zhao +--- + pkg/cri/opts/container.go | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- containerd-1.5.5.orig/pkg/cri/opts/container.go ++++ containerd-1.5.5/pkg/cri/opts/container.go +@@ -20,7 +20,6 @@ import ( + "context" + "io/ioutil" + "os" +- "path/filepath" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" +@@ -89,7 +88,10 @@ func WithVolumes(volumeMounts map[string + }() + + for host, volume := range volumeMounts { +- src := filepath.Join(root, volume) ++ src, err := fs.RootPath(root, volume) ++ if err != nil { ++ return errors.Wrapf(err, "rootpath on root %s, volume %s", root, volume) ++ } + if _, err := os.Stat(src); err != nil { + if os.IsNotExist(err) { + // Skip copying directory if it does not exist. diff -Nru containerd-1.2.6/debian/patches/CVE-2022-24769.patch containerd-1.5.9/debian/patches/CVE-2022-24769.patch --- containerd-1.2.6/debian/patches/CVE-2022-24769.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/CVE-2022-24769.patch 2022-12-12 08:49:02.000000000 +0000 @@ -0,0 +1,147 @@ +From 6906b57c721f9114377ceb069662b196876915c0 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Wed, 8 Sep 2021 12:57:23 -0700 +Subject: [PATCH] Fix the Inheritable capability defaults. + +The Linux kernel never sets the Inheritable capability flag to +anything other than empty. Non-empty values are always exclusively +set by userspace code. + +[The kernel stopped defaulting this set of capability values to the + full set in 2000 after a privilege escalation with Capabilities + affecting Sendmail and others.] + +Signed-off-by: Andrew G. Morgan +--- + oci/spec.go | 7 +++---- + oci/spec_opts.go | 5 +---- + oci/spec_opts_linux_test.go | 4 ---- + oci/spec_test.go | 5 ++--- + pkg/cri/server/container_create_linux_test.go | 3 +-- + 5 files changed, 7 insertions(+), 17 deletions(-) + +--- containerd-1.5.5.orig/oci/spec.go ++++ containerd-1.5.5/oci/spec.go +@@ -148,10 +148,9 @@ func populateDefaultUnixSpec(ctx context + GID: 0, + }, + Capabilities: &specs.LinuxCapabilities{ +- Bounding: defaultUnixCaps(), +- Permitted: defaultUnixCaps(), +- Inheritable: defaultUnixCaps(), +- Effective: defaultUnixCaps(), ++ Bounding: defaultUnixCaps(), ++ Permitted: defaultUnixCaps(), ++ Effective: defaultUnixCaps(), + }, + Rlimits: []specs.POSIXRlimit{ + { +--- containerd-1.5.5.orig/oci/spec_opts.go ++++ containerd-1.5.5/oci/spec_opts.go +@@ -788,7 +788,6 @@ func WithCapabilities(caps []string) Spe + s.Process.Capabilities.Bounding = caps + s.Process.Capabilities.Effective = caps + s.Process.Capabilities.Permitted = caps +- s.Process.Capabilities.Inheritable = caps + + return nil + } +@@ -823,7 +822,6 @@ func WithAddedCapabilities(caps []string + &s.Process.Capabilities.Bounding, + &s.Process.Capabilities.Effective, + &s.Process.Capabilities.Permitted, +- &s.Process.Capabilities.Inheritable, + } { + if !capsContain(*cl, c) { + *cl = append(*cl, c) +@@ -843,7 +841,6 @@ func WithDroppedCapabilities(caps []stri + &s.Process.Capabilities.Bounding, + &s.Process.Capabilities.Effective, + &s.Process.Capabilities.Permitted, +- &s.Process.Capabilities.Inheritable, + } { + removeCap(cl, c) + } +@@ -858,7 +855,7 @@ func WithDroppedCapabilities(caps []stri + func WithAmbientCapabilities(caps []string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setCapabilities(s) +- ++ s.Process.Capabilities.Inheritable = caps + s.Process.Capabilities.Ambient = caps + return nil + } +--- containerd-1.5.5.orig/oci/spec_opts_linux_test.go ++++ containerd-1.5.5/oci/spec_opts_linux_test.go +@@ -40,7 +40,6 @@ func TestAddCaps(t *testing.T) { + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, +- s.Process.Capabilities.Inheritable, + } { + if !capsContain(cl, "CAP_CHOWN") { + t.Errorf("cap list %d does not contain added cap", i) +@@ -64,7 +63,6 @@ func TestDropCaps(t *testing.T) { + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, +- s.Process.Capabilities.Inheritable, + } { + if capsContain(cl, "CAP_CHOWN") { + t.Errorf("cap list %d contains dropped cap", i) +@@ -83,7 +81,6 @@ func TestDropCaps(t *testing.T) { + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, +- s.Process.Capabilities.Inheritable, + } { + if capsContain(cl, "CAP_FOWNER") { + t.Errorf("cap list %d contains dropped cap", i) +@@ -104,7 +101,6 @@ func TestDropCaps(t *testing.T) { + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, +- s.Process.Capabilities.Inheritable, + } { + if len(cl) != 0 { + t.Errorf("cap list %d is not empty", i) +--- containerd-1.5.5.orig/oci/spec_test.go ++++ containerd-1.5.5/oci/spec_test.go +@@ -45,7 +45,6 @@ func TestGenerateSpec(t *testing.T) { + for _, cl := range [][]string{ + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Permitted, +- s.Process.Capabilities.Inheritable, + s.Process.Capabilities.Effective, + } { + for i := 0; i < len(defaults); i++ { +@@ -193,8 +192,8 @@ func TestWithCapabilities(t *testing.T) + if len(s.Process.Capabilities.Permitted) != 1 || s.Process.Capabilities.Permitted[0] != "CAP_SYS_ADMIN" { + t.Error("Unexpected capabilities set") + } +- if len(s.Process.Capabilities.Inheritable) != 1 || s.Process.Capabilities.Inheritable[0] != "CAP_SYS_ADMIN" { +- t.Error("Unexpected capabilities set") ++ if len(s.Process.Capabilities.Inheritable) != 0 { ++ t.Errorf("Unexpected capabilities set: length is non zero (%d)", len(s.Process.Capabilities.Inheritable)) + } + } + +--- containerd-1.5.5.orig/pkg/cri/server/container_create_linux_test.go ++++ containerd-1.5.5/pkg/cri/server/container_create_linux_test.go +@@ -254,15 +254,14 @@ func TestContainerCapabilities(t *testin + for _, include := range test.includes { + assert.Contains(t, spec.Process.Capabilities.Bounding, include) + assert.Contains(t, spec.Process.Capabilities.Effective, include) +- assert.Contains(t, spec.Process.Capabilities.Inheritable, include) + assert.Contains(t, spec.Process.Capabilities.Permitted, include) + } + for _, exclude := range test.excludes { + assert.NotContains(t, spec.Process.Capabilities.Bounding, exclude) + assert.NotContains(t, spec.Process.Capabilities.Effective, exclude) +- assert.NotContains(t, spec.Process.Capabilities.Inheritable, exclude) + assert.NotContains(t, spec.Process.Capabilities.Permitted, exclude) + } ++ assert.Empty(t, spec.Process.Capabilities.Inheritable) + assert.Empty(t, spec.Process.Capabilities.Ambient) + } + } diff -Nru containerd-1.2.6/debian/patches/CVE-2022-24778.patch containerd-1.5.9/debian/patches/CVE-2022-24778.patch --- containerd-1.2.6/debian/patches/CVE-2022-24778.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/CVE-2022-24778.patch 2022-12-12 08:49:17.000000000 +0000 @@ -0,0 +1,68 @@ +From 6fdd9818a4d8142107b7ecd767d839c9707700d9 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Thu, 17 Mar 2022 15:52:56 -0400 +Subject: [PATCH] images: Add list of Platforms to CheckAuthorization() + +To be able to properly perform an authorization check on an image we need +to know the platform to perform check when in cryptManifestList(). Extend +the logic for cryptoOp == cryptoOpUnwrapOnly to skip over manifests that +do not correspond to the local platform and return an error if no manifest +was found that matches the local platform. + +The following projects seem NOT to be affect due to the change in the code +path of CheckAuthorization() since they are not using it: + +- cri-o +- nerdctl +- skopeo +- buildah +- podman + +The impact on imgcrypt via ctr-enc is not so clear either since +CheckAuthorization() is not called on the server side but by the ctr-enc +client, thus can be modified easily. + +Resolves: https://github.com/containerd/imgcrypt/issues/69 +Signed-off-by: Stefan Berger +--- + images/encryption/encryption.go | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/images/encryption/encryption.go b/images/encryption/encryption.go +index 204d32c0..291424d1 100644 +--- a//vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go ++++ b/vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go +@@ -50,6 +50,13 @@ const ( + // LayerFilter allows to select Layers by certain criteria + type LayerFilter func(desc ocispec.Descriptor) bool + ++// isLocalPlatform determines whether the given platform matches the local one ++func isLocalPlatform(platform *ocispec.Platform) bool { ++ matcher := platforms.NewMatcher(*platform) ++ ++ return matcher.Match(platforms.DefaultSpec()) ++} ++ + // IsEncryptedDiff returns true if mediaType is a known encrypted media type. + func IsEncryptedDiff(ctx context.Context, mediaType string) bool { + switch mediaType { +@@ -380,6 +387,9 @@ func cryptManifestList(ctx context.Context, cs content.Store, desc ocispec.Descr + var newManifests []ocispec.Descriptor + modified := false + for _, manifest := range index.Manifests { ++ if cryptoOp == cryptoOpUnwrapOnly && !isLocalPlatform(manifest.Platform) { ++ continue ++ } + newManifest, m, err := cryptChildren(ctx, cs, manifest, cc, lf, cryptoOp, manifest.Platform) + if err != nil || cryptoOp == cryptoOpUnwrapOnly { + return ocispec.Descriptor{}, false, err +@@ -389,6 +399,9 @@ func cryptManifestList(ctx context.Context, cs content.Store, desc ocispec.Descr + } + newManifests = append(newManifests, newManifest) + } ++ if cryptoOp == cryptoOpUnwrapOnly { ++ return ocispec.Descriptor{}, false, fmt.Errorf("No manifest found for local platform") ++ } + + if modified { + // we need to update the index diff -Nru containerd-1.2.6/debian/patches/CVE-2022-31030.patch containerd-1.5.9/debian/patches/CVE-2022-31030.patch --- containerd-1.2.6/debian/patches/CVE-2022-31030.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/CVE-2022-31030.patch 2022-12-12 08:49:27.000000000 +0000 @@ -0,0 +1,233 @@ +From 49ca87d7270091b8193301dc2f6759e9aa7c97b1 Mon Sep 17 00:00:00 2001 +From: Kazuyoshi Kato +Date: Mon, 16 May 2022 17:33:33 +0000 +Subject: [PATCH 1/2] Limit the response size of ExecSync + +Signed-off-by: Kazuyoshi Kato +--- + pkg/cri/server/container_execsync.go | 39 +++++++++++++++++- + pkg/cri/server/container_execsync_test.go | 49 +++++++++++++++++++++++ + 2 files changed, 86 insertions(+), 2 deletions(-) + create mode 100644 pkg/cri/server/container_execsync_test.go + +diff --git a/pkg/cri/server/container_execsync.go b/pkg/cri/server/container_execsync.go +index 3bf8d85c07b..15221f9bd09 100644 +--- a/pkg/cri/server/container_execsync.go ++++ b/pkg/cri/server/container_execsync.go +@@ -19,6 +19,7 @@ package server + import ( + "bytes" + "io" ++ "errors" + "syscall" + "time" + +@@ -38,14 +39,48 @@ import ( + cioutil "github.com/containerd/containerd/pkg/ioutil" + ) + ++type cappedWriter struct { ++ w io.WriteCloser ++ remain int ++} ++ ++var errNoRemain = errors.New("no more space to write") ++ ++func (cw *cappedWriter) Write(p []byte) (int, error) { ++ if cw.remain <= 0 { ++ return 0, errNoRemain ++ } ++ ++ end := cw.remain ++ if end > len(p) { ++ end = len(p) ++ } ++ written, err := cw.w.Write(p[0:end]) ++ cw.remain -= written ++ ++ if err != nil { ++ return written, err ++ } ++ if written < len(p) { ++ return written, errNoRemain ++ } ++ return written, nil ++} ++ ++func (cw *cappedWriter) Close() error { ++ return cw.w.Close() ++} ++ + // ExecSync executes a command in the container, and returns the stdout output. + // If command exits with a non-zero exit code, an error is returned. + func (c *criService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (*runtime.ExecSyncResponse, error) { ++ const maxStreamSize = 1024 * 1024 * 16 ++ + var stdout, stderr bytes.Buffer + exitCode, err := c.execInContainer(ctx, r.GetContainerId(), execOptions{ + cmd: r.GetCmd(), +- stdout: cioutil.NewNopWriteCloser(&stdout), +- stderr: cioutil.NewNopWriteCloser(&stderr), ++ stdout: &cappedWriter{w: cioutil.NewNopWriteCloser(&stdout), remain: maxStreamSize}, ++ stderr: &cappedWriter{w: cioutil.NewNopWriteCloser(&stderr), remain: maxStreamSize}, + timeout: time.Duration(r.GetTimeout()) * time.Second, + }) + if err != nil { +diff --git a/pkg/cri/server/container_execsync_test.go b/pkg/cri/server/container_execsync_test.go +new file mode 100644 +index 00000000000..18856b8fca4 +--- /dev/null ++++ b/pkg/cri/server/container_execsync_test.go +@@ -0,0 +1,49 @@ ++/* ++ Copyright The containerd Authors. ++ ++ Licensed under the Apache License, Version 2.0 (the "License"); ++ you may not use this file except in compliance with the License. ++ You may obtain a copy of the License at ++ ++ http://www.apache.org/licenses/LICENSE-2.0 ++ ++ Unless required by applicable law or agreed to in writing, software ++ distributed under the License is distributed on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ See the License for the specific language governing permissions and ++ limitations under the License. ++*/ ++ ++package server ++ ++import ( ++ "bytes" ++ "testing" ++ ++ cioutil "github.com/containerd/containerd/pkg/ioutil" ++ "github.com/stretchr/testify/assert" ++) ++ ++func TestCWWrite(t *testing.T) { ++ var buf bytes.Buffer ++ cw := &cappedWriter{w: cioutil.NewNopWriteCloser(&buf), remain: 10} ++ ++ n, err := cw.Write([]byte("hello")) ++ assert.NoError(t, err) ++ assert.Equal(t, 5, n) ++ ++ n, err = cw.Write([]byte("helloworld")) ++ assert.Equal(t, []byte("hellohello"), buf.Bytes(), "partial write") ++ assert.Equal(t, 5, n) ++ assert.ErrorIs(t, err, errNoRemain) ++ ++ _, err = cw.Write([]byte("world")) ++ assert.ErrorIs(t, err, errNoRemain) ++} ++ ++func TestCWClose(t *testing.T) { ++ var buf bytes.Buffer ++ cw := &cappedWriter{w: cioutil.NewNopWriteCloser(&buf), remain: 5} ++ err := cw.Close() ++ assert.NoError(t, err) ++} + +From 40aa4f3f1bd7bd72839fa05d1ff61d58cba4430b Mon Sep 17 00:00:00 2001 +From: Kazuyoshi Kato +Date: Thu, 2 Jun 2022 03:53:11 +0000 +Subject: [PATCH 2/2] Implicitly discard the input to drain the reader + +Signed-off-by: Derek McGowan +--- + pkg/cri/server/container_execsync.go | 26 ++++++++++++++--------- + pkg/cri/server/container_execsync_test.go | 11 ++++++---- + 2 files changed, 23 insertions(+), 14 deletions(-) + +diff --git a/pkg/cri/server/container_execsync.go b/pkg/cri/server/container_execsync.go +index 15221f9bd09..1cb34443548 100644 +--- a/pkg/cri/server/container_execsync.go ++++ b/pkg/cri/server/container_execsync.go +@@ -19,7 +19,6 @@ package server + import ( + "bytes" + "io" +- "errors" + "syscall" + "time" + +@@ -44,11 +43,9 @@ type cappedWriter struct { + remain int + } + +-var errNoRemain = errors.New("no more space to write") +- + func (cw *cappedWriter) Write(p []byte) (int, error) { + if cw.remain <= 0 { +- return 0, errNoRemain ++ return len(p), nil + } + + end := cw.remain +@@ -61,26 +58,35 @@ func (cw *cappedWriter) Write(p []byte) (int, error) { + if err != nil { + return written, err + } +- if written < len(p) { +- return written, errNoRemain +- } +- return written, nil ++ return len(p), nil + } + + func (cw *cappedWriter) Close() error { + return cw.w.Close() + } + ++func (cw *cappedWriter) isFull() bool { ++ return cw.remain <= 0 ++} ++ + // ExecSync executes a command in the container, and returns the stdout output. + // If command exits with a non-zero exit code, an error is returned. + func (c *criService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (*runtime.ExecSyncResponse, error) { + const maxStreamSize = 1024 * 1024 * 16 + + var stdout, stderr bytes.Buffer ++ ++ // cappedWriter truncates the output. In that case, the size of ++ // the ExecSyncResponse will hit the CRI plugin's gRPC response limit. ++ // Thus the callers outside of the containerd process (e.g. Kubelet) never see ++ // the truncated output. ++ cout := &cappedWriter{w: cioutil.NewNopWriteCloser(&stdout), remain: maxStreamSize} ++ cerr := &cappedWriter{w: cioutil.NewNopWriteCloser(&stderr), remain: maxStreamSize} ++ + exitCode, err := c.execInContainer(ctx, r.GetContainerId(), execOptions{ + cmd: r.GetCmd(), +- stdout: &cappedWriter{w: cioutil.NewNopWriteCloser(&stdout), remain: maxStreamSize}, +- stderr: &cappedWriter{w: cioutil.NewNopWriteCloser(&stderr), remain: maxStreamSize}, ++ stdout: cout, ++ stderr: cerr, + timeout: time.Duration(r.GetTimeout()) * time.Second, + }) + if err != nil { +diff --git a/pkg/cri/server/container_execsync_test.go b/pkg/cri/server/container_execsync_test.go +index 18856b8fca4..98990964963 100644 +--- a/pkg/cri/server/container_execsync_test.go ++++ b/pkg/cri/server/container_execsync_test.go +@@ -33,12 +33,15 @@ func TestCWWrite(t *testing.T) { + assert.Equal(t, 5, n) + + n, err = cw.Write([]byte("helloworld")) +- assert.Equal(t, []byte("hellohello"), buf.Bytes(), "partial write") +- assert.Equal(t, 5, n) +- assert.ErrorIs(t, err, errNoRemain) ++ assert.NoError(t, err, "no errors even it hits the cap") ++ assert.Equal(t, 10, n, "no indication of partial write") ++ assert.True(t, cw.isFull()) ++ assert.Equal(t, []byte("hellohello"), buf.Bytes(), "the underlying writer is capped") + + _, err = cw.Write([]byte("world")) +- assert.ErrorIs(t, err, errNoRemain) ++ assert.NoError(t, err) ++ assert.True(t, cw.isFull()) ++ assert.Equal(t, []byte("hellohello"), buf.Bytes(), "the underlying writer is capped") + } + + func TestCWClose(t *testing.T) { diff -Nru containerd-1.2.6/debian/patches/preserve-debug-info.patch containerd-1.5.9/debian/patches/preserve-debug-info.patch --- containerd-1.2.6/debian/patches/preserve-debug-info.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/preserve-debug-info.patch 2022-02-09 20:38:58.000000000 +0000 @@ -0,0 +1,10 @@ +--- a/Makefile ++++ b/Makefile +@@ -53,7 +53,6 @@ + endif + + ifndef GODEBUG +- EXTRA_LDFLAGS += -s -w + DEBUG_GO_GCFLAGS := + DEBUG_TAGS := + else diff -Nru containerd-1.2.6/debian/patches/series containerd-1.5.9/debian/patches/series --- containerd-1.2.6/debian/patches/series 2019-04-16 01:39:52.000000000 +0000 +++ containerd-1.5.9/debian/patches/series 2022-12-12 10:25:11.000000000 +0000 @@ -0,0 +1,7 @@ +skip-tests-with-privilege.patch +preserve-debug-info.patch +CVE-2022-23648.patch +CVE-2022-23471.patch +CVE-2022-24769.patch +CVE-2022-24778.patch +CVE-2022-31030.patch diff -Nru containerd-1.2.6/debian/patches/skip-tests-with-privilege.patch containerd-1.5.9/debian/patches/skip-tests-with-privilege.patch --- containerd-1.2.6/debian/patches/skip-tests-with-privilege.patch 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/debian/patches/skip-tests-with-privilege.patch 2022-02-09 20:38:58.000000000 +0000 @@ -0,0 +1,149 @@ +Description: Skip tests which require a certain level of privilege + During build we cannot bindmount sysfs and cgroupfs in a chroot which leads to + failures. +Author: Lucas Kanashiro +Forwarded: not-needed +Last-Updated: 2021-05-20 + +--- a/pkg/cri/server/container_create_linux_test.go ++++ b/pkg/cri/server/container_create_linux_test.go +@@ -187,6 +187,7 @@ + } + + func TestContainerCapabilities(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -267,6 +268,7 @@ + } + + func TestContainerSpecTty(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -289,6 +291,7 @@ + } + + func TestContainerSpecDefaultPath(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -311,6 +314,7 @@ + } + + func TestContainerSpecReadonlyRootfs(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -328,6 +332,7 @@ + } + + func TestContainerSpecWithExtraMounts(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -389,6 +394,7 @@ + } + + func TestContainerAndSandboxPrivileged(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -591,6 +597,7 @@ + } + + func TestPrivilegedBindMount(t *testing.T) { ++ t.Skip("It requires privilege to mount sysfs and cgroupfs. Not achievable during the build.") + testPid := uint32(1234) + c := newTestCRIService() + testSandboxID := "sandbox-id" +@@ -741,6 +748,7 @@ + } + + func TestPidNamespace(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testPid := uint32(1234) + testSandboxID := "sandbox-id" +@@ -782,6 +790,7 @@ + } + + func TestNoDefaultRunMount(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testPid := uint32(1234) + testSandboxID := "sandbox-id" +@@ -1086,6 +1095,7 @@ + } + + func TestMaskedAndReadonlyPaths(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -1174,6 +1184,7 @@ + } + + func TestHostname(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" +@@ -1305,6 +1316,7 @@ + } + + func TestPrivilegedDevices(t *testing.T) { ++ t.Skip("It requires privilege to test devices. Not achievable during the build.") + testPid := uint32(1234) + c := newTestCRIService() + testSandboxID := "sandbox-id" +@@ -1367,6 +1379,7 @@ + } + + func TestBaseOCISpec(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + c := newTestCRIService() + baseLimit := int64(100) + c.baseOCISpecs = map[string]*oci.Spec{ +--- a/pkg/cri/server/container_create_test.go ++++ b/pkg/cri/server/container_create_test.go +@@ -56,6 +56,7 @@ + const testImageName = "container-image-name" + + func TestGeneralContainerSpec(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + testID := "test-id" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() +@@ -69,6 +70,7 @@ + } + + func TestPodAnnotationPassthroughContainerSpec(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + if goruntime.GOOS == "darwin" { + t.Skip("not implemented on Darwin") + } +@@ -277,6 +279,7 @@ + } + + func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) { ++ t.Skip("It requires HugeTLB controller enabled which requires mounting cgroupfs. Not achievable during the build.") + if goruntime.GOOS == "darwin" { + t.Skip("not implemented on Darwin") + } +--- a/pkg/cri/server/container_update_resources_linux_test.go ++++ b/pkg/cri/server/container_update_resources_linux_test.go +@@ -27,6 +27,7 @@ + ) + + func TestUpdateOCILinuxResource(t *testing.T) { ++ t.Skip("It requires some privileges not achievable during the build.") + oomscoreadj := new(int) + *oomscoreadj = -500 + for desc, test := range map[string]struct { diff -Nru containerd-1.2.6/debian/rules containerd-1.5.9/debian/rules --- containerd-1.2.6/debian/rules 2019-04-16 01:39:52.000000000 +0000 +++ containerd-1.5.9/debian/rules 2022-02-09 20:38:58.000000000 +0000 @@ -5,11 +5,42 @@ # temporary build path (see http://golang.org/doc/code.html#GOPATH) OUR_GOPATH := $(CURDIR)/.gopath export GOPATH := $(OUR_GOPATH) +export GOCACHE := $(CURDIR)/.gocache + +# https://blog.golang.org/go116-module-changes (TODO figure out a new solution for Go 1.17+) +export GO111MODULE := off + +# riscv64 doesn't support cgo +# https://github.com/golang/go/issues/36641 +ifeq (riscv64, $(DEB_BUILD_ARCH)) +TAGS += no_btrfs +SKIP += github.com/containerd/containerd/snapshots/btrfs +endif + +# build explicitly against Go 1.13 (for now): +# https://github.com/containerd/containerd/issues/4509 +# https://github.com/containerd/containerd/pull/4050 +# https://github.com/golang/go/issues/37942 +# (containerd 1.4+ and Go 1.15+ can go back to "golang-go") +export PATH := /usr/lib/go-1.13/bin:$(PATH) + +override_dh_gencontrol: + # use "dh_golang" to generate "misc:Built-Using" (via "go list") + DH_GOLANG_BUILDPKG=' \ + -tags "$(TAGS)" \ + github.com/containerd/containerd/cmd/containerd \ + github.com/containerd/containerd/cmd/containerd-shim \ + github.com/containerd/containerd/cmd/containerd-shim-runc-v1 \ + github.com/containerd/containerd/cmd/containerd-shim-runc-v2 \ + github.com/containerd/containerd/cmd/containerd-stress \ + github.com/containerd/containerd/cmd/ctr \ + ' dh_golang --builddirectory='$(OUR_GOPATH:$(CURDIR)/%=%)' + dh_gencontrol override_dh_auto_configure: # copy pristine source for "/usr/share/gocode" to get into "golang-github-containerd-containerd-dev" before we muddy it with build artifacts, etc mkdir -p .pristine-source - tar -c --exclude=debian --exclude=.pc --exclude=.pristine-source . | tar -xC .pristine-source + tar -c --exclude=debian --exclude=.pc --exclude=.pristine-source --exclude=vendor . | tar -xC .pristine-source # set up GOPATH symlink farm mkdir -p '$(OUR_GOPATH)/src/github.com/containerd' ln -sfT '$(CURDIR)' '$(OUR_GOPATH)/src/github.com/containerd/containerd' @@ -20,11 +51,12 @@ LDFLAGS='' \ VERSION='$(shell dpkg-parsechangelog -SVersion)' \ REVISION='' \ + BUILDTAGS='$(TAGS)' \ && make man override_dh_auto_test: ifneq (arm, $(DEB_HOST_ARCH_CPU)) # skip the tests on armhf ("--- FAIL: TestParseSelector/linux (0.00s) platforms_test.go:292: arm support not fully implemented: not implemented") - cd '$(OUR_GOPATH)/src/github.com/containerd/containerd' && make test + cd '$(OUR_GOPATH)/src/github.com/containerd/containerd' && make test SKIPTESTS='$(SKIP)' endif override_dh_auto_install: @@ -33,5 +65,12 @@ mkdir -p debian/tmp/usr/share/gocode/src/github.com/containerd \ && mv .pristine-source debian/tmp/usr/share/gocode/src/github.com/containerd/containerd +override_dh_installsystemd: + dh_installsystemd + # replace "/usr/local/bin/containerd" with "/usr/bin/containerd" in our systemd service file + grep '/usr/local/bin/containerd' debian/*/lib/systemd/system/containerd.service \ + && sed -i 's!/usr/local/bin/containerd!/usr/bin/containerd!g' debian/*/lib/systemd/system/containerd.service \ + && ! grep '/usr/local/bin/containerd' debian/*/lib/systemd/system/containerd.service + %: - dh $@ --with=systemd + dh $@ diff -Nru containerd-1.2.6/defaults/defaults.go containerd-1.5.9/defaults/defaults.go --- containerd-1.2.6/defaults/defaults.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/defaults/defaults.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,4 +23,10 @@ // DefaultMaxSendMsgSize defines the default maximum message size for // sending protobufs passed over the GRPC API. DefaultMaxSendMsgSize = 16 << 20 + // DefaultRuntimeNSLabel defines the namespace label to check for the + // default runtime + DefaultRuntimeNSLabel = "containerd.io/defaults/runtime" + // DefaultSnapshotterNSLabel defines the namespace label to check for the + // default snapshotter + DefaultSnapshotterNSLabel = "containerd.io/defaults/snapshotter" ) diff -Nru containerd-1.2.6/defaults/defaults_unix.go containerd-1.5.9/defaults/defaults_unix.go --- containerd-1.2.6/defaults/defaults_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/defaults/defaults_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,4 +32,8 @@ // DefaultFIFODir is the default location used by client-side cio library // to store FIFOs. DefaultFIFODir = "/run/containerd/fifo" + // DefaultRuntime is the default linux runtime + DefaultRuntime = "io.containerd.runc.v2" + // DefaultConfigDir is the default location for config files. + DefaultConfigDir = "/etc/containerd" ) diff -Nru containerd-1.2.6/defaults/defaults_windows.go containerd-1.5.9/defaults/defaults_windows.go --- containerd-1.2.6/defaults/defaults_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/defaults/defaults_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,10 +26,13 @@ var ( // DefaultRootDir is the default location used by containerd to store // persistent data - DefaultRootDir = filepath.Join(os.Getenv("programfiles"), "containerd", "root") + DefaultRootDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "root") // DefaultStateDir is the default location used by containerd to store // transient data - DefaultStateDir = filepath.Join(os.Getenv("programfiles"), "containerd", "state") + DefaultStateDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "state") + + // DefaultConfigDir is the default location for config files. + DefaultConfigDir = filepath.Join(os.Getenv("programfiles"), "containerd") ) const ( @@ -40,4 +43,6 @@ // DefaultFIFODir is the default location used by client-side cio library // to store FIFOs. Unused on Windows. DefaultFIFODir = "" + // DefaultRuntime is the default windows runtime + DefaultRuntime = "io.containerd.runhcs.v1" ) diff -Nru containerd-1.2.6/diff/apply/apply.go containerd-1.5.9/diff/apply/apply.go --- containerd-1.2.6/diff/apply/apply.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff/apply/apply.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,12 +22,8 @@ "io/ioutil" "time" - "github.com/containerd/containerd/archive" - "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/diff" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" digest "github.com/opencontainers/go-digest" @@ -53,67 +49,74 @@ // Apply applies the content associated with the provided digests onto the // provided mounts. Archive content will be extracted and decompressed if // necessary. -func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) { +func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (d ocispec.Descriptor, err error) { t1 := time.Now() defer func() { if err == nil { log.G(ctx).WithFields(logrus.Fields{ - "d": time.Since(t1), - "dgst": desc.Digest, - "size": desc.Size, - "media": desc.MediaType, + "d": time.Since(t1), + "digest": desc.Digest, + "size": desc.Size, + "media": desc.MediaType, }).Debugf("diff applied") } }() - isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType) + var config diff.ApplyConfig + for _, o := range opts { + if err := o(ctx, desc, &config); err != nil { + return emptyDesc, errors.Wrap(err, "failed to apply config opt") + } + } + + ra, err := s.store.ReaderAt(ctx, desc) if err != nil { - return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType) + return emptyDesc, errors.Wrap(err, "failed to get reader from content store") } + defer ra.Close() - var ocidesc ocispec.Descriptor - if err := mount.WithTempMount(ctx, mounts, func(root string) error { - ra, err := s.store.ReaderAt(ctx, desc) - if err != nil { - return errors.Wrap(err, "failed to get reader from content store") - } - defer ra.Close() - - r := content.NewReader(ra) - if isCompressed { - ds, err := compression.DecompressStream(r) - if err != nil { - return err - } - defer ds.Close() - r = ds + var processors []diff.StreamProcessor + processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra)) + processors = append(processors, processor) + for { + if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil { + return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType) + } + processors = append(processors, processor) + if processor.MediaType() == ocispec.MediaTypeImageLayer { + break } + } + defer processor.Close() - digester := digest.Canonical.Digester() - rc := &readCounter{ - r: io.TeeReader(r, digester.Hash()), - } + digester := digest.Canonical.Digester() + rc := &readCounter{ + r: io.TeeReader(processor, digester.Hash()), + } - if _, err := archive.Apply(ctx, root, rc); err != nil { - return err - } + if err := apply(ctx, mounts, rc); err != nil { + return emptyDesc, err + } - // Read any trailing data - if _, err := io.Copy(ioutil.Discard, rc); err != nil { - return err - } + // Read any trailing data + if _, err := io.Copy(ioutil.Discard, rc); err != nil { + return emptyDesc, err + } - ocidesc = ocispec.Descriptor{ - MediaType: ocispec.MediaTypeImageLayer, - Size: rc.c, - Digest: digester.Digest(), + for _, p := range processors { + if ep, ok := p.(interface { + Err() error + }); ok { + if err := ep.Err(); err != nil { + return emptyDesc, err + } } - return nil - - }); err != nil { - return emptyDesc, err } - return ocidesc, nil + return ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageLayer, + Size: rc.c, + Digest: digester.Digest(), + }, nil } type readCounter struct { diff -Nru containerd-1.2.6/diff/apply/apply_linux.go containerd-1.5.9/diff/apply/apply_linux.go --- containerd-1.2.6/diff/apply/apply_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/apply/apply_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,134 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apply + +import ( + "context" + "io" + "strings" + + "github.com/containerd/containerd/archive" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/userns" + "github.com/pkg/errors" +) + +func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error { + switch { + case len(mounts) == 1 && mounts[0].Type == "overlay": + // OverlayConvertWhiteout (mknod c 0 0) doesn't work in userns. + // https://github.com/containerd/containerd/issues/3762 + if userns.RunningInUserNS() { + break + } + path, parents, err := getOverlayPath(mounts[0].Options) + if err != nil { + if errdefs.IsInvalidArgument(err) { + break + } + return err + } + opts := []archive.ApplyOpt{ + archive.WithConvertWhiteout(archive.OverlayConvertWhiteout), + } + if len(parents) > 0 { + opts = append(opts, archive.WithParents(parents)) + } + _, err = archive.Apply(ctx, path, r, opts...) + return err + case len(mounts) == 1 && mounts[0].Type == "aufs": + path, parents, err := getAufsPath(mounts[0].Options) + if err != nil { + if errdefs.IsInvalidArgument(err) { + break + } + return err + } + opts := []archive.ApplyOpt{ + archive.WithConvertWhiteout(archive.AufsConvertWhiteout), + } + if len(parents) > 0 { + opts = append(opts, archive.WithParents(parents)) + } + _, err = archive.Apply(ctx, path, r, opts...) + return err + } + return mount.WithTempMount(ctx, mounts, func(root string) error { + _, err := archive.Apply(ctx, root, r) + return err + }) +} + +func getOverlayPath(options []string) (upper string, lower []string, err error) { + const upperdirPrefix = "upperdir=" + const lowerdirPrefix = "lowerdir=" + + for _, o := range options { + if strings.HasPrefix(o, upperdirPrefix) { + upper = strings.TrimPrefix(o, upperdirPrefix) + } else if strings.HasPrefix(o, lowerdirPrefix) { + lower = strings.Split(strings.TrimPrefix(o, lowerdirPrefix), ":") + } + } + if upper == "" { + return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "upperdir not found") + } + + return +} + +// getAufsPath handles options as given by the containerd aufs package only, +// formatted as "br:=rw[:=ro+wh]*" +func getAufsPath(options []string) (upper string, lower []string, err error) { + const ( + sep = ":" + brPrefix = "br:" + rwSuffix = "=rw" + roSuffix = "=ro+wh" + ) + for _, o := range options { + if strings.HasPrefix(o, brPrefix) { + o = strings.TrimPrefix(o, brPrefix) + } else { + continue + } + + for _, b := range strings.Split(o, sep) { + if strings.HasSuffix(b, rwSuffix) { + if upper != "" { + return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "multiple rw branch found") + } + upper = strings.TrimSuffix(b, rwSuffix) + } else if strings.HasSuffix(b, roSuffix) { + if upper == "" { + return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch be first") + } + lower = append(lower, strings.TrimSuffix(b, roSuffix)) + } else { + return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "unhandled aufs suffix") + } + + } + } + if upper == "" { + return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch not found") + } + return +} diff -Nru containerd-1.2.6/diff/apply/apply_linux_test.go containerd-1.5.9/diff/apply/apply_linux_test.go --- containerd-1.2.6/diff/apply/apply_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/apply/apply_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apply + +import ( + "testing" +) + +func TestGetOverlayPath(t *testing.T) { + good := []string{"upperdir=/test/upper", "lowerdir=/test/lower1:/test/lower2", "workdir=/test/work"} + path, parents, err := getOverlayPath(good) + if err != nil { + t.Fatalf("Get overlay path failed: %v", err) + } + if path != "/test/upper" { + t.Fatalf("Unexpected upperdir: %q", path) + } + if len(parents) != 2 || parents[0] != "/test/lower1" || parents[1] != "/test/lower2" { + t.Fatalf("Unexpected parents: %v", parents) + } + + bad := []string{"lowerdir=/test/lower"} + _, _, err = getOverlayPath(bad) + if err == nil { + t.Fatalf("An error is expected") + } +} + +func TestGetAufsPath(t *testing.T) { + for _, test := range []struct { + options []string + expectErr bool + }{ + { + options: []string{"random:option", "br:/test/rw=rw:/test/ro=ro+wh"}, + expectErr: false, + }, + { + options: []string{"random:option"}, + expectErr: true, + }, + { + options: []string{"br:/test/ro=ro+wh"}, + expectErr: true, + }, + } { + path, parents, err := getAufsPath(test.options) + if test.expectErr { + if err == nil { + t.Fatalf("An error is expected") + } + continue + } + if err != nil { + t.Fatalf("Get aufs path failed: %v", err) + } + if path != "/test/rw" { + t.Fatalf("Unexpected rw dir: %q", path) + } + if len(parents) != 1 || parents[0] != "/test/ro" { + t.Fatalf("Unexpected parents: %v", parents) + } + + } +} diff -Nru containerd-1.2.6/diff/apply/apply_other.go containerd-1.5.9/diff/apply/apply_other.go --- containerd-1.2.6/diff/apply/apply_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/apply/apply_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apply + +import ( + "context" + "io" + + "github.com/containerd/containerd/archive" + "github.com/containerd/containerd/mount" +) + +func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error { + return mount.WithTempMount(ctx, mounts, func(root string) error { + _, err := archive.Apply(ctx, root, r) + return err + }) +} diff -Nru containerd-1.2.6/diff/diff.go containerd-1.5.9/diff/diff.go --- containerd-1.2.6/diff/diff.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff/diff.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ "context" "github.com/containerd/containerd/mount" + "github.com/gogo/protobuf/types" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -51,6 +52,15 @@ Compare(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error) } +// ApplyConfig is used to hold parameters needed for a apply operation +type ApplyConfig struct { + // ProcessorPayloads specifies the payload sent to various processors + ProcessorPayloads map[string]*types.Any +} + +// ApplyOpt is used to configure an Apply operation +type ApplyOpt func(context.Context, ocispec.Descriptor, *ApplyConfig) error + // Applier allows applying diffs between mounts type Applier interface { // Apply applies the content referred to by the given descriptor to @@ -58,7 +68,7 @@ // implementation and content descriptor. For example, in the common // case the descriptor is a file system difference in tar format, // that tar would be applied on top of the mounts. - Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error) + Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount, opts ...ApplyOpt) (ocispec.Descriptor, error) } // WithMediaType sets the media type to use for creating the diff, without @@ -87,3 +97,11 @@ return nil } } + +// WithPayloads sets the apply processor payloads to the config +func WithPayloads(payloads map[string]*types.Any) ApplyOpt { + return func(_ context.Context, _ ocispec.Descriptor, c *ApplyConfig) error { + c.ProcessorPayloads = payloads + return nil + } +} diff -Nru containerd-1.2.6/diff/lcow/lcow.go containerd-1.5.9/diff/lcow/lcow.go --- containerd-1.2.6/diff/lcow/lcow.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff/lcow/lcow.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,16 +21,17 @@ import ( "context" "io" + "io/ioutil" "os" "path" + "runtime" "time" + "github.com/Microsoft/go-winio/pkg/security" "github.com/Microsoft/hcsshim/ext4/tar2ext4" - "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" @@ -61,7 +62,7 @@ ic.Meta.Platforms = append(ic.Meta.Platforms, ocispec.Platform{ OS: "linux", - Architecture: "amd64", + Architecture: runtime.GOARCH, }) return NewWindowsLcowDiff(md.(*metadata.DB).ContentStore()) }, @@ -94,27 +95,29 @@ // Apply applies the content associated with the provided digests onto the // provided mounts. Archive content will be extracted and decompressed if // necessary. -func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) { +func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (d ocispec.Descriptor, err error) { t1 := time.Now() defer func() { if err == nil { log.G(ctx).WithFields(logrus.Fields{ - "d": time.Since(t1), - "dgst": desc.Digest, - "size": desc.Size, - "media": desc.MediaType, + "d": time.Since(t1), + "digest": desc.Digest, + "size": desc.Size, + "media": desc.MediaType, }).Debugf("diff applied") } }() - layer, _, err := mountsToLayerAndParents(mounts) - if err != nil { - return emptyDesc, err + var config diff.ApplyConfig + for _, o := range opts { + if err := o(ctx, desc, &config); err != nil { + return emptyDesc, errors.Wrap(err, "failed to apply config opt") + } } - isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType) + layer, _, err := mountsToLayerAndParents(mounts) if err != nil { - return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType) + return emptyDesc, err } ra, err := s.store.ReaderAt(ctx, desc) @@ -122,19 +125,22 @@ return emptyDesc, errors.Wrap(err, "failed to get reader from content store") } defer ra.Close() - rdr := content.NewReader(ra) - if isCompressed { - ds, err := compression.DecompressStream(rdr) - if err != nil { - return emptyDesc, err + + processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra)) + for { + if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil { + return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType) + } + if processor.MediaType() == ocispec.MediaTypeImageLayer { + break } - defer ds.Close() - rdr = ds } + defer processor.Close() + // Calculate the Digest as we go digester := digest.Canonical.Digester() rc := &readCounter{ - r: io.TeeReader(rdr, digester.Hash()), + r: io.TeeReader(processor, digester.Hash()), } layerPath := path.Join(layer, "layer.vhd") @@ -142,7 +148,6 @@ if err != nil { return emptyDesc, err } - defer outFile.Close() defer func() { if err != nil { outFile.Close() @@ -152,7 +157,22 @@ err = tar2ext4.Convert(rc, outFile, tar2ext4.ConvertWhiteout, tar2ext4.AppendVhdFooter, tar2ext4.MaximumDiskSize(maxLcowVhdSizeGB)) if err != nil { - return emptyDesc, errors.Wrapf(err, "failed to convert tar to ext4 vhd") + return emptyDesc, errors.Wrapf(err, "failed to convert tar2ext4 vhd") + } + err = outFile.Sync() + if err != nil { + return emptyDesc, errors.Wrapf(err, "failed to sync tar2ext4 vhd to disk") + } + outFile.Close() + + // Read any trailing data + if _, err := io.Copy(ioutil.Discard, rc); err != nil { + return emptyDesc, err + } + + err = security.GrantVmGroupAccess(layerPath) + if err != nil { + return emptyDesc, errors.Wrapf(err, "failed GrantVmGroupAccess on layer vhd: %v", layerPath) } return ocispec.Descriptor{ @@ -165,7 +185,7 @@ // Compare creates a diff between the given mounts and uploads the result // to the content store. func (s windowsLcowDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) { - return emptyDesc, errdefs.ErrNotImplemented + return emptyDesc, errors.Wrap(errdefs.ErrNotImplemented, "windowsLcowDiff does not implement Compare method") } type readCounter struct { diff -Nru containerd-1.2.6/diff/stream.go containerd-1.5.9/diff/stream.go --- containerd-1.2.6/diff/stream.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/stream.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,191 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package diff + +import ( + "context" + "io" + "os" + + "github.com/containerd/containerd/archive/compression" + "github.com/containerd/containerd/images" + "github.com/gogo/protobuf/types" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +var ( + handlers []Handler + + // ErrNoProcessor is returned when no stream processor is available for a media-type + ErrNoProcessor = errors.New("no processor for media-type") +) + +func init() { + // register the default compression handler + RegisterProcessor(compressedHandler) +} + +// RegisterProcessor registers a stream processor for media-types +func RegisterProcessor(handler Handler) { + handlers = append(handlers, handler) +} + +// GetProcessor returns the processor for a media-type +func GetProcessor(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { + // reverse this list so that user configured handlers come up first + for i := len(handlers) - 1; i >= 0; i-- { + processor, ok := handlers[i](ctx, stream.MediaType()) + if ok { + return processor(ctx, stream, payloads) + } + } + return nil, ErrNoProcessor +} + +// Handler checks a media-type and initializes the processor +type Handler func(ctx context.Context, mediaType string) (StreamProcessorInit, bool) + +// StaticHandler returns the processor init func for a static media-type +func StaticHandler(expectedMediaType string, fn StreamProcessorInit) Handler { + return func(ctx context.Context, mediaType string) (StreamProcessorInit, bool) { + if mediaType == expectedMediaType { + return fn, true + } + return nil, false + } +} + +// StreamProcessorInit returns the initialized stream processor +type StreamProcessorInit func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) + +// RawProcessor provides access to direct fd for processing +type RawProcessor interface { + // File returns the fd for the read stream of the underlying processor + File() *os.File +} + +// StreamProcessor handles processing a content stream and transforming it into a different media-type +type StreamProcessor interface { + io.ReadCloser + + // MediaType is the resulting media-type that the processor processes the stream into + MediaType() string +} + +func compressedHandler(ctx context.Context, mediaType string) (StreamProcessorInit, bool) { + compressed, err := images.DiffCompression(ctx, mediaType) + if err != nil { + return nil, false + } + if compressed != "" { + return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { + ds, err := compression.DecompressStream(stream) + if err != nil { + return nil, err + } + + return &compressedProcessor{ + rc: ds, + }, nil + }, true + } + return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { + return &stdProcessor{ + rc: stream, + }, nil + }, true +} + +// NewProcessorChain initialized the root StreamProcessor +func NewProcessorChain(mt string, r io.Reader) StreamProcessor { + return &processorChain{ + mt: mt, + rc: r, + } +} + +type processorChain struct { + mt string + rc io.Reader +} + +func (c *processorChain) MediaType() string { + return c.mt +} + +func (c *processorChain) Read(p []byte) (int, error) { + return c.rc.Read(p) +} + +func (c *processorChain) Close() error { + return nil +} + +type stdProcessor struct { + rc StreamProcessor +} + +func (c *stdProcessor) MediaType() string { + return ocispec.MediaTypeImageLayer +} + +func (c *stdProcessor) Read(p []byte) (int, error) { + return c.rc.Read(p) +} + +func (c *stdProcessor) Close() error { + return nil +} + +type compressedProcessor struct { + rc io.ReadCloser +} + +func (c *compressedProcessor) MediaType() string { + return ocispec.MediaTypeImageLayer +} + +func (c *compressedProcessor) Read(p []byte) (int, error) { + return c.rc.Read(p) +} + +func (c *compressedProcessor) Close() error { + return c.rc.Close() +} + +// BinaryHandler creates a new stream processor handler which calls out to the given binary. +// The id is used to identify the stream processor and allows the caller to send +// payloads specific for that stream processor (i.e. decryption keys for decrypt stream processor). +// The binary will be called for the provided mediaTypes and return the given media type. +func BinaryHandler(id, returnsMediaType string, mediaTypes []string, path string, args, env []string) Handler { + set := make(map[string]struct{}, len(mediaTypes)) + for _, m := range mediaTypes { + set[m] = struct{}{} + } + return func(_ context.Context, mediaType string) (StreamProcessorInit, bool) { + if _, ok := set[mediaType]; ok { + return func(ctx context.Context, stream StreamProcessor, payloads map[string]*types.Any) (StreamProcessor, error) { + payload := payloads[id] + return NewBinaryProcessor(ctx, mediaType, returnsMediaType, stream, path, args, env, payload) + }, true + } + return nil, false + } +} + +const mediaTypeEnvVar = "STREAM_PROCESSOR_MEDIATYPE" diff -Nru containerd-1.2.6/diff/stream_unix.go containerd-1.5.9/diff/stream_unix.go --- containerd-1.2.6/diff/stream_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/stream_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,147 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package diff + +import ( + "bytes" + "context" + "fmt" + "io" + "os" + "os/exec" + "sync" + + "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/types" + "github.com/pkg/errors" +) + +// NewBinaryProcessor returns a binary processor for use with processing content streams +func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args, env []string, payload *types.Any) (StreamProcessor, error) { + cmd := exec.CommandContext(ctx, name, args...) + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, env...) + + var payloadC io.Closer + if payload != nil { + data, err := proto.Marshal(payload) + if err != nil { + return nil, err + } + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + go func() { + io.Copy(w, bytes.NewReader(data)) + w.Close() + }() + + cmd.ExtraFiles = append(cmd.ExtraFiles, r) + payloadC = r + } + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt)) + var ( + stdin io.Reader + closer func() error + err error + ) + if f, ok := stream.(RawProcessor); ok { + stdin = f.File() + closer = f.File().Close + } else { + stdin = stream + } + cmd.Stdin = stdin + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + cmd.Stdout = w + + stderr := bytes.NewBuffer(nil) + cmd.Stderr = stderr + + if err := cmd.Start(); err != nil { + return nil, err + } + p := &binaryProcessor{ + cmd: cmd, + r: r, + mt: rmt, + stderr: stderr, + } + go p.wait() + + // close after start and dup + w.Close() + if closer != nil { + closer() + } + if payloadC != nil { + payloadC.Close() + } + return p, nil +} + +type binaryProcessor struct { + cmd *exec.Cmd + r *os.File + mt string + stderr *bytes.Buffer + + mu sync.Mutex + err error +} + +func (c *binaryProcessor) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *binaryProcessor) wait() { + if err := c.cmd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); ok { + c.mu.Lock() + c.err = errors.New(c.stderr.String()) + c.mu.Unlock() + } + } +} + +func (c *binaryProcessor) File() *os.File { + return c.r +} + +func (c *binaryProcessor) MediaType() string { + return c.mt +} + +func (c *binaryProcessor) Read(p []byte) (int, error) { + return c.r.Read(p) +} + +func (c *binaryProcessor) Close() error { + err := c.r.Close() + if kerr := c.cmd.Process.Kill(); err == nil { + err = kerr + } + return err +} diff -Nru containerd-1.2.6/diff/stream_windows.go containerd-1.5.9/diff/stream_windows.go --- containerd-1.2.6/diff/stream_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/diff/stream_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,166 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package diff + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sync" + + winio "github.com/Microsoft/go-winio" + "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const processorPipe = "STREAM_PROCESSOR_PIPE" + +// NewBinaryProcessor returns a binary processor for use with processing content streams +func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args, env []string, payload *types.Any) (StreamProcessor, error) { + cmd := exec.CommandContext(ctx, name, args...) + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, env...) + + if payload != nil { + data, err := proto.Marshal(payload) + if err != nil { + return nil, err + } + up, err := getUiqPath() + if err != nil { + return nil, err + } + path := fmt.Sprintf("\\\\.\\pipe\\containerd-processor-%s-pipe", up) + l, err := winio.ListenPipe(path, nil) + if err != nil { + return nil, err + } + go func() { + defer l.Close() + conn, err := l.Accept() + if err != nil { + logrus.WithError(err).Error("accept npipe connection") + return + } + io.Copy(conn, bytes.NewReader(data)) + conn.Close() + }() + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", processorPipe, path)) + } + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", mediaTypeEnvVar, imt)) + var ( + stdin io.Reader + closer func() error + err error + ) + if f, ok := stream.(RawProcessor); ok { + stdin = f.File() + closer = f.File().Close + } else { + stdin = stream + } + cmd.Stdin = stdin + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + cmd.Stdout = w + stderr := bytes.NewBuffer(nil) + cmd.Stderr = stderr + + if err := cmd.Start(); err != nil { + return nil, err + } + p := &binaryProcessor{ + cmd: cmd, + r: r, + mt: rmt, + stderr: stderr, + } + go p.wait() + + // close after start and dup + w.Close() + if closer != nil { + closer() + } + return p, nil +} + +type binaryProcessor struct { + cmd *exec.Cmd + r *os.File + mt string + stderr *bytes.Buffer + + mu sync.Mutex + err error +} + +func (c *binaryProcessor) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *binaryProcessor) wait() { + if err := c.cmd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); ok { + c.mu.Lock() + c.err = errors.New(c.stderr.String()) + c.mu.Unlock() + } + } +} + +func (c *binaryProcessor) File() *os.File { + return c.r +} + +func (c *binaryProcessor) MediaType() string { + return c.mt +} + +func (c *binaryProcessor) Read(p []byte) (int, error) { + return c.r.Read(p) +} + +func (c *binaryProcessor) Close() error { + err := c.r.Close() + if kerr := c.cmd.Process.Kill(); err == nil { + err = kerr + } + return err +} + +func getUiqPath() (string, error) { + dir, err := ioutil.TempDir("", "") + if err != nil { + return "", err + } + os.Remove(dir) + return filepath.Base(dir), nil +} diff -Nru containerd-1.2.6/diff/walking/differ.go containerd-1.5.9/diff/walking/differ.go --- containerd-1.2.6/diff/walking/differ.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff/walking/differ.go 2022-01-05 17:30:58.000000000 +0000 @@ -99,21 +99,22 @@ if err != nil { cw.Close() if newReference { - if err := s.store.Abort(ctx, config.Reference); err != nil { - log.G(ctx).WithField("ref", config.Reference).Warnf("failed to delete diff upload") + if abortErr := s.store.Abort(ctx, config.Reference); abortErr != nil { + log.G(ctx).WithError(abortErr).WithField("ref", config.Reference).Warnf("failed to delete diff upload") } } } }() if !newReference { - if err := cw.Truncate(0); err != nil { + if err = cw.Truncate(0); err != nil { return err } } if isCompressed { dgstr := digest.SHA256.Digester() - compressed, err := compression.CompressStream(cw, compression.Gzip) + var compressed io.WriteCloser + compressed, err = compression.CompressStream(cw, compression.Gzip) if err != nil { return errors.Wrap(err, "failed to get compressed stream") } @@ -149,7 +150,9 @@ if err != nil { return errors.Wrap(err, "failed to get info from content store") } - + if info.Labels == nil { + info.Labels = make(map[string]string) + } // Set uncompressed label if digest already existed without label if _, ok := info.Labels[uncompressed]; !ok { info.Labels[uncompressed] = config.Labels[uncompressed] diff -Nru containerd-1.2.6/diff/windows/windows.go containerd-1.5.9/diff/windows/windows.go --- containerd-1.2.6/diff/windows/windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff/windows/windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,9 @@ import ( "context" + "crypto/rand" + "encoding/base64" + "fmt" "io" "io/ioutil" "time" @@ -30,7 +33,6 @@ "github.com/containerd/containerd/content" "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" @@ -75,6 +77,7 @@ } var emptyDesc = ocispec.Descriptor{} +var uncompressed = "containerd.io/uncompressed" // NewWindowsDiff is the Windows container layer implementation // for comparing and applying filesystem layers @@ -87,22 +90,24 @@ // Apply applies the content associated with the provided digests onto the // provided mounts. Archive content will be extracted and decompressed if // necessary. -func (s windowsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) { +func (s windowsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (d ocispec.Descriptor, err error) { t1 := time.Now() defer func() { if err == nil { log.G(ctx).WithFields(logrus.Fields{ - "d": time.Since(t1), - "dgst": desc.Digest, - "size": desc.Size, - "media": desc.MediaType, - }).Debugf("diff applied") + "d": time.Since(t1), + "digest": desc.Digest, + "size": desc.Size, + "media": desc.MediaType, + }).Debug("diff applied") } }() - isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType) - if err != nil { - return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType) + var config diff.ApplyConfig + for _, o := range opts { + if err := o(ctx, desc, &config); err != nil { + return emptyDesc, errors.Wrap(err, "failed to apply config opt") + } } ra, err := s.store.ReaderAt(ctx, desc) @@ -111,19 +116,20 @@ } defer ra.Close() - r := content.NewReader(ra) - if isCompressed { - ds, err := compression.DecompressStream(r) - if err != nil { - return emptyDesc, err + processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra)) + for { + if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil { + return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType) + } + if processor.MediaType() == ocispec.MediaTypeImageLayer { + break } - defer ds.Close() - r = ds } + defer processor.Close() digester := digest.Canonical.Digester() rc := &readCounter{ - r: io.TeeReader(r, digester.Hash()), + r: io.TeeReader(processor, digester.Hash()), } layer, parentLayerPaths, err := mountsToLayerAndParents(mounts) @@ -134,11 +140,12 @@ // TODO darrenstahlmsft: When this is done isolated, we should disable these. // it currently cannot be disabled, unless we add ref counting. Since this is // temporary, leaving it enabled is OK for now. + // https://github.com/containerd/containerd/issues/1681 if err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil { return emptyDesc, err } - if _, err := archive.Apply(ctx, layer, rc, archive.WithParentLayers(parentLayerPaths), archive.AsWindowsContainerLayer()); err != nil { + if _, err := archive.Apply(ctx, layer, rc, archive.WithParents(parentLayerPaths), archive.AsWindowsContainerLayer()); err != nil { return emptyDesc, err } @@ -157,7 +164,136 @@ // Compare creates a diff between the given mounts and uploads the result // to the content store. func (s windowsDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) { - return emptyDesc, errdefs.ErrNotImplemented + t1 := time.Now() + + var config diff.Config + for _, opt := range opts { + if err := opt(&config); err != nil { + return emptyDesc, err + } + } + + layers, err := mountPairToLayerStack(lower, upper) + if err != nil { + return emptyDesc, err + } + + if config.MediaType == "" { + config.MediaType = ocispec.MediaTypeImageLayerGzip + } + + var isCompressed bool + switch config.MediaType { + case ocispec.MediaTypeImageLayer: + case ocispec.MediaTypeImageLayerGzip: + isCompressed = true + default: + return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", config.MediaType) + } + + newReference := false + if config.Reference == "" { + newReference = true + config.Reference = uniqueRef() + } + + cw, err := s.store.Writer(ctx, content.WithRef(config.Reference), content.WithDescriptor(ocispec.Descriptor{ + MediaType: config.MediaType, + })) + + if err != nil { + return emptyDesc, errors.Wrap(err, "failed to open writer") + } + + defer func() { + if err != nil { + cw.Close() + if newReference { + if abortErr := s.store.Abort(ctx, config.Reference); abortErr != nil { + log.G(ctx).WithError(abortErr).WithField("ref", config.Reference).Warnf("failed to delete diff upload") + } + } + } + }() + + if !newReference { + if err = cw.Truncate(0); err != nil { + return emptyDesc, err + } + } + + // TODO darrenstahlmsft: When this is done isolated, we should disable this. + // it currently cannot be disabled, unless we add ref counting. Since this is + // temporary, leaving it enabled is OK for now. + // https://github.com/containerd/containerd/issues/1681 + if err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege}); err != nil { + return emptyDesc, err + } + + if isCompressed { + dgstr := digest.SHA256.Digester() + var compressed io.WriteCloser + compressed, err = compression.CompressStream(cw, compression.Gzip) + if err != nil { + return emptyDesc, errors.Wrap(err, "failed to get compressed stream") + } + err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:])) + compressed.Close() + if err != nil { + return emptyDesc, errors.Wrap(err, "failed to write compressed diff") + } + + if config.Labels == nil { + config.Labels = map[string]string{} + } + config.Labels[uncompressed] = dgstr.Digest().String() + } else { + if err = archive.WriteDiff(ctx, cw, "", layers[0], archive.AsWindowsContainerLayerPair(), archive.WithParentLayers(layers[1:])); err != nil { + return emptyDesc, errors.Wrap(err, "failed to write diff") + } + } + + var commitopts []content.Opt + if config.Labels != nil { + commitopts = append(commitopts, content.WithLabels(config.Labels)) + } + + dgst := cw.Digest() + if err := cw.Commit(ctx, 0, dgst, commitopts...); err != nil { + if !errdefs.IsAlreadyExists(err) { + return emptyDesc, errors.Wrap(err, "failed to commit") + } + } + + info, err := s.store.Info(ctx, dgst) + if err != nil { + return emptyDesc, errors.Wrap(err, "failed to get info from content store") + } + if info.Labels == nil { + info.Labels = make(map[string]string) + } + // Set uncompressed label if digest already existed without label + if _, ok := info.Labels[uncompressed]; !ok { + info.Labels[uncompressed] = config.Labels[uncompressed] + if _, err := s.store.Update(ctx, info, "labels."+uncompressed); err != nil { + return emptyDesc, errors.Wrap(err, "error setting uncompressed label") + } + } + + desc := ocispec.Descriptor{ + MediaType: config.MediaType, + Size: info.Size, + Digest: info.Digest, + } + + log.G(ctx).WithFields(logrus.Fields{ + "d": time.Since(t1), + "dgst": desc.Digest, + "size": desc.Size, + "media": desc.MediaType, + }).Debug("diff created") + + return desc, nil } type readCounter struct { @@ -180,7 +316,7 @@ // This is a special case error. When this is received the diff service // will attempt the next differ in the chain which for Windows is the // lcow differ that we want. - return "", nil, errdefs.ErrNotImplemented + return "", nil, errors.Wrapf(errdefs.ErrNotImplemented, "windowsDiff does not support layer type %s", mnt.Type) } parentLayerPaths, err := mnt.GetParentPaths() @@ -190,3 +326,58 @@ return mnt.Source, parentLayerPaths, nil } + +// mountPairToLayerStack ensures that the two sets of mount-lists are actually a correct +// parent-and-child, or orphan-and-empty-list, and return the full list of layers, starting +// with the upper-most (most childish?) +func mountPairToLayerStack(lower, upper []mount.Mount) ([]string, error) { + + // May return an ErrNotImplemented, which will fall back to LCOW + upperLayer, upperParentLayerPaths, err := mountsToLayerAndParents(upper) + if err != nil { + return nil, errors.Wrapf(err, "Upper mount invalid") + } + + // Trivial case, diff-against-nothing + if len(lower) == 0 { + if len(upperParentLayerPaths) != 0 { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer with parents against a null layer") + } + return []string{upperLayer}, nil + } + + if len(upperParentLayerPaths) < 1 { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer with no parents against another layer") + } + + lowerLayer, lowerParentLayerPaths, err := mountsToLayerAndParents(lower) + if errdefs.IsNotImplemented(err) { + // Upper was a windows-layer, lower is not. We can't handle that. + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a windows-layer against a non-windows-layer") + } else if err != nil { + return nil, errors.Wrapf(err, "Lower mount invalid") + } + + if upperParentLayerPaths[0] != lowerLayer { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer other than its own parent") + } + + if len(upperParentLayerPaths) != len(lowerParentLayerPaths)+1 { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer with different parents") + } + for i, upperParent := range upperParentLayerPaths[1:] { + if upperParent != lowerParentLayerPaths[i] { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "windowsDiff cannot diff a layer against a layer with different parents") + } + } + + return append([]string{upperLayer}, upperParentLayerPaths...), nil +} + +func uniqueRef() string { + t := time.Now() + var b [3]byte + // Ignore read failures, just decreases uniqueness + rand.Read(b[:]) + return fmt.Sprintf("%d-%s", t.UnixNano(), base64.URLEncoding.EncodeToString(b[:])) +} diff -Nru containerd-1.2.6/diff.go containerd-1.5.9/diff.go --- containerd-1.2.6/diff.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/diff.go 2022-01-05 17:30:58.000000000 +0000 @@ -45,10 +45,17 @@ client diffapi.DiffClient } -func (r *diffRemote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts []mount.Mount) (ocispec.Descriptor, error) { +func (r *diffRemote) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount, opts ...diff.ApplyOpt) (ocispec.Descriptor, error) { + var config diff.ApplyConfig + for _, opt := range opts { + if err := opt(ctx, desc, &config); err != nil { + return ocispec.Descriptor{}, err + } + } req := &diffapi.ApplyRequest{ - Diff: fromDescriptor(diff), - Mounts: fromMounts(mounts), + Diff: fromDescriptor(desc), + Mounts: fromMounts(mounts), + Payloads: config.ProcessorPayloads, } resp, err := r.client.Apply(ctx, req) if err != nil { @@ -80,17 +87,19 @@ func toDescriptor(d *types.Descriptor) ocispec.Descriptor { return ocispec.Descriptor{ - MediaType: d.MediaType, - Digest: d.Digest, - Size: d.Size_, + MediaType: d.MediaType, + Digest: d.Digest, + Size: d.Size_, + Annotations: d.Annotations, } } func fromDescriptor(d ocispec.Descriptor) *types.Descriptor { return &types.Descriptor{ - MediaType: d.MediaType, - Digest: d.Digest, - Size_: d.Size, + MediaType: d.MediaType, + Digest: d.Digest, + Size_: d.Size, + Annotations: d.Annotations, } } diff -Nru containerd-1.2.6/docs/client-opts.md containerd-1.5.9/docs/client-opts.md --- containerd-1.2.6/docs/client-opts.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/client-opts.md 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,7 @@ ## Extending the Client -As a consumer of the containerd client you need to be able add your domain specific functionality. +As a consumer of the containerd client you need to be able to add your domain specific functionality. There are a few ways of doing this, changing the client code, submitting a PR to the containerd client, or forking the client. These ways of extending the client should only be considered after every other method has been tried. diff -Nru containerd-1.2.6/docs/content-flow.md containerd-1.5.9/docs/content-flow.md --- containerd-1.2.6/docs/content-flow.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/content-flow.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,419 @@ +# Content Flow + +A major goal of containerd is to create a system wherein content can be used for executing containers. +In order to execute on that flow, containerd requires content and to manage it. + +This document describes how content flows into containerd, how it is managed, and where it exists +at each stage in the process. We use an example of going from a known image +[docker.io/library/redis:5.0.9](https://hub.docker.com/layers/redis/library/redis/5.0.9/images/sha256-4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3?context=explore) to explore the +flow of content. + +## Content Areas + +Content exists in several areas in the containerd lifecycle: + +* OCI registry, for example [hub.docker.com](https://hub.docker.com) or [quay.io](https://quay.io) +* containerd content store, under containerd's local storage space, for example, on a standard Linux installation at `/var/lib/containerd/io.containerd.content.v1.content` +* snapshots, under containerd's local storage space, for example, on a standard Linux installation at `/var/lib/containerd/io.containerd.snapshotter.v1.`. For an overlayfs snapshotter, that would be at `/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs` + +In order to create a container, the following must occur: + +1. The image and all its content must be loaded into the content store. This normally happens via download from the OCI registry, but you can load content in directly as well. +1. Committed snapshots must be created from each layer of content for the image. +1. An active snapshot must be created on top of the final layer of content for the image. + +A container now can be created, with its root filesystem as the active snapshot. + +The rest of this document looks at the content in each area in detail, and how they relate to one another. + +### Image Format + +Images in a registry normally are stored in the following format. An "image" is comprised of a JSON document +known as a descriptor. A descriptor always contains an element, `mediaType`, which tells us which type it is. It is one of two options: + +* a "manifest", which lists the hashes of the config file for running the image as a container, and the binary data layers that create the filesystem for the image +* an "index", which lists the hashes of manifests, one per platform, where a platform is a combination of architecture (e.g. amd64 or arm64) and operating system (e.g. linux) + +The purpose of an index is to allow us to pick which manifest matches our target platform. + +To convert an image reference, such as `redis:5.0.9`, from a registry to actual on-disk storage, we: + +1. Retrieve the descriptor (JSON document) for the image +1. Determine from the `mediaType` if the descriptor is a manifest or an index: + * If the descriptor is an index, find in it the platform (architecture+os) that represents the platform on which we want to run the container, use that hash to retrieve the manifest + * If the descriptor already is a manifest, continue +1. For each element in the manifest - the config and one or more layers - use the hash listed to retrieve the components and save them + +We use our example image, `redis:5.0.9`, to clarify the process. + +When we first resolve `redis:5.0.9`, we get the following JSON document: + +```json +{ + "manifests": [ + { + "digest": "sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "amd64", + "os": "linux" + }, + "size": 1572 + }, + { + "digest": "sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "arm", + "os": "linux", + "variant": "v5" + }, + "size": 1573 + }, + { + "digest": "sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "arm", + "os": "linux", + "variant": "v7" + }, + "size": 1573 + }, + { + "digest": "sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "arm64", + "os": "linux", + "variant": "v8" + }, + "size": 1573 + }, + { + "digest": "sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "386", + "os": "linux" + }, + "size": 1572 + }, + { + "digest": "sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "mips64le", + "os": "linux" + }, + "size": 1572 + }, + { + "digest": "sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "ppc64le", + "os": "linux" + }, + "size": 1573 + }, + { + "digest": "sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "platform": { + "architecture": "s390x", + "os": "linux" + }, + "size": 1573 + } + ], + "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", + "schemaVersion": 2 +} +``` + +The descriptor above, towards the end, shows that the `mediaType` is a "manifest.list", or in OCI parlance, an index. +It has an array field called `manifests`, each element of which lists one platform and the hash of the manifest for that platform. +The "platform" is a combination of "architecture" and "os". Since we will be running on the common +linux on amd64, we look for an entry in `manifests` that has a `platform` entry as follows: + +```json +"platform": { + "architecture": "amd64", + "os": "linux" +} +``` + +This is the first one in the list, and it has the hash of `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a`. + +We then retrieve the item with that hash, specifically `docker.io/library/redis@sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a` +This gives us the manifest for the image on linux/amd64: + +```json +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 6836, + "digest": "sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 27098147, + "digest": "sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 1730, + "digest": "sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 1417708, + "digest": "sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 7345094, + "digest": "sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 99, + "digest": "sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 410, + "digest": "sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b" + } + ] +} +``` + +The `mediaType` tell us that this is a "manifest", and it fits the correct format: + +* one `config`, whose hash is `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6` +* one or more `layers`; in this example, there are 6 layers + +Each of these elements - the index, the manifests, the config file and each of the layers - is stored +separately in the registry, and is downloaded independently. + +### Content Store + +When content is loaded into containerd's content store, it stores them very similarly to how the registry does. +Each component is stored in a file whose name is the hash of it. + +Continuing our redis example, if we do `client.Pull()` or `ctr pull`, we will get the following in our +content store: + +* `sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728` - the index +* `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a` - the manifest for `linux/amd64` +* `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6` - the config +* `sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b` - layer 0 +* `sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774` - layer 1 +* `sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac` - layer 2 +* `sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7` - layer 3 +* `sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6` - layer 4 +* `sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b` - layer 5 + +If we look in our content store, we see exactly these (I filtered and sorted to make it easier to read): + +```console +$ tree /var/lib/containerd/io.containerd.content.v1.content/blobs +/var/lib/containerd/io.containerd.content.v1.content/blobs +└── sha256 + ├── 1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728 + ├── a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a + ├── df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6 + ├── 123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b + ├── f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774 + ├── 66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac + ├── 79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7 + ├── de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6 + └── 602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b +``` + +We can see the same thing if we use the containerd interface. Again, we sorted it for consistent easier viewing. + +```console +ctr content ls +DIGEST SIZE AGE LABELS +sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728 1.862 kB 6 minutes containerd.io/gc.ref.content.0=sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a,containerd.io/gc.ref.content.1=sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3,containerd.io/gc.ref.content.2=sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7,containerd.io/gc.ref.content.3=sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233,containerd.io/gc.ref.content.4=sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26,containerd.io/gc.ref.content.5=sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6,containerd.io/gc.ref.content.6=sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c,containerd.io/gc.ref.content.7=sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9 +sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a 1.572 kB 6 minutes containerd.io/gc.ref.content.2=sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774,containerd.io/gc.ref.content.3=sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac,containerd.io/gc.ref.content.4=sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7,containerd.io/gc.ref.content.5=sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6,containerd.io/gc.ref.content.6=sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b,containerd.io/gc.ref.content.0=sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6,containerd.io/gc.ref.content.1=sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b +sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6 6.836 kB 6 minutes containerd.io/gc.ref.snapshot.overlayfs=sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d +sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b 27.1 MB 6 minutes containerd.io/uncompressed=sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc +sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774 1.73 kB 6 minutes containerd.io/uncompressed=sha256:b5a8df342567aa93d568b263b25c1eaf52655f0952e1911742ffb4f7a521e044 +sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac 1.418 MB 6 minutes containerd.io/uncompressed=sha256:c03c7e9701eb61f1e2232f6d19faa699cd9d346207aaf4f50d84b1e37bbad3e2 +sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7 7.345 MB 6 minutes containerd.io/uncompressed=sha256:367024e4e00618a9ada3203b5922d3186a0aa6136a1c4cbf5ed380171e1afe48 +sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6 99 B 6 minutes containerd.io/uncompressed=sha256:60ef3ee42de712ef7748cc8e92192e926180b1be6fec9580933f1347fb6b2747 +sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b 410 B 6 minutes containerd.io/uncompressed=sha256:bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c +``` + +#### Labels + +Note that each chunk of content has several labels on it. This sub-section describes the labels. +This is not intended to be a comprehensive overview of labels. + +##### Layer Labels + +We start with the layers themselves. These have only one label: `containerd.io/uncompressed`. These files are +gzipped tar files; the value of the label gives the hash of them when uncompressed. You can get the same value +by doing: + +```console +$ cat | gunzip - | sha256sum - +``` + +For example: + +```console +$ cat /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b | gunzip - | sha256sum - +bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c +``` + +That aligns precisely with the last layer: + +``` +sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b 410 B 6 minutes containerd.io/uncompressed=sha256:bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c +``` + +##### Config Labels + +We have a single config layer, `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6`. It has a label prefixed with `containerd.io/gc.ref.` indicating +that it is a label that impacts garbage collection. + +In this case, the label is `containerd.io/gc.ref.snapshot.overlayfs` and has a value of `sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d`. + +This is used to connect this config to a snapshot. We will look at that shortly when we discuss snapshots. + +##### Manifest Labels + +The labels on the manifest also begin with `containerd.io/gc.ref`, indicating that they are used to control +garbage collection. A manifest has several "children". These normally are the config and the layers. We want +to ensure that as long as the image remains around, i.e. the manifest, the children do not get garbage collected. +Thus, we have labels referencing each child, `containerd.io/gc.ref.content.`. + +In our example, the manifest is `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a`, and the labels are as follows. + +``` +containerd.io/gc.ref.content.0=sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6 +containerd.io/gc.ref.content.1=sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b +containerd.io/gc.ref.content.2=sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774 +containerd.io/gc.ref.content.3=sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac +containerd.io/gc.ref.content.4=sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7 +containerd.io/gc.ref.content.5=sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6 +containerd.io/gc.ref.content.6=sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b +``` + +These are precisely those children of the manifest - the config and layers - that are stored in our content store. + +##### Index Labels + +The labels on the index also begin with `containerd.io/gc.ref`, indicating that they are used to control +garbage collection. An index has several "children", i.e. the manifests, one for each platform, as discussed above. +We want to ensure that as long as the index remains around, the children do not get garbage collected. +Thus, we have labels referencing each child, `containerd.io/gc.ref.content.`. + +In our example, the index is `sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728`, and the labels are as follows: + +``` +containerd.io/gc.ref.content.0=sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a +containerd.io/gc.ref.content.1=sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3 +containerd.io/gc.ref.content.2=sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7 +containerd.io/gc.ref.content.3=sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233 +containerd.io/gc.ref.content.4=sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26 +containerd.io/gc.ref.content.5=sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6 +containerd.io/gc.ref.content.6=sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c +containerd.io/gc.ref.content.7=sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9 +``` + +Notice that there are 8 children to the index, but all of them are for platforms other than ours, `linux/amd64`, +and thus only one of them, `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a` actually is +in our content store. That doesn't hurt; it just means that the others will not be garbage collected either. Since +they aren't there, they won't be removed. + +### Snapshots + +The content in the content store is immutable, but also in formats that often are unusable. For example, +most container layers are in a tar-gzip format. One cannot simply mount a tar-gzip file. Even if one could, +we want to leave our immutable content not only unchanged, but unchangeable, even by accident, i.e. immutable. + +In order to use it, we create snapshots of the content. + +The process is as follows: + +1. The snapshotter creates a snapshot from the parent. In the case of the first layer, that is blank. This is now an "active" snapshot. +1. The diff applier, which has knowledge of the internal format of the layer blob, applies the layer blob to the active snapshot. +1. The snapshotter commits the snapshot after the diff has been applied. This is now a "committed" snapshot. +1. The committed snapshot is used as the parent for the next layer. + +Returning to our example, each layer will have a corresponding immutable snapshot layer. Recalling that +our example has 6 layers, we expect to see 6 committed snapshots. The output has been sorted to make viewing +easier; it matches the layers from the content store and manifest itself. + +``` +# ctr snapshot ls +KEY PARENT KIND +sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc Committed +sha256:c2cba74b5b43db78068241279a3225ca4f9639c17a5f0ce019489ee71b4382a5 sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc Committed +sha256:315768cd0d297e3cb707360f8dde646419940b42e055845a160880cf98b5a242 sha256:c2cba74b5b43db78068241279a3225ca4f9639c17a5f0ce019489ee71b4382a5 Committed +sha256:13aa829f25ce405c1c5f40e0449b9270ce162ac7e4c2a81359df6fe09f939afd sha256:315768cd0d297e3cb707360f8dde646419940b42e055845a160880cf98b5a242 Committed +sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 sha256:13aa829f25ce405c1c5f40e0449b9270ce162ac7e4c2a81359df6fe09f939afd Committed +sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 Committed +``` + +#### Parents + +Each snapshot has a parent, except for the root. It is a tree, or a stacked cake, starting with the first layer. +This matches how the layers are built, as layers. + +#### Name + +The key, or name, for the snapshot does not match the hash from the content store. This is because the hash from the +content store is the hash of the _original_ content, in this case tar-gzipped. The snapshot expands it out into the +filesystem to make it useful. It also does not match the uncompressed content, i.e. the tar file without gzip, and as +given on the label `containerd.io/uncompressed`. + +Rather the name is the result of applying the layer to the previous one and hashing it. By that logic, the very root +of the tree, the first layer, should have the same hash and name as the uncompressed value of the first layer blob. +Indeed, it does. The root layer is `sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b` +which, when uncompressed, has the value `sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc`, +which is the first layer in the snapshot, and also the label on that layer in the content store: + +``` +sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b 27.1 MB 6 minutes containerd.io/uncompressed=sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc +``` + +#### Final Layer + +The final, or top, layer, is the point at which you would want to create an active snapshot to start a container. +Thus, we would need to track it. This is exactly the label that is placed on the config. In our example, the +config is at `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6` and had the label +`containerd.io/gc.ref.snapshot.overlayfs=sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d`. + +Looking at our snapshots, the value of the final layer of the stack is, indeed, that: + +``` +sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 Committed +``` + +Note as well, that the label on the config in the content store starts with `containerd.io/gc.ref`. This is +a garbage collection label. It is this label that keeps the garbage collector from removing the snapshot. +Because the config has a reference to it, the top layer is "protected" from garbage collection. This layer, +in turn, depends on the next layer down, so it is protected from collection, and so on until the root or base layer. + +### Container + +With the above in place, we know how to create an active snapshot that is useful for the container. We simply +need to [Prepare()](https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter) the active snapshot, +passing it an ID and the parent, in this case the top layer of committed snapshots. + +Thus, the steps are: + +1. Get the content into the content store, either via [Pull()](https://godoc.org/github.com/containerd/containerd#Client.Pull), or via loading it in the [content.Store API](https://godoc.org/github.com/containerd/containerd/content#Store) +1. Unpack the image to create committed snapshots for each layer, using [image.Unpack()](https://godoc.org/github.com/containerd/containerd#Image). Alternatively, if you use [Pull()](https://godoc.org/github.com/containerd/containerd#Client.Pull), you can pass it an option to unpack when pulling, using [WithPullUnpack()](https://godoc.org/github.com/containerd/containerd#WithPullUnpack) +1. Create an active snapshot using [Prepare()](https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter). You can skip this step if you plan on creating a container, as you can pass it as an option to the next step. +1. Create a container using [NewContainer()](https://godoc.org/github.com/containerd/containerd#Client.NewContainer), optionally telling it to create a snapshot with [WithNewSnapshot()](https://godoc.org/github.com/containerd/containerd#WithNewSnapshot) diff -Nru containerd-1.2.6/docs/cri/architecture.md containerd-1.5.9/docs/cri/architecture.md --- containerd-1.2.6/docs/cri/architecture.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/architecture.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +# Architecture of The CRI Plugin +This document describes the architecture of the `cri` plugin for `containerd`. + +This plugin is an implementation of Kubernetes [container runtime interface (CRI)](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/cri/runtime/v1alpha2/api.proto). Containerd operates on the same node as the [Kubelet](https://kubernetes.io/docs/reference/generated/kubelet/). The `cri` plugin inside containerd handles all CRI service requests from the Kubelet and uses containerd internals to manage containers and container images. + +The `cri` plugin uses containerd to manage the full container lifecycle and all container images. As also shown below, `cri` manages pod networking via [CNI](https://github.com/containernetworking/cni) (another CNCF project). + +![architecture](./architecture.png) + +Let's use an example to demonstrate how the `cri` plugin works for the case when Kubelet creates a single-container pod: +* Kubelet calls the `cri` plugin, via the CRI runtime service API, to create a pod; +* `cri` creates and configures the pod’s network namespace using CNI; +* `cri` uses containerd internal to create and start a special [pause container](https://www.ianlewis.org/en/almighty-pause-container) (the sandbox container) and put that container inside the pod’s cgroups and namespace (steps omitted for brevity); +* Kubelet subsequently calls the `cri` plugin, via the CRI image service API, to pull the application container image; +* `cri` further uses containerd to pull the image if the image is not present on the node; +* Kubelet then calls `cri`, via the CRI runtime service API, to create and start the application container inside the pod using the pulled container image; +* `cri` finally uses containerd internal to create the application container, put it inside the pod’s cgroups and namespace, then to start the pod’s new application container. +After these steps, a pod and its corresponding application container is created and running. Binary files /tmp/tmp4z7_tba8/FAzrZmqiYm/containerd-1.2.6/docs/cri/architecture.png and /tmp/tmp4z7_tba8/Bfxrm9w9fP/containerd-1.5.9/docs/cri/architecture.png differ diff -Nru containerd-1.2.6/docs/cri/config.md containerd-1.5.9/docs/cri/config.md --- containerd-1.2.6/docs/cri/config.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/config.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,345 @@ +# CRI Plugin Config Guide +This document provides the description of the CRI plugin configuration. +The CRI plugin config is part of the containerd config (default +path: `/etc/containerd/config.toml`). + +See [here](https://github.com/containerd/containerd/blob/master/docs/ops.md) +for more information about containerd config. + +The explanation and default value of each configuration item are as follows: +```toml +# Use config version 2 to enable new configuration fields. +# Config file is parsed as version 1 by default. +# Version 2 uses long plugin names, i.e. "io.containerd.grpc.v1.cri" vs "cri". +version = 2 + +# The 'plugins."io.containerd.grpc.v1.cri"' table contains all of the server options. +[plugins."io.containerd.grpc.v1.cri"] + + # disable_tcp_service disables serving CRI on the TCP server. + # Note that a TCP server is enabled for containerd if TCPAddress is set in section [grpc]. + disable_tcp_service = true + + # stream_server_address is the ip address streaming server is listening on. + stream_server_address = "127.0.0.1" + + # stream_server_port is the port streaming server is listening on. + stream_server_port = "0" + + # stream_idle_timeout is the maximum time a streaming connection can be + # idle before the connection is automatically closed. + # The string is in the golang duration format, see: + # https://golang.org/pkg/time/#ParseDuration + stream_idle_timeout = "4h" + + # enable_selinux indicates to enable the selinux support. + enable_selinux = false + + # selinux_category_range allows the upper bound on the category range to be set. + # if not specified or set to 0, defaults to 1024 from the selinux package. + selinux_category_range = 1024 + + # sandbox_image is the image used by sandbox container. + sandbox_image = "k8s.gcr.io/pause:3.5" + + # stats_collect_period is the period (in seconds) of snapshots stats collection. + stats_collect_period = 10 + + # enable_tls_streaming enables the TLS streaming support. + # It generates a self-sign certificate unless the following x509_key_pair_streaming are both set. + enable_tls_streaming = false + + # tolerate_missing_hugetlb_controller if set to false will error out on create/update + # container requests with huge page limits if the cgroup controller for hugepages is not present. + # This helps with supporting Kubernetes <=1.18 out of the box. (default is `true`) + tolerate_missing_hugetlb_controller = true + + # ignore_image_defined_volumes ignores volumes defined by the image. Useful for better resource + # isolation, security and early detection of issues in the mount configuration when using + # ReadOnlyRootFilesystem since containers won't silently mount a temporary volume. + ignore_image_defined_volumes = false + + # netns_mounts_under_state_dir places all mounts for network namespaces under StateDir/netns + # instead of being placed under the hardcoded directory /var/run/netns. Changing this setting + # requires that all containers are deleted. + netns_mounts_under_state_dir = false + + # 'plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming' contains a x509 valid key pair to stream with tls. + [plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming] + # tls_cert_file is the filepath to the certificate paired with the "tls_key_file" + tls_cert_file = "" + + # tls_key_file is the filepath to the private key paired with the "tls_cert_file" + tls_key_file = "" + + # max_container_log_line_size is the maximum log line size in bytes for a container. + # Log line longer than the limit will be split into multiple lines. -1 means no + # limit. + max_container_log_line_size = 16384 + + # disable_cgroup indicates to disable the cgroup support. + # This is useful when the daemon does not have permission to access cgroup. + disable_cgroup = false + + # disable_apparmor indicates to disable the apparmor support. + # This is useful when the daemon does not have permission to access apparmor. + disable_apparmor = false + + # restrict_oom_score_adj 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. + restrict_oom_score_adj = false + + # max_concurrent_downloads restricts the number of concurrent downloads for each image. + max_concurrent_downloads = 3 + + # disable_proc_mount disables Kubernetes ProcMount support. This MUST be set to `true` + # when using containerd with Kubernetes <=1.11. + disable_proc_mount = false + + # unsetSeccompProfile is the profile containerd/cri will use if the provided seccomp profile is + # unset (`""`) for a container (default is `unconfined`) + unset_seccomp_profile = "" + + # 'plugins."io.containerd.grpc.v1.cri".containerd' contains config related to containerd + [plugins."io.containerd.grpc.v1.cri".containerd] + + # snapshotter is the snapshotter used by containerd. + snapshotter = "overlayfs" + + # no_pivot disables pivot-root (linux only), required when running a container in a RamDisk with runc. + # This only works for runtime type "io.containerd.runtime.v1.linux". + no_pivot = false + + # disable_snapshot_annotations disables to pass additional annotations (image + # related information) to snapshotters. These annotations are required by + # stargz snapshotter (https://github.com/containerd/stargz-snapshotter) + # changed to default true with https://github.com/containerd/containerd/pull/4665 and subsequent service refreshes. + disable_snapshot_annotations = true + + # discard_unpacked_layers allows GC to remove layers from the content store after + # successfully unpacking these layers to the snapshotter. + discard_unpacked_layers = false + + # default_runtime_name is the default runtime name to use. + default_runtime_name = "runc" + + # 'plugins."io.containerd.grpc.v1.cri".containerd.default_runtime' is the runtime to use in containerd. + # DEPRECATED: use `default_runtime_name` and `plugins."io.containerd.grpc.v1.cri".runtimes` instead. + # Remove in containerd 1.4. + [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime] + + # 'plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime' is a runtime to run untrusted workloads on it. + # DEPRECATED: use `untrusted` runtime in `plugins."io.containerd.grpc.v1.cri".runtimes` instead. + # Remove in containerd 1.4. + [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime] + + # 'plugins."io.containerd.grpc.v1.cri".containerd.runtimes' is a map from CRI RuntimeHandler strings, which specify types + # of runtime configurations, to the matching configurations. + # In this example, 'runc' is the RuntimeHandler string to match. + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + # runtime_type is the runtime type to use in containerd. + # The default value is "io.containerd.runc.v2" since containerd 1.4. + # The default value was "io.containerd.runc.v1" in containerd 1.3, "io.containerd.runtime.v1.linux" in prior releases. + runtime_type = "io.containerd.runc.v2" + + # pod_annotations is a list of pod annotations passed to both pod + # sandbox as well as container OCI annotations. Pod_annotations also + # supports golang path match pattern - https://golang.org/pkg/path/#Match. + # e.g. ["runc.com.*"], ["*.runc.com"], ["runc.com/*"]. + # + # For the naming convention of annotation keys, please reference: + # * Kubernetes: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set + # * OCI: https://github.com/opencontainers/image-spec/blob/master/annotations.md + pod_annotations = [] + + # container_annotations is a list of container annotations passed through to the OCI config of the containers. + # Container annotations in CRI are usually generated by other Kubernetes node components (i.e., not users). + # Currently, only device plugins populate the annotations. + container_annotations = [] + + # privileged_without_host_devices allows overloading the default behaviour of passing host + # devices through to privileged containers. This is useful when using a runtime where it does + # not make sense to pass host devices to the container when privileged. Defaults to false - + # i.e pass host devices through to privileged containers. + privileged_without_host_devices = false + + # base_runtime_spec is a file path to a JSON file with the OCI spec that will be used as the base spec that all + # container's are created from. + # Use containerd's `ctr oci spec > /etc/containerd/cri-base.json` to output initial spec file. + # Spec files are loaded at launch, so containerd daemon must be restared on any changes to refresh default specs. + # Still running containers and restarted containers will still be using the original spec from which that container was created. + base_runtime_spec = "" + + # 'plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options' is options specific to + # "io.containerd.runc.v1" and "io.containerd.runc.v2". Its corresponding options type is: + # https://github.com/containerd/containerd/blob/v1.3.2/runtime/v2/runc/options/oci.pb.go#L26 . + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] + # NoPivotRoot disables pivot root when creating a container. + NoPivotRoot = false + + # NoNewKeyring disables new keyring for the container. + NoNewKeyring = false + + # ShimCgroup places the shim in a cgroup. + ShimCgroup = "" + + # IoUid sets the I/O's pipes uid. + IoUid = 0 + + # IoGid sets the I/O's pipes gid. + IoGid = 0 + + # BinaryName is the binary name of the runc binary. + BinaryName = "" + + # Root is the runc root directory. + Root = "" + + # CriuPath is the criu binary path. + CriuPath = "" + + # SystemdCgroup enables systemd cgroups. + SystemdCgroup = false + + # CriuImagePath is the criu image path + CriuImagePath = "" + + # CriuWorkPath is the criu work path. + CriuWorkPath = "" + + # 'plugins."io.containerd.grpc.v1.cri".cni' contains config related to cni + [plugins."io.containerd.grpc.v1.cri".cni] + # bin_dir is the directory in which the binaries for the plugin is kept. + bin_dir = "/opt/cni/bin" + + # conf_dir is the directory in which the admin places a CNI conf. + conf_dir = "/etc/cni/net.d" + + # max_conf_num specifies the maximum number of CNI plugin config files to + # load from the CNI config directory. By default, only 1 CNI plugin config + # file will be loaded. If you want to load multiple CNI plugin config files + # set max_conf_num to the number desired. Setting max_config_num to 0 is + # interpreted as no limit is desired and will result in all CNI plugin + # config files being loaded from the CNI config directory. + max_conf_num = 1 + + # conf_template is the file path of golang template used to generate + # cni config. + # If this is set, containerd will generate a cni config file from the + # template. Otherwise, containerd will wait for the system admin or cni + # daemon to drop the config file into the conf_dir. + # This is a temporary backward-compatible solution for kubenet users + # who don't have a cni daemonset in production yet. + # This will be deprecated when kubenet is deprecated. + # See the "CNI Config Template" section for more details. + conf_template = "" + + # 'plugins."io.containerd.grpc.v1.cri".image_decryption' contains config related + # to handling decryption of encrypted container images. + [plugins."io.containerd.grpc.v1.cri".image_decryption] + # key_model defines the name of the key model used for how the cri obtains + # keys used for decryption of encrypted container images. + # The [decryption document](https://github.com/containerd/cri/blob/master/docs/decryption.md) + # contains additional information about the key models available. + # + # Set of available string options: {"", "node"} + # Omission of this field defaults to the empty string "", which indicates no key model, + # disabling image decryption. + # + # In order to use the decryption feature, additional configurations must be made. + # The [decryption document](https://github.com/containerd/cri/blob/master/docs/decryption.md) + # provides information of how to set up stream processors and the containerd imgcrypt decoder + # with the appropriate key models. + # + # Additional information: + # * Stream processors: https://github.com/containerd/containerd/blob/master/docs/stream_processors.md + # * Containerd imgcrypt: https://github.com/containerd/imgcrypt + key_model = "node" + + # 'plugins."io.containerd.grpc.v1.cri".registry' contains config related to + # the registry + [plugins."io.containerd.grpc.v1.cri".registry] + # config_path specifies a directory to look for the registry hosts configuration. + # + # The cri plugin will look for and use config_path/host-namespace/hosts.toml + # configs if present OR load certificate files as laid out in the Docker/Moby + # specific layout https://docs.docker.com/engine/security/certificates/ + # + # If config_path is not provided defaults are used. + # + # *** registry.configs and registry.mirrors that were a part of containerd 1.4 + # are now DEPRECATED and will only be used if the config_path is not specified. + config_path = "" +``` + +## Registry Configuration + +Here is a simple example for a default registry hosts configuration. Set +`config_path = "/etc/containerd/certs.d"` in your config.toml for containerd. +Make a directory tree at the config path that includes `docker.io` as a directory +representing the host namespace to be configured. Then add a `hosts.toml` file +in the `docker.io` to configure the host namespace. It should look like this: +``` +$ tree /etc/containerd/certs.d +/etc/containerd/certs.d +└── docker.io + └── hosts.toml + +$ cat /etc/containerd/certs.d/docker.io/hosts.toml +server = "https://docker.io" + +[host."https://registry-1.docker.io"] + capabilities = ["pull", "resolve"] +``` + +## Untrusted Workload + +The recommended way to run untrusted workload is to use +[`RuntimeClass`](https://kubernetes.io/docs/concepts/containers/runtime-class/) api +introduced in Kubernetes 1.12 to select RuntimeHandlers configured to run +untrusted workload in `plugins."io.containerd.grpc.v1.cri".containerd.runtimes`. + +However, if you are using the legacy `io.kubernetes.cri.untrusted-workload`pod annotation +to request a pod be run using a runtime for untrusted workloads, the RuntimeHandler +`plugins."io.containerd.grpc.v1.cri"cri.containerd.runtimes.untrusted` must be defined first. +When the annotation `io.kubernetes.cri.untrusted-workload` is set to `true` the `untrusted` +runtime will be used. For example, see +[Create an untrusted pod using Kata Containers](https://github.com/kata-containers/documentation/blob/master/how-to/how-to-use-k8s-with-cri-containerd-and-kata.md#create-an-untrusted-pod-using-kata-containers). + +## CNI Config Template + +Ideally the cni config should be placed by system admin or cni daemon like calico, +weaveworks etc. However, there are still users using [kubenet](https://kubernetes.io/docs/concepts/cluster-administration/network-plugins/#kubenet) +today, who don't have a cni daemonset in production. The cni config template is +a temporary backward-compatible solution for them. This is expected to be +deprecated when kubenet is deprecated. + +The cni config template uses the [golang +template](https://golang.org/pkg/text/template/) format. Currently supported +values are: +* `.PodCIDR` is a string of the first CIDR assigned to the node. +* `.PodCIDRRanges` is a string array of all CIDRs assigned to the node. It is + usually used for + [dualstack](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/563-dual-stack) support. +* `.Routes` is a string array of all routes needed. It is usually used for + dualstack support or single stack but IPv4 or IPv6 is decided at runtime. + +The [golang template actions](https://golang.org/pkg/text/template/#hdr-Actions) +can be used to render the cni config. For example, you can use the following +template to add CIDRs and routes for dualstack in the CNI config: +``` +"ipam": { + "type": "host-local", + "ranges": [{{range $i, $range := .PodCIDRRanges}}{{if $i}}, {{end}}[{"subnet": "{{$range}}"}]{{end}}], + "routes": [{{range $i, $route := .Routes}}{{if $i}}, {{end}}{"dst": "{{$route}}"}{{end}}] +} +``` + +## Deprecation +The config options of the CRI plugin follow the [Kubernetes deprecation +policy of "admin-facing CLI components"](https://kubernetes.io/docs/reference/using-api/deprecation-policy/#deprecating-a-flag-or-cli). + +In summary, when a config option is announced to be deprecated: +* It is kept functional for 6 months or 1 release (whichever is longer); +* A warning is emitted when it is used. Binary files /tmp/tmp4z7_tba8/FAzrZmqiYm/containerd-1.2.6/docs/cri/containerd.png and /tmp/tmp4z7_tba8/Bfxrm9w9fP/containerd-1.5.9/docs/cri/containerd.png differ diff -Nru containerd-1.2.6/docs/cri/crictl.md containerd-1.5.9/docs/cri/crictl.md --- containerd-1.2.6/docs/cri/crictl.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/crictl.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,216 @@ +CRICTL User Guide +================= +This document presumes you already have `containerd` with the `cri` plugin installed and running. + +This document is for developers who wish to debug, inspect, and manage their pods, +containers, and container images. + +Before generating issues against this document, `containerd`, `containerd/cri`, +or `crictl` please make sure the issue has not already been submitted. + +## Install crictl +If you have not already installed crictl please install the version compatible +with the `cri` plugin you are using. If you are a user, your deployment +should have installed crictl for you. If not, get it from your release tarball. +If you are a developer the current version of crictl is specified [here](../hack/utils.sh). +A helper command has been included to install the dependencies at the right version: +```console +$ make install.deps +``` +* Note: The file named `/etc/crictl.yaml` is used to configure crictl +so you don't have to repeatedly specify the runtime sock used to connect crictl +to the container runtime: +```console +$ cat /etc/crictl.yaml +runtime-endpoint: unix:///run/containerd/containerd.sock +image-endpoint: unix:///run/containerd/containerd.sock +timeout: 10 +debug: true +``` + +## Download and Inspect a Container Image +The pull command tells the container runtime to download a container image from +a container registry. +```console +$ crictl pull busybox + ... +$ crictl inspecti busybox + ... displays information about the image. +``` + +***Note:*** If you get an error similar to the following when running a `crictl` +command (and your containerd instance is already running): +```console +crictl info +FATA[0000] getting status of runtime failed: rpc error: code = Unimplemented desc = unknown service runtime.v1alpha2.RuntimeService +``` +This could be that you are using an incorrect containerd configuration (maybe +from a Docker install). You will need to update your containerd configuration +to the containerd instance that you are running. One way of doing this is as +follows: +```console +$ mv /etc/containerd/config.toml /etc/containerd/config.bak +$ containerd config default > /etc/containerd/config.toml +``` + +## Directly Load a Container Image +Another way to load an image into the container runtime is with the load +command. With the load command you inject a container image into the container +runtime from a file. First you need to create a container image tarball. For +example to create an image tarball for a pause container using Docker: +```console +$ docker pull k8s.gcr.io/pause:3.5 + 3.5: Pulling from pause + 019d8da33d91: Pull complete + Digest: sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 + Status: Downloaded newer image for k8s.gcr.io/pause:3.5 + k8s.gcr.io/pause:3.5 +$ docker save k8s.gcr.io/pause:3.5 -o pause.tar +``` +Then use `ctr` to load the container image into the container runtime: +```console +# The cri plugin uses the "k8s.io" containerd namespace. +$ sudo ctr -n=k8s.io images import pause.tar + Loaded image: k8s.gcr.io/pause:3.5 +``` +List images and inspect the pause image: +```console +$ sudo crictl images +IMAGE TAG IMAGE ID SIZE +docker.io/library/busybox latest f6e427c148a76 728kB +k8s.gcr.io/pause 3.5 ed210e3e4a5ba 683kB +$ sudo crictl inspecti ed210e3e4a5ba + ... displays information about the pause image. +$ sudo crictl inspecti k8s.gcr.io/pause:3.5 + ... displays information about the pause image. +``` + +## Run a pod sandbox (using a config file) +```console +$ cat sandbox-config.json +{ + "metadata": { + "name": "nginx-sandbox", + "namespace": "default", + "attempt": 1, + "uid": "hdishd83djaidwnduwk28bcsb" + }, + "linux": { + } +} + +$ crictl runp sandbox-config.json +e1c83b0b8d481d4af8ba98d5f7812577fc175a37b10dc824335951f52addbb4e +$ crictl pods +PODSANDBOX ID CREATED STATE NAME NAMESPACE ATTEMPT +e1c83b0b8d481 2 hours ago SANDBOX_READY nginx-sandbox default 1 +$ crictl inspectp e1c8 + ... displays information about the pod and the pod sandbox pause container. +``` +* Note: As shown above, you may use truncated IDs if they are unique. +* Other commands to manage the pod include `stops ID` to stop a running pod and +`rmp ID` to remove a pod sandbox. + +## Create and Run a Container in the Pod Sandbox (using a config file) +```console +$ cat container-config.json +{ + "metadata": { + "name": "busybox" + }, + "image":{ + "image": "busybox" + }, + "command": [ + "top" + ], + "linux": { + } +} + +$ crictl create e1c83 container-config.json sandbox-config.json +0a2c761303163f2acaaeaee07d2ba143ee4cea7e3bde3d32190e2a36525c8a05 +$ crictl ps -a +CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT +0a2c761303163 docker.io/busybox 2 hours ago CONTAINER_CREATED busybox 0 +$ crictl start 0a2c +0a2c761303163f2acaaeaee07d2ba143ee4cea7e3bde3d32190e2a36525c8a05 +$ crictl ps +CONTAINER ID IMAGE CREATED STATE NAME ATTEMPT +0a2c761303163 docker.io/busybox 2 hours ago CONTAINER_RUNNING busybox 0 +$ crictl inspect 0a2c7 + ... show detailed information about the container +``` +## Exec a Command in the Container +```console +$ crictl exec -i -t 0a2c ls +bin dev etc home proc root sys tmp usr var +``` +## Display Stats for the Container +```console +$ crictl stats +CONTAINER CPU % MEM DISK INODES +0a2c761303163f 0.00 983kB 16.38kB 6 +``` +* Other commands to manage the container include `stop ID` to stop a running +container and `rm ID` to remove a container. +## Display Version Information +```console +$ crictl version +Version: 0.1.0 +RuntimeName: containerd +RuntimeVersion: 1.0.0-beta.1-186-gdd47a72-TEST +RuntimeApiVersion: v1alpha2 +``` +## Display Status & Configuration Information about Containerd & The CRI Plugin +```console +$ crictl info +{ + "status": { + "conditions": [ + { + "type": "RuntimeReady", + "status": true, + "reason": "", + "message": "" + }, + { + "type": "NetworkReady", + "status": true, + "reason": "", + "message": "" + } + ] + }, + "config": { + "containerd": { + "snapshotter": "overlayfs", + "runtime": "io.containerd.runtime.v1.linux" + }, + "cni": { + "binDir": "/opt/cni/bin", + "confDir": "/etc/cni/net.d" + }, + "registry": { + "mirrors": { + "docker.io": { + "endpoint": [ + "https://registry-1.docker.io" + ] + } + } + }, + "streamServerPort": "10010", + "sandboxImage": "k8s.gcr.io/pause:3.5", + "statsCollectPeriod": 10, + "containerdRootDir": "/var/lib/containerd", + "containerdEndpoint": "unix:///run/containerd/containerd.sock", + "rootDir": "/var/lib/containerd/io.containerd.grpc.v1.cri", + "stateDir": "/run/containerd/io.containerd.grpc.v1.cri", + }, + "golang": "go1.10" +} +``` +## More Information +See [here](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md) +for information about crictl. Binary files /tmp/tmp4z7_tba8/FAzrZmqiYm/containerd-1.2.6/docs/cri/cri.png and /tmp/tmp4z7_tba8/Bfxrm9w9fP/containerd-1.5.9/docs/cri/cri.png differ diff -Nru containerd-1.2.6/docs/cri/decryption.md containerd-1.5.9/docs/cri/decryption.md --- containerd-1.2.6/docs/cri/decryption.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/decryption.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,45 @@ +# Configure Image Decryption +This document describes the method to configure encrypted container image decryption for `containerd` for use with the `cri` plugin. + +## Encrypted Container Images + +Encrypted container images are OCI images which contain encrypted blobs. These encrypted images can be created through the use of [containerd/imgcrypt project](https://github.com/containerd/imgcrypt). To decrypt these images, the `containerd` runtime uses information passed from the `cri` such as keys, options and encryption metadata. + +## The "node" Key Model + +Encryption ties trust to an entity based on the model in which a key is associated with it. We call this the key model. One such usecase is when we want to tie the trust of a key to the node in a cluster. In this case, we call it the "node" or "host" Key Model. Future work will include more key models to facilitate other trust associations (i.e. for multi-tenancy). + +### "node" Key Model Usecase + +In this model encryption is tied to worker nodes. The usecase here revolves around the idea that an image should be decryptable only on trusted host. Using this model, various node based technologies which help bootstrap trust in worker nodes and perform secure key distribution (i.e. TPM, host attestation, secure/measured boot). In this scenario, runtimes are capable of fetching the necessary decryption keys. An example of this is using the [`--decryption-keys-path` flag in imgcrypt](https://github.com/containerd/imgcrypt). + +### Configuring image decryption for "node" key model + +This is the default model since containerd v1.5. + +For containerd v1.4, you need to add the following configuration to `/etc/containerd/config.toml` and restart the `containerd` service manually. +```toml +version = 2 + +[plugins."io.containerd.grpc.v1.cri".image_decryption] + key_model = "node" + +[stream_processors] + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"] + accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"] + returns = "application/vnd.oci.image.layer.v1.tar+gzip" + path = "ctd-decoder" + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"] + accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"] + returns = "application/vnd.oci.image.layer.v1.tar" + path = "ctd-decoder" + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] +``` + +In this example, container image decryption is set to use the "node" key model. +In addition, the decryption [`stream_processors`](https://github.com/containerd/containerd/blob/master/docs/stream_processors.md) are configured as specified in [containerd/imgcrypt project](https://github.com/containerd/imgcrypt), with the additional field `--decryption-keys-path` configured to specify where decryption keys are located locally in the node. + +The `$OCICRYPT_KEYPROVIDER_CONFIG` environment variable is used for [ocicrypt keyprovider protocol](https://github.com/containers/ocicrypt/blob/master/docs/keyprovider.md). diff -Nru containerd-1.2.6/docs/cri/installation.md containerd-1.5.9/docs/cri/installation.md --- containerd-1.2.6/docs/cri/installation.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/installation.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,132 @@ +# Install Containerd with Release Tarball +This document provides the steps to install `containerd` and its dependencies with the release tarball, and bring up a Kubernetes cluster using kubeadm. + +These steps have been verified on Ubuntu 16.04. For other OS distributions, the steps may differ. Please feel free to file issues or PRs if you encounter any problems on other OS distributions. + +*Note: You need to run the following steps on each node you are planning to use in your Kubernetes cluster.* + +## Release Tarball +For each `containerd` release, we'll publish a release tarball specifically for Kubernetes named `cri-containerd-cni-${VERSION}-${OS}-${ARCH}.tar.gz`. This release tarball contains all required binaries and files for using `containerd` with Kubernetes. For example, the 1.4.3 version is available at https://github.com/containerd/containerd/releases/download/v1.4.3/cri-containerd-cni-1.4.3-linux-amd64.tar.gz. + +### Content +As shown below, the release tarball contains: + +- `containerd`, `containerd-shim`, `containerd-shim-runc-v1`, `containerd-shim-runc-v2`, `ctr`: binaries for containerd. +- `runc`: runc binary. +- `/opt/cni/bin`: binaries for [Container Network Interface](https://github.com/containernetworking/cni) +- `crictl`, `crictl.yaml`: command line tools for CRI container runtime and its config file. +- `critest`: binary to run [CRI validation test](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/validation.md). +- `containerd.service`: Systemd unit for containerd. +- `/opt/containerd/cluster/`: scripts for `kube-up.sh`. + +```console +$ tar -tf cri-containerd-cni-1.4.3-linux-amd64.tar.gz +etc/ +etc/cni/ +etc/cni/net.d/ +etc/cni/net.d/10-containerd-net.conflist +etc/crictl.yaml +etc/systemd/ +etc/systemd/system/ +etc/systemd/system/containerd.service +usr/ +usr/local/ +usr/local/bin/ +usr/local/bin/containerd-shim-runc-v2 +usr/local/bin/ctr +usr/local/bin/containerd-shim +usr/local/bin/containerd-shim-runc-v1 +usr/local/bin/crictl +usr/local/bin/critest +usr/local/bin/containerd +usr/local/sbin/ +usr/local/sbin/runc +opt/ +opt/cni/ +opt/cni/bin/ +opt/cni/bin/vlan +opt/cni/bin/host-local +opt/cni/bin/flannel +opt/cni/bin/bridge +opt/cni/bin/host-device +opt/cni/bin/tuning +opt/cni/bin/firewall +opt/cni/bin/bandwidth +opt/cni/bin/ipvlan +opt/cni/bin/sbr +opt/cni/bin/dhcp +opt/cni/bin/portmap +opt/cni/bin/ptp +opt/cni/bin/static +opt/cni/bin/macvlan +opt/cni/bin/loopback +opt/containerd/ +opt/containerd/cluster/ +opt/containerd/cluster/version +opt/containerd/cluster/gce/ +opt/containerd/cluster/gce/cni.template +opt/containerd/cluster/gce/configure.sh +opt/containerd/cluster/gce/cloud-init/ +opt/containerd/cluster/gce/cloud-init/master.yaml +opt/containerd/cluster/gce/cloud-init/node.yaml +opt/containerd/cluster/gce/env +``` + +### Binary Information +Information about the binaries in the release tarball: + +| Binary Name | Support | OS | Architecture | +|:------------------------------:|:------------------:|:-----:|:------------:| +| containerd | seccomp, apparmor, selinux
overlay, btrfs | linux | amd64 | +| containerd-shim | overlay, btrfs | linux | amd64 | +| runc | seccomp, apparmor, selinux | linux | amd64 | + + +If you have other requirements for the binaries, e.g. another architecture support etc., you need to build the binaries yourself following [the instructions](../../BUILDING.md). + +### Download + +The release tarball could be downloaded from the release page https://github.com/containerd/containerd/releases. + +## Step 0: Install Dependent Libraries +Install required library for seccomp. +```bash +sudo apt-get update +sudo apt-get install libseccomp2 +``` +Note that: +1) If you are using Ubuntu <=Trusty or Debian <=jessie, a backported version of `libseccomp2` is needed. (See the [trusty-backports](https://packages.ubuntu.com/trusty-backports/libseccomp2) and [jessie-backports](https://packages.debian.org/jessie-backports/libseccomp2)). +## Step 1: Download Release Tarball +Download release tarball for the `containerd` version you want to install from the GCS bucket. +```bash +wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz +``` +Validate checksum of the release tarball: +```bash +wget https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum +sha256sum --check cri-containerd-cni-${VERSION}-linux-amd64.tar.gz.sha256sum +``` +## Step 2: Install Containerd +If you are using systemd, just simply unpack the tarball to the root directory: +```bash +sudo tar --no-overwrite-dir -C / -xzf cri-containerd-cni-${VERSION}-linux-amd64.tar.gz +sudo systemctl daemon-reload +sudo systemctl start containerd +``` +If you are not using systemd, please unpack all binaries into a directory in your `PATH`, and start `containerd` as monitored long running services with the service manager you are using e.g. `supervisord`, `upstart` etc. +## Step 3: Install Kubeadm, Kubelet and Kubectl +Follow [the instructions](https://kubernetes.io/docs/setup/independent/install-kubeadm/) to install kubeadm, kubelet and kubectl. +## Step 4: Create Systemd Drop-In for Containerd +Create the systemd drop-in file `/etc/systemd/system/kubelet.service.d/0-containerd.conf`: +``` +[Service] +Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock" +``` +And reload systemd configuration: +```bash +systemctl daemon-reload +``` +## Bring Up the Cluster +Now you should have properly installed all required binaries and dependencies on each of your node. + +The next step is to use kubeadm to bring up the Kubernetes cluster. It is the same with [the ansible installer](../../contrib/ansible). Please follow the steps 2-4 [here](../../contrib/ansible/README.md#step-2). Binary files /tmp/tmp4z7_tba8/FAzrZmqiYm/containerd-1.2.6/docs/cri/performance.png and /tmp/tmp4z7_tba8/Bfxrm9w9fP/containerd-1.5.9/docs/cri/performance.png differ diff -Nru containerd-1.2.6/docs/cri/proposal.md containerd-1.5.9/docs/cri/proposal.md --- containerd-1.2.6/docs/cri/proposal.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/proposal.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,111 @@ +Containerd CRI Integration +============= +Author: Lantao Liu (@random-liu) +## Abstract +This proposal aims to integrate [containerd](https://github.com/containerd/containerd) with Kubelet against the [container runtime interface (CRI)](https://github.com/kubernetes/kubernetes/blob/v1.6.0/pkg/kubelet/api/v1alpha1/runtime/api.proto). +## Background +Containerd is a core container runtime, which provides the minimum set of functionalities to manage the complete container lifecycle of its host system, including container execution and supervision, image distribution and storage, etc. + +Containerd was [introduced in Docker 1.11](https://blog.docker.com/2016/04/docker-engine-1-11-runc/), used to manage [runC](https://runc.io/) containers on the node. As shown below, it creates a containerd-shim for each container, and the shim manages the lifecycle of its corresponding container. +![containerd](./containerd.png) + +In Dec. 2016, Docker Inc. spun it out into a standalone component, and donated it to [CNCF](https://www.cncf.io/) in Mar. 2017. + +## Motivation +Containerd is one potential alternative to Docker as the runtime for Kubernetes clusters. *Compared with Docker*, containerd has pros and cons. +### Pros +* **Stability**: Containerd has limited scope and slower feature velocity, which is expected to be more stable. +* **Compatibility**: The scope of containerd aligns with Kubernetes' requirements. It provides the required functionalities and the flexibility for areas like image pulling, networking, volume and logging etc. +* **Performance**: + * Containerd consumes less resource than Docker at least because it's a subset of Docker; + * Containerd CRI integration eliminates an extra hop in the stack (as shown below). ![performance](./performance.png) +* **Neutral Foundation**: Containerd is part of CNCF now. +### Cons +* **User Adoption**: + * Ideally, Kubernetes users don't interact with the underlying container runtime directly. However, for the lack of debug toolkits, sometimes users still need to login the node to debug with Docker CLI directly. + * Containerd provides barebone CLIs [ctr](https://github.com/containerd/containerd/tree/master/cmd/ctr) and [dist](https://github.com/containerd/containerd/tree/master/cmd/dist) for development and debugging purpose, but they may not be sufficient and necessary. Additionally, presuming these are sufficient and necessary tools, a plan and time would be needed to sufficiently document these CLIs and educate users in their use. +* **Maturity**: The rescoped containerd is pretty new, and it's still under heavy development. +## Goals +* Make sure containerd meets the requirement of Kubernetes, now and into the foreseeable future. +* Implement containerd CRI shim and make sure it provides equivalent functionality, usability and debuggability. +* Improve Kubernetes by taking advantage of the flexibility provided by containerd. +## Design +The following sections discuss the design aspects of the containerd CRI integration. For the purposes of this doc, the containerd CRI integration will be referred to as `CRI-containerd`. +### Container Lifecycle +CRI-containerd relies on containerd to manage container lifecycle. + +Ideally, CRI-containerd only needs to do api translation and information reorganization. However, CRI-containerd needs to maintain some metadata because: +* There is a mismatch between container lifecycle of CRI and containerd - containerd only tracks running processes, once the container and it's corresponding containerd-shim exit, the container is no longer visible in the containerd API. +* Some sandbox/container metadata is not provided by containerd, and we can not leverage OCI runtime annotation to store it because of the container lifecycle mismatch, e.g. labels/annotations, `PodSandboxID` of a container, `FinishedAt` timestamp, `ExitCode`, `Mounts` etc. + +CRI-containerd should checkpoint these metadata itself or use [containerd metadata service](https://github.com/containerd/containerd/blob/0a5544d8c4dab44dfc682f5ad07f1cd011c0a115/design/plugins.md#core) if available. +### Container Logging +Containerd doesn't provide persistent container log. It redirects container STDIO into different FIFOs. + +CRI-containerd should start a goroutine (process/container in the future) to: +* Continuously drain the FIFO; +* Decorate the log line into [CRI-defined format](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/kubelet-cri-logging.md#proposed-solution); +* Write the log into [CRI-defined log path](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/kubelet-cri-logging.md#proposed-solution). +### Container Streaming +Containerd supports creating a process in the container with `Exec`, and the STDIO is also exposed as FIFOs. Containerd also supports resizing console of a specific process with `Pty`. + +CRI-containerd could reuse the [streaming server](https://github.com/kubernetes/kubernetes/blob/release-1.6/pkg/kubelet/server/streaming/server.go), it should implement the [streaming runtime interface](https://github.com/kubernetes/kubernetes/blob/release-1.6/pkg/kubelet/server/streaming/server.go#L61-L65). + +For different CRI streaming functions: +* `ExecSync`: CRI-containerd should use `Exec` to create the exec process, collect the stdout/stderr of the process, and wait for the process to terminate. +* `Exec`: CRI-containerd should use `Exec` to create the exec process, create a goroutine (process/container) to redirect streams, and wait for the process to terminate. +* `Attach`: CRI-containerd should create a goroutine (process/container) to read the existing container log to the output, redirect streams of the init process, and wait for any stream to be closed. +* `PortForward`: CRI-containerd could implement this with `socat` and `nsenter`, similar with [current Docker portforward implementation](https://github.com/kubernetes/kubernetes/blob/release-1.6/pkg/kubelet/dockertools/docker_manager.go#L1373-L1428). +### Container Networking +Containerd doesn't provide container networking, but OCI runtime spec supports joining a linux container into an existing network namespace. + +CRI-containerd should: +* Create a network namespace for a sandbox; +* Call [network plugin](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/network/plugins.go) to update the options of the network namespace; +* Let the user containers in the same sandbox share the network namespace. +### Container Metrics +Containerd provides [container cgroup metrics](https://github.com/containerd/containerd/blob/master/reports/2017-03-17.md#metrics), and plans to provide [container writable layer disk usage](https://github.com/containerd/containerd/issues/678). + +CRI container metrics api needs to be defined ([#27097](https://github.com/kubernetes/kubernetes/issues/27097)). After that, CRI-containerd should translate containerd container metrics into CRI container metrics. +### Image Management +CRI-containerd relies on containerd to manage images. Containerd should provide all function and information required by CRI, and CRI-containerd only needs to do api translation and information reorganization. + +### ImageFS Metrics +Containerd plans to provide [image filesystem metrics](https://github.com/containerd/containerd/issues/678). + +CRI image filesystem metrics needs to be defined ([#33048](https://github.com/kubernetes/kubernetes/issues/33048)). After that, we should make sure containerd provides the required metrics, and CRI-containerd should translate containerd image filesystem metrics into CRI image filesystem metrics. +### Out of Scope +Following items are out of the scope of this design, we may address them in future version as enhancement or optimization. +* **Debuggability**: One of the biggest concern of CRI-containerd is debuggability. We should provide equivalent debuggability with Docker CLI through `kubectl`, [`cri-tools`](https://github.com/kubernetes-sigs/cri-tools) or containerd CLI. +* **Built-in CRI support**: The [plugin model](https://github.com/containerd/containerd/blob/master/design/plugins.md) provided by containerd makes it possible to directly build CRI support into containerd as a plugin, which will eliminate one more hop from the stack. But because of the [limitation of golang plugin](https://github.com/containerd/containerd/issues/563), we have to either maintain our own branch or push CRI plugin upstream. +* **Seccomp**: ([#36997](https://github.com/kubernetes/kubernetes/issues/36997)) Seccomp is supported in OCI runtime spec. However, current seccomp implementation in Kubernetes is experimental and docker specific, the api needs to be defined in CRI first before CRI-containerd implements it. +* **Streaming server authentication**: ([#36666](https://github.com/kubernetes/kubernetes/issues/36666)) CRI-containerd will be out-of-process with Kubelet, so it could not reuse Kubelet authentication. Its streaming server should implement its own authentication mechanism. +* **Move container facilities into pod cgroup**: Container facilities including container image puller, container streaming handler, log handler and containerd-shim serve a specific container. They should be moved to the corresponding pod cgroup, and the overhead introduced by them should be charged to the pod. +* **Log rotation**: ([#42718](https://github.com/kubernetes/kubernetes/issues/42718)) Container log rotation is under design. A function may be added in CRI to signal the runtime to reopen log file. CRI-containerd should implement that function after it is defined. +* **Exec container**: With the flexibility provided by containerd, it is possible to implement `Exec` with a separate container sharing the same rootfs and mount namespace with the original container. The advantage is that the `Exec` container could have it's own sub-cgroup, so that it will not consume the resource of application container and user could specify dedicated resource for it. +* **Advanced image management**: The image management interface in CRI is relatively simple because the requirement of Kubelet image management is not clearly scoped out. In the future, we may want to leverage the flexibility provided by containerd more, e.g. estimate image size before pulling etc. +* ... +## Roadmap and Milestones +### Milestones +#### Kubernetes 1.7 - Q2 +* [P0] Basic container lifecycle. +* [P0] Basic image management. +* [P0] Container networking. +* [P1] Container streaming/logging. +* [P2] Container/ImageFS Metrics. + +*Test Plan: Each feature added should have unit test and pass its corresponding cri validation test.* +#### Kubernetes 1.8 - Q3 +* [P0] Feature complete, pass 100% cri validation test. +* [P0] Integrate CRI-containerd with Kubernetes, and build the e2e/node e2e test framework. +* [P1] Address the debuggability problem. +### Q2 Roadmap +| Item | 1/2 Mar. | 2/2 Mar. | 1/2 Apr. | 2/2 Apr. | 1/2 May. | 2/2 May. | +|:--------------------------------:|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:| +| Survey | ✓ | | | | | | +| POC | | ✓ | | | | | +| Proposal | | | ✓ | | | | +| Containerd Feature Complete | ✓ | ✓ | ✓ | | | | +| Runtime Management Integration | | | ✓ | ✓ | ✓ | ✓ | +| Image Management Integration | | | | ✓ | ✓ | ✓ | +| Container Networking Integration | | | | | ✓ | ✓ | diff -Nru containerd-1.2.6/docs/cri/registry.md containerd-1.5.9/docs/cri/registry.md --- containerd-1.2.6/docs/cri/registry.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/registry.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,195 @@ +# Configure Image Registry + +This document describes the method to configure the image registry for `containerd` for use with the `cri` plugin. + +*** registry.mirrors and registry.configs as described in this document +have been DEPRECATED. As described in [the cri config](./config.md#registry-configuration) you +should now use the form +```toml +[plugins."io.containerd.grpc.v1.cri".registry] + config_path = "/etc/containerd/certs.d" +``` + +## Configure Registry Endpoint + +With containerd, `docker.io` is the default image registry. You can also set up other image registries similar to docker. + +To configure image registries create/modify the `/etc/containerd/config.toml` as follows: + +```toml +# Config file is parsed as version 1 by default. +# To use the long form of plugin names set "version = 2" +# explicitly use v2 config format +version = 2 + +[plugins."io.containerd.grpc.v1.cri".registry.mirrors] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] + endpoint = ["https://registry-1.docker.io"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."test.https-registry.io"] + endpoint = ["https://HostIP1:Port1"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."test.http-registry.io"] + endpoint = ["http://HostIP2:Port2"] + # wildcard matching is supported but not required. + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."*"] + endpoint = ["https://HostIP3:Port3"] +``` + +The default configuration can be generated by `containerd config default > /etc/containerd/config.toml`. + +The endpoint is a list that can contain multiple image registry URLs split by commas. When pulling an image +from a registry, containerd will try these endpoint URLs one by one, and use the first working one. Please note +that if the default registry endpoint is not already specified in the endpoint list, it will be automatically +tried at the end with scheme `https` and path `v2`, e.g. `https://gcr.io/v2` for `gcr.io`. + +As an example, for the image `gcr.io/library/busybox:latest`, the endpoints are: + +* `gcr.io` is configured: endpoints for `gcr.io` + default endpoint `https://gcr.io/v2`. +* `*` is configured, and `gcr.io` is not: endpoints for `*` + default + endpoint `https://gcr.io/v2`. +* None of above is configured: default endpoint `https://gcr.io/v2`. + +After modify this config, you need restart the `containerd` service. + +## Configure Registry TLS Communication + +`cri` plugin also supports configuring TLS settings when communicating with a registry. + +To configure the TLS settings for a specific registry, create/modify the `/etc/containerd/config.toml` as follows: + +```toml +# explicitly use v2 config format +version = 2 + +# The registry host has to be a domain name or IP. Port number is also +# needed if the default HTTPS or HTTP port is not used. +[plugins."io.containerd.grpc.v1.cri".registry.configs."my.custom.registry".tls] + ca_file = "ca.pem" + cert_file = "cert.pem" + key_file = "key.pem" +``` + +In the config example shown above, TLS mutual authentication will be used for communications with the registry endpoint located at . +`ca_file` is file name of the certificate authority (CA) certificate used to authenticate the x509 certificate/key pair specified by the files respectively pointed to by `cert_file` and `key_file`. + +`cert_file` and `key_file` are not needed when TLS mutual authentication is unused. + +```toml +# explicitly use v2 config format +version = 2 + +[plugins."io.containerd.grpc.v1.cri".registry.configs."my.custom.registry".tls] + ca_file = "ca.pem" +``` + +To skip the registry certificate verification: + +```toml +# explicitly use v2 config format +version = 2 + +[plugins."io.containerd.grpc.v1.cri".registry.configs."my.custom.registry".tls] + insecure_skip_verify = true +``` + +## Configure Registry Credentials + +`cri` plugin also supports docker like registry credential config. + +To configure a credential for a specific registry, create/modify the +`/etc/containerd/config.toml` as follows: + +```toml +# explicitly use v2 config format +version = 2 + +# The registry host has to be a domain name or IP. Port number is also +# needed if the default HTTPS or HTTP port is not used. +[plugins."io.containerd.grpc.v1.cri".registry.configs."gcr.io".auth] + username = "" + password = "" + auth = "" + identitytoken = "" +``` + +The meaning of each field is the same with the corresponding field in `.docker/config.json`. + +Please note that auth config passed by CRI takes precedence over this config. +The registry credential in this config will only be used when auth config is +not specified by Kubernetes via CRI. + +After modifying this config, you need to restart the `containerd` service. + +### Configure Registry Credentials Example - GCR with Service Account Key Authentication + +If you don't already have Google Container Registry (GCR) set-up then you need to do the following steps: + +* Create a Google Cloud Platform (GCP) account and project if not already created (see [GCP getting started](https://cloud.google.com/gcp/getting-started)) +* Enable GCR for your project (see [Quickstart for Container Registry](https://cloud.google.com/container-registry/docs/quickstart)) +* For authentication to GCR: Create [service account and JSON key](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key) +* The JSON key file needs to be downloaded to your system from the GCP console +* For access to the GCR storage: Add service account to the GCR storage bucket with storage admin access rights (see [Granting permissions](https://cloud.google.com/container-registry/docs/access-control#grant-bucket)) + +Refer to [Pushing and pulling images](https://cloud.google.com/container-registry/docs/pushing-and-pulling) for detailed information on the above steps. + +> Note: The JSON key file is a multi-line file and it can be cumbersome to use the contents as a key outside of the file. It is worthwhile generating a single line format output of the file. One way of doing this is using the `jq` tool as follows: `jq -c . key.json` + +It is beneficial to first confirm that from your terminal you can authenticate with your GCR and have access to the storage before hooking it into containerd. This can be verified by performing a login to your GCR and +pushing an image to it as follows: + +```console +docker login -u _json_key -p "$(cat key.json)" gcr.io + +docker pull busybox + +docker tag busybox gcr.io/your-gcp-project-id/busybox + +docker push gcr.io/your-gcp-project-id/busybox + +docker logout gcr.io +``` + +Now that you know you can access your GCR from your terminal, it is now time to try out containerd. + +Edit the containerd config (default location is at `/etc/containerd/config.toml`) +to add your JSON key for `gcr.io` domain image pull +requests: + +```toml +version = 2 + +[plugins."io.containerd.grpc.v1.cri".registry] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] + endpoint = ["https://registry-1.docker.io"] + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"] + endpoint = ["https://gcr.io"] + [plugins."io.containerd.grpc.v1.cri".registry.configs] + [plugins."io.containerd.grpc.v1.cri".registry.configs."gcr.io".auth] + username = "_json_key" + password = 'paste output from jq' +``` + +> Note: `username` of `_json_key` signifies that JSON key authentication will be used. + +Restart containerd: + +```console +service containerd restart +``` + +Pull an image from your GCR with `crictl`: + +```console +$ sudo crictl pull gcr.io/your-gcp-project-id/busybox + +DEBU[0000] get image connection +DEBU[0000] connect using endpoint 'unix:///run/containerd/containerd.sock' with '3s' timeout +DEBU[0000] connected successfully using endpoint: unix:///run/containerd/containerd.sock +DEBU[0000] PullImageRequest: &PullImageRequest{Image:&ImageSpec{Image:gcr.io/your-gcr-instance-id/busybox,},Auth:nil,SandboxConfig:nil,} +DEBU[0001] PullImageResponse: &PullImageResponse{ImageRef:sha256:78096d0a54788961ca68393e5f8038704b97d8af374249dc5c8faec1b8045e42,} +Image is up to date for sha256:78096d0a54788961ca68393e5f8038704b97d8af374249dc5c8faec1b8045e42 +``` + +--- + +NOTE: The configuration syntax used in this doc is in version 2 which is the recommended since `containerd` 1.3. For the previous config format you can reference [https://github.com/containerd/cri/blob/release/1.2/docs/registry.md](https://github.com/containerd/cri/blob/release/1.2/docs/registry.md). diff -Nru containerd-1.2.6/docs/cri/testing.md containerd-1.5.9/docs/cri/testing.md --- containerd-1.2.6/docs/cri/testing.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/cri/testing.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +CRI Plugin Testing Guide +======================== +This document assumes you have already setup the development environment (go, git, `github.com/containerd/containerd` repo etc.). + +Before sending pull requests you should at least make sure your changes have passed code verification, unit, integration and CRI validation tests. + +## Build +Follow the [building](../../BUILDING.md) instructions. + +## CRI Integration Test +* Run CRI integration test: +```bash +make cri-integration +``` +## CRI Validation Test +[CRI validation test](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/validation.md) is a test framework for validating that a Container Runtime Interface (CRI) implementation such as containerd with the `cri` plugin meets all the requirements necessary to manage pod sandboxes, containers, images etc. + +CRI validation test makes it possible to verify CRI conformance of `containerd` without setting up Kubernetes components or running Kubernetes end-to-end tests. +* [Install dependencies](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/validation.md#install). +* Run the containerd you built above with the `cri` plugin built in: +```bash +containerd -l debug +``` +* Run CRI [validation](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/validation.md#run) test. + +[More information](https://github.com/kubernetes-sigs/cri-tools) about CRI validation test. +## Node E2E Test +[Node e2e test](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md) is a test framework testing Kubernetes node level functionalities such as managing pods, mounting volumes etc. It starts a local cluster with Kubelet and a few other minimum dependencies, and runs node functionality tests against the local cluster. + +Currently e2e-node tests are supported from via Pull Request comments on github. +Enter "/test all" as a comment on a pull request for a list of testing options that have been integrated through prow bot with kubernetes testing services hosted on GCE. +Typing `/test pull-containerd-node-e2e` will start a node e2e test run on your pull request commits. + +[More information](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md) about Kubernetes node e2e test. diff -Nru containerd-1.2.6/docs/dockercon-summit.md containerd-1.5.9/docs/dockercon-summit.md --- containerd-1.2.6/docs/dockercon-summit.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/dockercon-summit.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# Dockercon 2017 Summit - -This year at Dockercon US 2017 we will be having a containerd Summit on Thursday morning the week of the conference. - -We are going to change the format slightly compared to the previous summit that was held in February. We will be allocating more time to the breakout sessions and less time to static talks. However, the group will be much larger than the previous summit so this document serves as a way to add discussion points for the breakout sessions. - -If you would like to add a discussion point to the agenda, submit a PR adding it to the list below. A simple one line sentence is enough or expand if needed. - -If you have not signed up to attend the summit you can do so in this [form](https://docs.google.com/forms/d/e/1FAIpQLScNkLm984ABbFChPh02uJR2lJ6y1AXjFaDITCaxTFL-sHhPwQ/viewform). - -## Discussion Points - -The following are proposed discussion points for the containerd summit at Dockercon US 2017: - - -* Since containerd is one of the bottom bricks in the stack, how can we setup automated integration tests for consumers of containerd? -* We'd like to propose an Authorization plugin to containerd that would allow an external component to police events like container start & stop (and have a discussion about the best way to go about it) -* Should containerd provide image filesystem metrics? If yes, what metrics should be included? How to implement that? -* Support for disk quotas: How? What is the role of containerd? How is it going to be integrated with volume managers that want to be in the same quota group? -* Checkpoint/Restore: how can we support more use cases? One of the big issues here is the large number of options that can be passed to CRIU. -* How to support multi-OS docker images, for example, Linux Vs Windows using one graph driver plugin properly? diff -Nru containerd-1.2.6/docs/.dockerignore containerd-1.5.9/docs/.dockerignore --- containerd-1.2.6/docs/.dockerignore 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/.dockerignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -.dockerignore -.git -.gitignore -Dockerfile -docker-compose.yml \ No newline at end of file diff -Nru containerd-1.2.6/docs/.editorconfig containerd-1.5.9/docs/.editorconfig --- containerd-1.2.6/docs/.editorconfig 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/.editorconfig 2022-01-05 17:30:58.000000000 +0000 @@ -1,13 +1,8 @@ -[*] +[*.md] end_of_line = lf charset = utf-8 max_line_length = 80 trim_trailing_whitespace = true insert_final_newline = false - -[*.{html,js,sh,sass,md,mmark}] indent_style = space indent_size = 2 - -[Makefile] -indent_style = tab diff -Nru containerd-1.2.6/docs/garbage-collection.md containerd-1.5.9/docs/garbage-collection.md --- containerd-1.2.6/docs/garbage-collection.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/garbage-collection.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,164 @@ +# Garbage Collection + +`containerd` has a garbage collector capable of removing resources which are no +longer being used. The client is responsible for ensuring that all resources +which are created are either used or held by a lease at all times, else they +will be considered eligible for removal. The Go client library +(`github.com/containerd/containerd`) has built-in behavior to ensure resources +are properly tracked and leased. However, the lifecycles of leases are the +responsibility of the caller of the library. The `containerd` daemon has strict +resource management and will garbage collect any unused resource. + +## What is a lease? + +Leases are a resource in `containerd` which are created by clients and are used +to reference other resources such as snapshots and content. Leases may be +configured with an expiration or deleted by clients once it has completed an +operation. Leases are needed to inform the `containerd` daemon that a resource +may be used in the future after the client completes an operation, even though +it currently is not seen as utilized. + +## How to use leases + +### using Go client + +The best way to use leases is to add it to a Go context immediately after the +context is created. Normally the lifespan of a lease will be the same as the +lifecycle of a Go context. + +```.go + ctx, done, err := client.WithLease(ctx) + if err != nil { + return err + } + defer done(ctx) +``` + +This will create a lease which will defer its own deletion and have a default +expiry of 24 hours (in case the process dies before defer). For most use cases, +this is enough and no more thought needs to be put into leases. + +_But, of course, more complicated use cases are supported..._ + +If the program or lease are intended to be longer lived, instead of the very +easy `client.WithLease`, the lease manager can be used directly. This also +allows for setting custom labels on the lease or manipulating its resources. +Use `client.LeasesService()` to get a [lease Manager](https://godoc.org/github.com/containerd/containerd/leases#Manager) +which can be used to create, list, and delete leases as well as manage the +referenced resources for that lease. + +```.go + manager := client.LeasesService() + + // this lease will never expire + // Use `leases.WithExpiration` to make it expire + // Use `leases.WithLabels` to apply any labels + l, err := manager.Create(ctx, leases.WithRandomID()) + if err != nil { + return err + } + + // Update current context to add lease + ctx = leases.WithLease(ctx, l.ID) + + // Do something, lease will be used... + + // Delete lease at any time, or track it to delete later + if err := ls.Delete(ctx, l); err != nil { + return err + } +``` + + +### using gRPC + +The lease is not an explicit field in the API (except of course the leases +service), but rather an optional field any API service can use. Leases can +be set on any gRPC service endpoint using a gRPC header. Set the +gRPC header `containerd-lease` to the lease identifier and the API +service will operate within that lease context. + +To manage the creation and deletion of leases, use the leases gRPC service. + +## Garbage Collection labels + +The garbage collection defines relationships between resources in two different +ways, by type specific resources properties, and by resource labels. The type +specific properties do not need to be managed by the user as they are part of +the natural structure of a resource (i.e. a container's snapshot, a snapshot's +parent, an image's target, etc). However resources may have relationships which +are not defined by `containerd`, but rather by the client. For example, an OCI +image has a manifest which references a config file and layer tars. These +resources are stored in `containerd` as generic blobs, it is the client that +understands the relationships between these blobs and sets them up using labels +on the content resources. + +Resource labels can also be used to cue the garbage collector on other +properties, such as expiry, whether an object should be kept without any +reference or limit what is referenced. + +The supported garbage collection labels are: + +| Label key | Label value | Supported Resources | Description | +|---|---|---|---| +| `containerd.io/gc.root` | _nonempty_ | Content, Snapshots | Keep this object and anything it references. (Clients may set this to a [rfc3339](https://tools.ietf.org/html/rfc3339) timestamp to indicate when this value was set, however, the garbage collector does not parse the value) | +| `containerd.io/gc.ref.snapshot.` | `` | Content, Snapshots | Resource references the given snapshot `` for the snapshotter `` | +| `containerd.io/gc.ref.content` | _digest_ | Content, Snapshots, Images, Containers | Resource references the given content blob | +| `containerd.io/gc.ref.content.` | _digest_ | Content, Snapshots, Images, Containers | Resource references the given content blob with a `` label key | +| `containerd.io/gc.expire` | _timestamp_ formatted as [rfc3339](https://tools.ietf.org/html/rfc3339) | Leases | When to expire the lease. The garbage collector will delete the lease after expiration. | +| `containerd.io/gc.flat` | _nonempty_ | Leases | Ignore label references of leased resources. This only applies when the reference is originating from the lease, if the leased resources are referenced elsewhere, then their label references will be used. | + +## Garbage Collection configuration + +The garbage collector (gc) is scheduled on a background goroutine and runs based +on a number of configurable factors. By default the garbage collector will +attempt to keep the database unlocked 98% of the time based on prior +calculations of lock time from garbage collection. Also by default, the garbage +collector will not schedule itself if no deletions occurred or after every 100 +database writes. + +The garbage collection scheduler considers the time the database is locked +as the pause time. The garbage collection will take longer than this when +resources are being removed, for example cleaning up snapshots may be slow. +The scheduler will only schedule after the whole garbage collection is +completed but use the average pause time for determining when the next run +attempt is. + +Garbage collection may be configured using the `containerd` daemon's +configuration file, usually at `/etc/containerd/config.toml`. The +configuration is under the `scheduler` plugin. + +### Configuration parameters + +| Configuration | Default | Description | +|---|---|---| +| `pause_threshold` | 0.02 | Represents the maximum amount of time gc should be scheduled based on the average pause time. A maximum value of .5 (50%) is enforced to prevent over scheduling. | +| `deletion_threshold` | 0 | A threshold of number of deletes to immediately trigger gc. 0 means a gc will not be triggered by deletion count, however a deletion will ensure the next scheduled gc will run. | +| `mutation_threshold` | 100 | A threshold for running gc after the given number of database mutations. Note any mutation which performed a delete will always cause gc to run, this case handles more rare events such as label reference removal. | +| `schedule_delay` | "0ms" | The delay between a trigger event and running gc. A non-zero value can be used when mutations may quickly burst. | +| `startup_delay` | "100ms" | The delay before running the initial garbage collection after daemon startup. This should be run after other startup processes have completed and no gc can be scheduled before this delay. | + +The default configuration is represented as... +```.toml +[plugins] + [plugins.scheduler] + pause_threshold = 0.02 + deletion_threshold = 0 + mutation_threshold = 100 + schedule_delay = "0ms" + startup_delay = "100ms" +``` + +## Synchronous Garbage Collection + +In addition to garbage collections done through the scheduler, the client +may also request a garbage collection during resource removal. In this case, +the garbage collection will be scheduled immediately (or after `schedule_delay` +when configured to non-zero). The service will not return until the garbage +collection has completed. This is currently supported on removal of images and +leases. Use [`images.SynchronousDelete()`](https://godoc.org/github.com/containerd/containerd/images#SynchronousDelete) +for [`images.Store`](https://godoc.org/github.com/containerd/containerd/images#Store)'s +`Delete` and +[`leases.SynchronousDelete`](https://godoc.org/github.com/containerd/containerd/leases#SynchronousDelete) +for [`leases.Manager`](https://godoc.org/github.com/containerd/containerd/leases#Manager)'s +`Delete`. diff -Nru containerd-1.2.6/docs/getting-started.md containerd-1.5.9/docs/getting-started.md --- containerd-1.2.6/docs/getting-started.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/getting-started.md 2022-01-05 17:30:58.000000000 +0000 @@ -6,7 +6,7 @@ In this guide we will pull and run a redis server with containerd using the client package. We will assume that you are running a modern linux host for this example with a compatible build of `runc`. -Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc`. +Please refer to [RUNC.md](/docs/RUNC.md) for the currently supported version of `runc`. This project requires Go 1.9.x or above. If you need to install Go or update your currently installed one, please refer to Go install page at https://golang.org/doc/install. @@ -19,7 +19,6 @@ A sample configuration file looks like this: ```toml -subreaper = true oom_score = -999 [debug] @@ -429,4 +428,4 @@ In the end, we really did not write that much code when you use the client package. I hope this guide helped to get you up and running with containerd. -Feel free to join the [slack channel](https://dockr.ly/community) if you have any questions and like all things, if you want to help contribute to containerd or this guide, submit a pull request. +Feel free to join the `#containerd` and `#containerd-dev` slack channels on Cloud Native Computing Foundation's (CNCF) slack - `cloud-native.slack.com` if you have any questions and like all things, if you want to help contribute to containerd or this guide, submit a pull request. [Get Invite to CNCF slack.](https://slack.cncf.io) diff -Nru containerd-1.2.6/docs/.gitignore containerd-1.5.9/docs/.gitignore --- containerd-1.2.6/docs/.gitignore 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -**/.DS_Store -**/desktop.ini -CNAME - -# Hugo-generated content -public/ diff -Nru containerd-1.2.6/docs/hosts.md containerd-1.5.9/docs/hosts.md --- containerd-1.2.6/docs/hosts.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/hosts.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,312 @@ + +# Registry Configuration - Introduction + +Configuring registries will be done by specifying (optionally) a `hosts.toml` file for +each desired registry host in a configuration directory. **Note**: Updates under this directory +do not require restarting the containerd daemon. + +## Specifying the Configuration Directory + +### Using Host Namespace Configs with CTR + +When pulling via `ctr` use the `--hosts-dir` option: +``` +ctr images pull --hosts-dir "/etc/containerd/certs.d" +``` + +### CRI +_The old CRI config pattern for specifying registry.mirrors and registry.configs has +been **DEPRECATED**._ You should now point your registry `config_path` to the path where your +`hosts.toml` files are located. + +Modify your `config.toml` (default location: `/etc/containerd/config.toml`) as follows: +```toml +[plugins."io.containerd.grpc.v1.cri".registry] + config_path = "/etc/containerd/certs.d" +``` + +## Support for Docker's Certificate File Pattern + +If no hosts.toml configuration exists in the host directory, it will fallback to check +certificate files based on [Docker's certificate file pattern](https://docs.docker.com/engine/reference/commandline/dockerd/#insecure-registries) +(".crt" files for CA certificates and ".cert"/".key" files for client certificates). + +## Registry Host Namespace + +A registry host is the location where container images and artifacts are sourced. These +registry hosts may be local or remote and are typically accessed via http/https using the +[OCI distribution specification](https://github.com/opencontainers/distribution-spec/blob/main/spec.md). +A registry mirror is not a registry host but these mirrors can also be used to pull content. +Registry hosts are typically refered to by their internet domain names, aka. registry +host names. For example, docker.io, quay.io, gcr.io, and ghcr.io. + +A registry host namespace is, for the purpose of containerd registry configuration, a +path to the `hosts.toml` file specified by the registry host name, or ip address, and an +optional port identifier. When making a pull request for an image the format is +typically as follows: +``` +pull [registry_host_name|IP address][:port][/v2][/org_path][:tag|@DIGEST] +``` + +The registry host namespace portion is `[registry_host_name|IP address][:port]`. Example +tree for docker.io: + +``` +$ tree /etc/containerd/certs.d +/etc/containerd/certs.d +└── docker.io + └── hosts.toml +``` + +The `/v2` portion of the pull request format shown above refers to the version of the +distribution api. If not included in the pull request, `/v2` is added by default for all +clients compliant to the distribution specification linked above. + +For example when pulling image_name:tag from a private registry named myregistry.io over +port 5000: +``` +pull myregistry.io:5000/image_name:tag +``` +The pull will resolve to `https://myregistry.io:5000/v2/image_name:tag` + +## Specifying Registry Credentials + +### CTR + +When performing image operations via `ctr` use the --help option to get a list of options you can set for specifying credentials: +``` +ctr i pull --help +... +OPTIONS: + --skip-verify, -k skip SSL certificate validation + --plain-http allow connections using plain HTTP + --user value, -u value user[:password] Registry user and password + --refresh value refresh token for authorization server + --hosts-dir value Custom hosts configuration directory + --tlscacert value path to TLS root CA + --tlscert value path to TLS client certificate + --tlskey value path to TLS client key + --http-dump dump all HTTP request/responses when interacting with container registry + --http-trace enable HTTP tracing for registry interactions + --snapshotter value snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER] + --label value labels to attach to the image + --platform value Pull content from a specific platform + --all-platforms pull content and metadata from all platforms + --all-metadata Pull metadata for all platforms + --print-chainid Print the resulting image's chain ID + --max-concurrent-downloads value Set the max concurrent downloads for each pull (default: 0) +``` + +## CRI + +Although we have deprecated the old CRI config pattern for specifying registry.mirrors +and registry.configs you can still specify your credentials via +[CRI config](https://github.com/containerd/containerd/blob/master/docs/cri/registry.md#configure-registry-credentials). + +Additionally, the containerd CRI plugin implements/supports the authentication parameters passed in through CRI pull image service requests. +For example, when containerd is the container runtime implementation for `Kubernetes`, the containerd CRI plugin receives +authentication credentials from kubelet as retrieved from +[Kubernetes Image Pull Secrets](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) + +# Registry Configuration - Examples + +### Simple (default) Host Config for Docker +Here is a simple example for a default registry hosts configuration. Set +`config_path = "/etc/containerd/certs.d"` in your config.toml for containerd. +Make a directory tree at the config path that includes `docker.io` as a directory +representing the host namespace to be configured. Then add a `hosts.toml` file +in the `docker.io` to configure the host namespace. It should look like this: + +``` +$ tree /etc/containerd/certs.d +/etc/containerd/certs.d +└── docker.io + └── hosts.toml + +$ cat /etc/containerd/certs.d/docker.io/hosts.toml +server = "https://docker.io" + +[host."https://registry-1.docker.io"] + capabilities = ["pull", "resolve"] +``` + +### Setup a Local Mirror for Docker + +``` +server = "https://registry-1.docker.io" # Exclude this to not use upstream + +[host."https://public-mirror.example.com"] + capabilities = ["pull"] # Requires less trust, won't resolve tag to digest from this host +[host."https://docker-mirror.internal"] + capabilities = ["pull", "resolve"] + ca = "docker-mirror.crt" # Or absolute path /etc/containerd/certs.d/docker.io/docker-mirror.crt +``` + +### Bypass TLS Verification Example + +To bypass the TLS verification for a private registry at `192.168.31.250:5000` + +Create a path and `hosts.toml` text at the path "/etc/containerd/certs.d/docker.io/hosts.toml" with following or similar contents: + +```toml +server = "https://registry-1.docker.io" + +[host."http://192.168.31.250:5000"] + capabilities = ["pull", "resolve", "push"] + skip_verify = true +``` + +# hosts.toml Content Description - Detail + +For each registry host namespace directory in your registry `config_path` you may +include a `hosts.toml` configuration file. The following root level toml fields +apply to the registry host namespace: + +**Note**: All paths specified in the `hosts.toml` file may be absolute or relative +to the `hosts.toml` file. + +## server field +`server` specifies the default server for this registry host namespace. When +`host`(s) are specified, the hosts are tried first in the order listed. +``` +server = "https://docker.io" +``` + +## capabilities field + +`capabilities` is an optional setting for specifying what operations a host is +capable of performing. Include only the values that apply. +``` +capabilities = ["pull", "resolve", "push"] +``` + +capabilities (or Host capabilities) represent the capabilities of the registry host. +This also represents the set of operations for which the registry host may be trusted +to perform. + +For example, pushing is a capability which should only be performed on an upstream +source, not a mirror. + +Resolving (the process of converting a name into a digest) +must be considered a trusted operation and only done by +a host which is trusted (or more preferably by secure process +which can prove the provenance of the mapping). + +A public mirror should never be trusted to do a resolve action. + +| Registry Type | Pull | Resolve | Push | +|------------------|------|---------|------| +| Public Registry | yes | yes | yes | +| Private Registry | yes | yes | yes | +| Public Mirror | yes | no | no | +| Private Mirror | yes | yes | no | + +## ca field + +`ca` (Certificate Authority Certification) can be set to a path or an array of +paths each pointing to a ca file for use in authenticating with the registry +namespace. +``` +ca = "/etc/certs/mirror.pem" +``` +or +``` +ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"] +``` + +## client field + +`client` certificates are configured as follows + +a path: +``` +client = "/etc/certs/client.pem" +``` + +an array of paths: +``` +client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] +``` + +an array of pairs of paths: +``` +client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]] +``` + +## skip_verify field + +`skip_verify` set this flag to `true` to skip the registry certificate +verification for this registry host namespace. (Defaults to `false`) +``` +skip_verify = false +``` + +## header fields (in the toml table format) + +`[header]` contains some number of keys where each key is to one of a string or + +an array of strings as follows: +``` +[header] + x-custom-1 = "custom header" +``` + +or +``` +[header] + x-custom-1 = ["custom header part a","part b"] +``` + +or +``` +[header] + x-custom-1 = "custom header", + x-custom-1-2 = "another custom header" +``` + +## host field(s) (in the toml table format) + +`[host]."https://namespace"` and `[host].http://namespace` entries in the +`hosts.toml` configuration are registry namespaces used in lieu of the default +registry host namespace. These hosts are sometimes called mirrors because they +may contain a copy of the container images and artifacts you are attempting to +retrieve from the default registry. Each `host`/`mirror` namespace is also +configured in much the same way as the default registry namespace. Notably the +`server` is not specified in the `host` description because it is specified in +the namespace. Here are a few rough examples configuring host mirror namespaces +for this registry host namespace: +``` +[host."https://mirror.registry"] + capabilities = ["pull"] + ca = "/etc/certs/mirror.pem" + skip_verify = false + [host."https://mirror.registry".header] + x-custom-2 = ["value1", "value2"] + +[host."https://mirror-bak.registry/us"] + capabilities = ["pull"] + skip_verify = true + +[host."http://mirror.registry"] + capabilities = ["pull"] + +[host."https://test-1.registry"] + capabilities = ["pull", "resolve", "push"] + ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"] + client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]] + +[host."https://test-2.registry"] + client = "/etc/certs/client.pem" + +[host."https://test-3.registry"] + client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] +``` + +**Note**: Recursion is not supported in the specification of host mirror +namespaces in the hosts.toml file. Thus the following is not allowed/supported: +``` +[host."http://mirror.registry"] + capabilities = ["pull"] + [host."http://double-mirror.registry"] + capabilities = ["pull"] +``` diff -Nru containerd-1.2.6/docs/man/containerd.1.md containerd-1.5.9/docs/man/containerd.1.md --- containerd-1.2.6/docs/man/containerd.1.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/man/containerd.1.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# containerd 1 01/29/2018 - -## SYNOPSIS - -containerd [global options] command [command options] [arguments...] - -## DESCRIPTION - -**containerd** is a high performance container runtime whose daemon can be started -by using this command. If none of the *config*, *publish*, or *help* commands -are specified the default action of the **containerd** command is to start the -containerd daemon in the foreground. - -A default configuration is used if no TOML configuration is specified or located -at the default file location. The *containerd config* command can be used to -generate the default configuration for containerd. The output of that command -can be used and modified as necessary as a custom configuration. - -The *publish* command is used internally by parts of the containerd runtime -to publish events. It is not meant to be used as a standalone utility. - -## OPTIONS - -**--config value, -c value** -: Specify the default path to the configuration file (default: "/etc/containerd/config.toml") - -**--log-level value, -l value** -: Set the logging level. Available levels are: [debug, info, warn, error, fatal, panic] - -**--address value, -a value** -: UNIX socket address for containerd's GRPC server to listen on (default: "/run/containerd/containerd.sock") - -**--root value** -: The containerd root directory (default: "/var/lib/containerd"). A persistent directory location where metadata and image content are stored - -**--state value** -: The containerd state directory (default: "/run/containerd"). A transient state directory used during containerd operation - -**--help, -h** -: Show containerd command help text - -**--version, -v** -: Print the containerd server version - -## BUGS - -Please file any specific issues that you encounter at -https://github.com/containerd/containerd. - -## AUTHOR - -Phil Estes - -## SEE ALSO - -ctr(1), containerd-config(1), containerd-config.toml(5) diff -Nru containerd-1.2.6/docs/man/containerd-config.1.md containerd-1.5.9/docs/man/containerd-config.1.md --- containerd-1.2.6/docs/man/containerd-config.1.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/man/containerd-config.1.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# containerd-config 1 01/30/2018 - -## SYNOPSIS - -containerd config [command] - -## DESCRIPTION - -The *containerd config* command has one subcommand, named *default*, which -will display on standard output the default containerd config for this version -of the containerd daemon. - -This output can be piped to a __containerd-config.toml(5)__ file and placed in -**/etc/containerd** to be used as the configuration for containerd on daemon -startup. The configuration can be placed in any filesystem location and used -with the **--config** option to the containerd daemon as well. - -See __containerd-config.toml(5)__ for more information on the containerd -configuration options. - -## OPTIONS - -**default** -: This subcommand will output the TOML formatted containerd configuration to standard output - -## BUGS - -Please file any specific issues that you encounter at -https://github.com/containerd/containerd. - -## AUTHOR - -Phil Estes - -## SEE ALSO - -ctr(1), containerd(1), containerd-config.toml(5) diff -Nru containerd-1.2.6/docs/man/containerd-config.8.md containerd-1.5.9/docs/man/containerd-config.8.md --- containerd-1.2.6/docs/man/containerd-config.8.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/man/containerd-config.8.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,41 @@ +# containerd-config 8 01/30/2018 + +## NAME + +containerd-config - information on the containerd config + +## SYNOPSIS + +containerd config [command] + +## DESCRIPTION + +The *containerd config* command has one subcommand, named *default*, which +will display on standard output the default containerd config for this version +of the containerd daemon. + +This output can be piped to a __containerd-config.toml(5)__ file and placed in +**/etc/containerd** to be used as the configuration for containerd on daemon +startup. The configuration can be placed in any filesystem location and used +with the **--config** option to the containerd daemon as well. + +See __containerd-config.toml(5)__ for more information on the containerd +configuration options. + +## OPTIONS + +**default** +: This subcommand will output the TOML formatted containerd configuration to standard output + +## BUGS + +Please file any specific issues that you encounter at +https://github.com/containerd/containerd. + +## AUTHOR + +Phil Estes + +## SEE ALSO + +ctr(8), containerd(8), containerd-config.toml(5) diff -Nru containerd-1.2.6/docs/man/containerd-config.toml.5.md containerd-1.5.9/docs/man/containerd-config.toml.5.md --- containerd-1.2.6/docs/man/containerd-config.toml.5.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/man/containerd-config.toml.5.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,9 @@ # /etc/containerd/config.toml 5 08/08/2018 +## NAME + +containerd-config.toml - configuration file for containerd + ## SYNOPSIS The **config.toml** file is a configuration file for the containerd daemon. The @@ -28,6 +32,16 @@ **oom_score** : The out of memory (OOM) score applied to the containerd daemon process (Default: 0) +**imports** +: Imports is a list of additional configuration files to include. +This allows one to split the main configuration file and keep some sections +separately (for example vendors may keep a custom runtime configuration in a +separate file without modifying the main `config.toml`). +Imported files will overwrite simple fields like `int` or +`string` (if not empty) and will append `array` and `map` fields. +Imported files are also versioned, and the version can't be higher than +the main config. + **[grpc]** : Section for gRPC socket listener settings. Contains three properties: - **address** (Default: "/run/containerd/containerd.sock") @@ -78,6 +92,7 @@ root = "/var/lib/containerd" state = "/run/containerd" oom_score = 0 +imports = ["/etc/containerd/runtime_*.toml", "./debug.toml"] [grpc] address = "/run/containerd/containerd.sock" @@ -113,7 +128,7 @@ deletion_threshold = 0 mutation_threshold = 100 schedule_delay = 0 - startup_delay = 100000000 + startup_delay = "100ms" ``` ## BUGS @@ -127,4 +142,4 @@ ## SEE ALSO -ctr(1), containerd-config(1), containerd(1) +ctr(8), containerd-config(8), containerd(8) diff -Nru containerd-1.2.6/docs/man/ctr.1.md containerd-1.5.9/docs/man/ctr.1.md --- containerd-1.2.6/docs/man/ctr.1.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/man/ctr.1.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -# ctr 1 01/30/2018 - -## SYNOPSIS - -**ctr [global options] command [command options] [arguments...]** - -## DESCRIPTION - -**ctr** is an unsupported debug and administrative client for interacting -with the containerd daemon. Because it is unsupported, the commands, -options, and operation are not guaranteed to be backward compatible or -stable from release to release of the containerd project. - -## OPTIONS - -The following commands are available in the **ctr** utility: - -**plugins,plugin** -: Provides information about containerd plugins - -**version** -: Prints the client and server versions - -**containers,c,container** -: Manages and interacts with containers - -**content** -: Manages and interacts with content - -**events,event** -: Displays containerd events - -**images,image** -: Manages and interacts with images - -**namespaces,namespace** -: Manages and interacts with containerd namespaces - -**pprof** -: Provides golang pprof outputs for containerd - -**run** -: Runs a container - -**snapshots,snapshot** -: Manages and interacts with snapshots - -**tasks,t,task** -: Manages and interacts with tasks - -**shim** -: Interacts with a containerd shim directly - -**help,h** -: Displays a list of commands or help for one specific command - -The following global options apply to all **ctr** commands: - -**--debug** -: Enable debug output in logs - -**--address value, -a value** -: Address for containerd's GRPC server (default: */run/containerd/containerd.sock*) - -**--timeout value** -: Total timeout for ctr commands (default: *0s*) - -**--connect-timeout value** -: Timeout for connecting to containerd (default: *0s*) - -**--namespace value, -n value** -: Namespace to use with commands (default: *default*) [also read from *$CONTAINERD_NAMESPACE*] - -**--help, -h** -: Show help text - -**--version, -v** -: Prints the **ctr** version - -## BUGS - -Note that the **ctr** utility is not an officially supported part of the -containerd project releases. - -However, please feel free to file any specific issues that you encounter at -https://github.com/containerd/containerd. - -## AUTHOR - -Phil Estes - -## SEE ALSO - -containerd(1), containerd-config(1), containerd-config.toml(5) diff -Nru containerd-1.2.6/docs/managed-opt.md containerd-1.5.9/docs/managed-opt.md --- containerd-1.2.6/docs/managed-opt.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/managed-opt.md 2022-01-05 17:30:58.000000000 +0000 @@ -91,3 +91,15 @@ 1:M 01 Aug 15:59:53.484 * DB saved on disk 1:M 01 Aug 15:59:53.484 # Redis is now ready to exit, bye bye... ``` +For Windows: + +```Dockerfile +FROM mcr.microsoft.com/windows/nanoserver:1809 +ADD runhcs.exe /bin/runhcs.exe +``` + +```powershell +> ctr content fetch docker.io/ameyagawde/runhcs:1809 #An example image, not supported by containerd +> ctr install docker.io/ameyagawde/runhcs:1809 +``` +The Windows equivalent for `/opt/containerd` will be `$env:ProgramData\containerd\root\opt` \ No newline at end of file diff -Nru containerd-1.2.6/docs/namespaces.md containerd-1.5.9/docs/namespaces.md --- containerd-1.2.6/docs/namespaces.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/namespaces.md 2022-01-05 17:30:58.000000000 +0000 @@ -34,9 +34,7 @@ Simply create a new `context` and set your application's namespace on the `context`. Make sure to use a unique namespace for applications that does not conflict with existing namespaces. The namespaces -API, or the `ctr namespaces` client command, can be used to query/list and create new namespaces. Note that namespaces -can have a list of labels associated with the namespace. This can be useful for associating metadata with a particular -namespace. +API, or the `ctr namespaces` client command, can be used to query/list and create new namespaces. ```go ctx := context.Background() @@ -49,11 +47,24 @@ ) ``` +## Namespace Labels + +Namespaces can have a list of labels associated with the namespace. This can be useful for associating metadata with a particular namespace. +Labels can also be used to configure the defaults for containerd, for example: + +```bash +> sudo ctr namespaces label k8s.io containerd.io/defaults/snapshotter=btrfs +> sudo ctr namespaces label k8s.io containerd.io/defaults/runtime=testRuntime +``` + +This will set the default snapshotter as `btrfs` and runtime as `testRuntime`. +Note that currently only these two labels are used to configure the defaults and labels of `default` namespace are not considered for the same. + ## Inspecting Namespaces If we need to inspect containers, images, or other resources in various namespaces the `ctr` tool allows you to do this. Simply set the `--namespace,-n` flag on `ctr` to change the namespace. If you do not provide a namespace, `ctr` client commands -will all use the the default namespace, which is simply named "`default`". +will all use the default namespace, which is simply named "`default`". ```bash > sudo ctr -n docker tasks diff -Nru containerd-1.2.6/docs/ops.md containerd-1.5.9/docs/ops.md --- containerd-1.2.6/docs/ops.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/docs/ops.md 2022-01-05 17:30:58.000000000 +0000 @@ -79,12 +79,9 @@ In the containerd config file you will find settings for persistent and runtime storage locations as well as grpc, debug, and metrics addresses for the various APIs. There are a few settings that are important for ops. -The first setting is the `oom_score`. Because containerd will be managing multiple containers, we need to ensure that containers are killed before the containerd daemon in an out of memory condition. +The first setting is the `oom_score`. Because containerd will be managing multiple containers, we need to ensure that containers are killed before the containerd daemon gets into an out of memory condition. We also do not want to make containerd unkillable, but we want to lower its score to the level of other system daemons. -The `subreaper` setting is also important on linux systems. -This allows containerd to reap any re-parented processes from the shims or containers. - containerd also exports its own metrics as well as container level metrics via the prometheus metrics format. Currently, prometheus only supports TCP endpoints, therefore, the metrics address should be a TCP address that your prometheus infrastructure can scrape metrics from. @@ -161,8 +158,6 @@ root = "/var/lib/containerd" # runtime state information state = "/run/containerd" -# set containerd as a subreaper on linux when it is not running as PID 1 -subreaper = true # set containerd's OOM score oom_score = -999 @@ -201,6 +196,8 @@ In the config file you can specify plugin level options for the set of plugins that you use via the `[plugins.]` sections. You will have to read the plugin specific docs to find the options that your plugin accepts. +See [containerd's Plugin documentation](./PLUGINS.md) + ### Linux Runtime Plugin The linux runtime allows a few options to be set to configure the shim and the runtime that you are using. @@ -216,7 +213,22 @@ no_shim = false # display shim logs in the containerd daemon's log output shim_debug = true - # do not put the shim in its own mount namespace - # (this only need to be set on kernel < 3.18) - shim_no_newns = true +``` + +### Bolt Metadata Plugin + +The bolt metadata plugin allows configuration of the content sharing policy between namespaces. + +The default mode "shared" will make blobs available in all namespaces once it is pulled into any namespace. +The blob will be pulled into the namespace if a writer is opened with the "Expected" digest that is already present in the backend. + +The alternative mode, "isolated" requires that clients prove they have access to the content by providing all of the content to the ingest before the blob is added to the namespace. + +Both modes share backing data, while "shared" will reduce total bandwidth across namespaces, at the cost of allowing access to any blob just by knowing its digest. + +The default is "shared". While this is largely the most desired policy, one can change to "isolated" mode with the following configuration: + +```toml +[plugins.bolt] + content_sharing_policy = "isolated" ``` diff -Nru containerd-1.2.6/docs/PLUGINS.md containerd-1.5.9/docs/PLUGINS.md --- containerd-1.2.6/docs/PLUGINS.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/PLUGINS.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,267 @@ +# containerd Plugins + +containerd supports extending its functionality using most of its defined +interfaces. This includes using a customized runtime, snapshotter, content +store, and even adding gRPC interfaces. + +## Smart Client Model + +containerd has a smart client architecture, meaning any functionality which is +not required by the daemon is done by the client. This includes most high +level interactions such as creating a container's specification, interacting +with an image registry, or loading an image from tar. containerd's Go client +gives a user access to many points of extensions from creating their own +options on container creation to resolving image registry names. + +See [containerd's Go documentation](https://godoc.org/github.com/containerd/containerd) + +## External Plugins + +External plugins allow extending containerd's functionality using an officially +released version of containerd without needing to recompile the daemon to add a +plugin. + +containerd allows extensions through two methods: + - via a binary available in containerd's PATH + - by configuring containerd to proxy to another gRPC service + +### V2 Runtimes + +The runtime v2 interface allows resolving runtimes to binaries on the system. +These binaries are used to start the shim process for containerd and allows +containerd to manage those containers using the runtime shim api returned by +the binary. + +See [runtime v2 documentation](../runtime/v2/README.md) + +### Proxy Plugins + +A proxy plugin is configured using containerd's config file and will be loaded +alongside the internal plugins when containerd is started. These plugins are +connected to containerd using a local socket serving one of containerd's gRPC +API services. Each plugin is configured with a type and name just as internal +plugins are. + +#### Configuration + +Update the containerd config file, which by default is at +`/etc/containerd/config.toml`. Add a `[proxy_plugins]` section along with a +section for your given plugin `[proxy_plugins.myplugin]`. The `address` must +refer to a local socket file which the containerd process has access to. The +currently supported types are `snapshot` and `content`. + +``` +[proxy_plugins] + [proxy_plugins.customsnapshot] + type = "snapshot" + address = "/var/run/mysnapshotter.sock" +``` + +#### Implementation + +Implementing a proxy plugin is as easy as implementing the gRPC API for a +service. For implementing a proxy plugin in Go, look at the go doc for +[content store service](https://godoc.org/github.com/containerd/containerd/api/services/content/v1#ContentServer) +and [snapshotter service](https://godoc.org/github.com/containerd/containerd/api/services/snapshots/v1#SnapshotsServer). + +The following example creates a snapshot plugin binary which can be used +with any implementation of +[containerd's Snapshotter interface](https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter) +```go +package main + +import ( + "fmt" + "net" + "os" + + "google.golang.org/grpc" + + snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" + "github.com/containerd/containerd/contrib/snapshotservice" + "github.com/containerd/containerd/snapshots/native" +) + +func main() { + // Provide a unix address to listen to, this will be the `address` + // in the `proxy_plugin` configuration. + // The root will be used to store the snapshots. + if len(os.Args) < 3 { + fmt.Printf("invalid args: usage: %s \n", os.Args[0]) + os.Exit(1) + } + + // Create a gRPC server + rpc := grpc.NewServer() + + // Configure your custom snapshotter, this example uses the native + // snapshotter and a root directory. Your custom snapshotter will be + // much more useful than using a snapshotter which is already included. + // https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter + sn, err := native.NewSnapshotter(os.Args[2]) + if err != nil { + fmt.Printf("error: %v\n", err) + os.Exit(1) + } + + // Convert the snapshotter to a gRPC service, + // example in github.com/containerd/containerd/contrib/snapshotservice + service := snapshotservice.FromSnapshotter(sn) + + // Register the service with the gRPC server + snapshotsapi.RegisterSnapshotsServer(rpc, service) + + // Listen and serve + l, err := net.Listen("unix", os.Args[1]) + if err != nil { + fmt.Printf("error: %v\n", err) + os.Exit(1) + } + if err := rpc.Serve(l); err != nil { + fmt.Printf("error: %v\n", err) + os.Exit(1) + } +} +``` + +Using the previous configuration and example, you could run a snapshot plugin +with +``` +# Start plugin in one terminal +$ go run ./main.go /var/run/mysnapshotter.sock /tmp/snapshots + +# Use ctr in another +$ CONTAINERD_SNAPSHOTTER=customsnapshot ctr images pull docker.io/library/alpine:latest +$ tree -L 3 /tmp/snapshots +/tmp/snapshots +|-- metadata.db +`-- snapshots + `-- 1 + |-- bin + |-- dev + |-- etc + |-- home + |-- lib + |-- media + |-- mnt + |-- proc + |-- root + |-- run + |-- sbin + |-- srv + |-- sys + |-- tmp + |-- usr + `-- var + +18 directories, 1 file +``` + +## Built-in Plugins + +containerd uses plugins internally to ensure that internal implementations are +decoupled, stable, and treated equally with external plugins. To see all the +plugins containerd has, use `ctr plugins ls` + +``` +$ ctr plugins ls +TYPE ID PLATFORMS STATUS +io.containerd.content.v1 content - ok +io.containerd.snapshotter.v1 btrfs linux/amd64 ok +io.containerd.snapshotter.v1 aufs linux/amd64 error +io.containerd.snapshotter.v1 native linux/amd64 ok +io.containerd.snapshotter.v1 overlayfs linux/amd64 ok +io.containerd.snapshotter.v1 zfs linux/amd64 error +io.containerd.metadata.v1 bolt - ok +io.containerd.differ.v1 walking linux/amd64 ok +io.containerd.gc.v1 scheduler - ok +io.containerd.service.v1 containers-service - ok +io.containerd.service.v1 content-service - ok +io.containerd.service.v1 diff-service - ok +io.containerd.service.v1 images-service - ok +io.containerd.service.v1 leases-service - ok +io.containerd.service.v1 namespaces-service - ok +io.containerd.service.v1 snapshots-service - ok +io.containerd.runtime.v1 linux linux/amd64 ok +io.containerd.runtime.v2 task linux/amd64 ok +io.containerd.monitor.v1 cgroups linux/amd64 ok +io.containerd.service.v1 tasks-service - ok +io.containerd.internal.v1 restart - ok +io.containerd.grpc.v1 containers - ok +io.containerd.grpc.v1 content - ok +io.containerd.grpc.v1 diff - ok +io.containerd.grpc.v1 events - ok +io.containerd.grpc.v1 healthcheck - ok +io.containerd.grpc.v1 images - ok +io.containerd.grpc.v1 leases - ok +io.containerd.grpc.v1 namespaces - ok +io.containerd.grpc.v1 snapshots - ok +io.containerd.grpc.v1 tasks - ok +io.containerd.grpc.v1 version - ok +io.containerd.grpc.v1 cri linux/amd64 ok +``` + +From the output all the plugins can be seen as well those which did not +successfully load. In this case `aufs` and `zfs` are expected not to load +since they are not support on the machine. The logs will show why it failed, +but you can also get more details using the `-d` option. + +``` +$ ctr plugins ls -d id==aufs id==zfs +Type: io.containerd.snapshotter.v1 +ID: aufs +Platforms: linux/amd64 +Exports: + root /var/lib/containerd/io.containerd.snapshotter.v1.aufs +Error: + Code: Unknown + Message: modprobe aufs failed: "modprobe: FATAL: Module aufs not found in directory /lib/modules/4.17.2-1-ARCH\n": exit status 1 + +Type: io.containerd.snapshotter.v1 +ID: zfs +Platforms: linux/amd64 +Exports: + root /var/lib/containerd/io.containerd.snapshotter.v1.zfs +Error: + Code: Unknown + Message: path /var/lib/containerd/io.containerd.snapshotter.v1.zfs must be a zfs filesystem to be used with the zfs snapshotter +``` + +The error message which the plugin returned explains why the plugin was unable +to load. + +#### Configuration + +Plugins are configured using the `[plugins]` section of containerd's config. +Every plugin can have its own section using the pattern `[plugins.]`. + +example configuration +``` +[plugins] + [plugins.cgroups] + no_prometheus = false + [plugins.cri] + stream_server_address = "" + stream_server_port = "10010" + enable_selinux = false + sandbox_image = "k8s.gcr.io/pause:3.5" + stats_collect_period = 10 + systemd_cgroup = false + [plugins.cri.containerd] + snapshotter = "overlayfs" + [plugins.cri.containerd.default_runtime] + runtime_type = "io.containerd.runtime.v1.linux" + runtime_engine = "" + runtime_root = "" + [plugins.cri.containerd.untrusted_workload_runtime] + runtime_type = "" + runtime_engine = "" + runtime_root = "" + [plugins.cri.cni] + bin_dir = "/opt/cni/bin" + conf_dir = "/etc/cni/net.d" + [plugins.cri.registry] + [plugins.cri.registry.mirrors] + [plugins.cri.registry.mirrors."docker.io"] + endpoint = ["https://registry-1.docker.io"] +``` diff -Nru containerd-1.2.6/docs/remote-snapshotter.md containerd-1.5.9/docs/remote-snapshotter.md --- containerd-1.2.6/docs/remote-snapshotter.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/remote-snapshotter.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,129 @@ +# Remote Snapshotter + +Containerd allows snapshotters to reuse snapshots existing somewhere managed by them. + +_Remote Snapshotter_ is a snapshotter that leverages this functionality and reuses snapshots that are stored in a remotely shared place. +These remotely shared snapshots are called _remote snapshots_. +Remote snapshotter allows containerd to prepare these remote snapshots without pulling layers from registries, which hopefully shorten the time to take for image pull. + +One of the remote snapshotter implementations is [Stargz Snapshotter](https://github.com/containerd/stargz-snapshotter). +This enables containerd to lazily pull images from standard-compliant registries leveraging remote snapshotter functionality and stargz images by google/crfs. + +## The containerd client API + +The containerd client's `Pull` API with unpacking-mode allows the underlying snapshotter to query for remote snapshots before fetching content. +Remote snapshotter needs to be plugged into containerd in [the same ways as normal snapshotters](/docs/PLUGINS.md). + +```go +image, err := client.Pull(ctx, ref, + containerd.WithPullUnpack, + containerd.WithPullSnapshotter("my-remote-snapshotter"), +) +``` + +## Passing snapshotter-specific information + +Some remote snapshotters requires snapshotter-specific information through `Pull` API. +The information will be used in various ways including searching snapshot contents from a remote store. +One of the example snapshotters that requires snapshotter-specific information is stargz snapshotter. +It requires the image reference name and layer digests, etc. for searching layer contents from registries. + +Snapshotters receive the information through user-defined labels prefixed by `containerd.io/snapshot/`. +The containerd client supports two ways to pass these labels to the underlying snapshotter. + +### Using snapshotter's `WithLabels` option + +User-defined labels can be passed down to the underlying snapshotter using snapshotter option `WithLabels`. +Specified labels will be passed down every time the containerd client queries a remote snapshot. +This is useful if the values of these labels are determined statically regardless of the snapshots. +These user-defined labels must be prefixed by `containerd.io/snapshot/`. + +```go +import "github.com/containerd/containerd/snapshots" + +image, err := client.Pull(ctx, ref, + containerd.WithPullUnpack, + containerd.WithPullSnapshotter( + "my-remote-snapshotter", + snapshots.WithLabels(map[string]string{ + "containerd.io/snapshot/reference": ref, + }), + ), +) +``` + +### Using the containerd client's `WithImageHandlerWrapper` option + +User-defined labels can also be passed using an image handler wrapper. +This is useful when labels vary depending on the snapshot. + +Every time the containerd client queries remote snapshot, it passes `Annotations` appended to the targeting layer descriptor (means the layer descriptor that will be pulled and unpacked for preparing that snapshot) to the underlying snapshotter. +These annotations are passed to the snapshotter as user-defined labels. +The values of annotations can be dynamically added and modified in the handler wrapper. +Note that annotations must be prefixed by `containerd.io/snapshot/`. +[CRI plugin](https://github.com/containerd/cri/blob/09d6426f33cac217528158ddc6d254ca7d597a7b/pkg/server/image_pull.go#L127) and [stargz snapshotter](https://github.com/containerd/stargz-snapshotter/blob/875ec333403a885f5b6e5b64c94ec4dc713e0596/cmd/ctr-remote/commands/rpull.go#L97) leverage this method. + +```go +import "github.com/ktock/snapshotter/handler" + +if _, err := client.Pull(ctx, ref, + containerd.WithPullUnpack, + containerd.WithPullSnapshotter("my-remote-snapshotter"), + containerd.WithImageHandlerWrapper(handler.Wrapper(ref)), +) +``` + +## Snapshotter APIs for querying remote snapshots + +The containerd client queries remote snapshots to the underlying remote snapshotter using snapshotter APIs. +This section describes the high-level overview of how snapshotter APIs are used for remote snapshots functionality, with some piece of pseudo-codes that describe the simplified logic implemented in the containerd client. +For more details, see [`unpacker.go`](/unpacker.go) that implements this logic. + +During image pull, the containerd client calls `Prepare` API with the label `containerd.io/snapshot.ref`. +This is a containerd-defined label which contains ChainID that targets a committed snapshot that the client is trying to prepare. +At this moment, user-defined labels (prefixed by `containerd.io/snapshot/`) will also be merged into the labels option. + +```go +// Gets annotations appended to the targeting layer which would contain +// snapshotter-specific information passed by the user. +labels := snapshots.FilterInheritedLabels(desc.Annotations) +if labels == nil { + labels = make(map[string]string) +} + +// Specifies ChainID of the targeting committed snapshot. +labels["containerd.io/snapshot.ref"] = chainID + +// Merges snapshotter options specified by the user which would contain +// snapshotter-specific information passed by the user. +opts := append(rCtx.SnapshotterOpts, snapshots.WithLabels(labels)) + +// Calls `Prepare` API with target identifier and snapshotter-specific +// information. +mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) +``` + +If this snapshotter is a remote snapshotter, that committed snapshot hopefully exists, for example, in a shared remote store. +Remote snapshotter must define and enforce policies about whether it will use an existing snapshot. +When remote snapshotter allows the user to use that snapshot, it must return `ErrAlreadyExists`. + +If the containerd client gets `ErrAlreadyExists` by `Prepare`, it ensures the existence of that committed snapshot by calling `Stat` with the ChainID. +If this snapshot is available, the containerd client skips pulling and unpacking layer that would otherwise be needed for preparing and committing that snapshot. + +```go +mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) +if err != nil { + if errdefs.IsAlreadyExists(err) { + // Ensures the layer existence + if _, err := sn.Stat(ctx, chainID); err != nil { + // Handling error + } else { + // snapshot found with ChainID + // pulling/unpacking will be skipped + continue + } + } else { + return err + } +} +``` diff -Nru containerd-1.2.6/docs/rootless.md containerd-1.5.9/docs/rootless.md --- containerd-1.2.6/docs/rootless.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/rootless.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,72 @@ +# Running containerd as a non-root user + +A non-root user can execute containerd by using [`user_namespaces(7)`](http://man7.org/linux/man-pages/man7/user_namespaces.7.html). + +For example [RootlessKit](https://github.com/rootless-containers/rootlesskit) can be used for setting up a user namespace (along with mount namespace and optionally network namespace). Please refer to RootlessKit documentation for further information. + +See also https://rootlesscontaine.rs/ . + +## "Easy way" + +The easiest way is to use `containerd-rootless-setuptool.sh` included in [containerd/nerdctl](https://github.com/containerd/nerdctl). + +```console +$ containerd-rootless-setuptool.sh install +$ nerdctl run -d --restart=always --name nginx -p 8080:80 nginx:alpine +``` + +See https://github.com/containerd/nerdctl/blob/master/docs/rootless.md for the further information. + +## "Hard way" + +
+Click here to show the "hard way" + +

+ +### Daemon + +```console +$ rootlesskit --net=slirp4netns --copy-up=/etc --copy-up=/run \ + --state-dir=/run/user/1001/rootlesskit-containerd \ + sh -c "rm -f /run/containerd; exec containerd -c config.toml" +``` + +* `--net=slirp4netns --copy-up=/etc` is only required when you want to unshare network namespaces. + See [RootlessKit documentation](https://github.com/rootless-containers/rootlesskit/blob/v0.14.1/docs/network.md) for the further information about the network drivers. +* `--copy-up=/DIR` mounts a writable tmpfs on `/DIR` with symbolic links to the files under the `/DIR` on the parent namespace + so that the user can add/remove files under `/DIR` in the mount namespace. + `--copy-up=/etc` and `--copy-up=/run` are needed on typical setup. + Depending on the containerd plugin configuration, you may also need to add more `--copy-up` options. +* `rm -f /run/containerd` removes the "copied-up" symbolic link to `/run/containerd` on the parent namespace (if exists), which cannot be accessed by non-root users. + The actual `/run/containerd` directory on the host is not affected. +* `--state-dir` is set to a random directory under `/tmp` if unset. RootlessKit writes the PID to a file named `child_pid` under this directory. +* You need to provide `config.toml` with your own path configuration. e.g. +```toml +version = 2 +root = "/home/penguin/.local/share/containerd" +state = "/run/user/1001/containerd" + +[grpc] + address = "/run/user/1001/containerd/containerd.sock" +``` + +### Client + +A client program such as `ctr` also needs to be executed inside the daemon namespaces. +```console +$ nsenter -U --preserve-credentials -m -n -t $(cat /run/user/1001/rootlesskit-containerd/child_pid) +$ export CONTAINERD_ADDRESS=/run/user/1001/containerd/containerd.sock +$ export CONTAINERD_SNAPSHOTTER=native +$ ctr images pull docker.io/library/ubuntu:latest +$ ctr run -t --rm --fifo-dir /tmp/foo-fifo --cgroup "" docker.io/library/ubuntu:latest foo +``` + +* The `overlayfs` snapshotter does not work inside user namespaces before kernel 5.11, except on Ubuntu and Debian kernels. + However, [`fuse-overlayfs` snapshotter](https://github.com/containerd/fuse-overlayfs-snapshotter) can be used instead if running kernel >= 4.18. +* Enabling cgroup requires cgroup v2 and systemd, e.g. `ctr run --cgroup "user.slice:foo:bar" --runc-systemd-cgroup ...` . + See also [runc documentation](https://github.com/opencontainers/runc/blob/v1.0.0-rc93/docs/cgroup-v2.md). + + +

+
diff -Nru containerd-1.2.6/docs/RUNC.md containerd-1.5.9/docs/RUNC.md --- containerd-1.2.6/docs/RUNC.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/RUNC.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +containerd is built with OCI support and with support for advanced features +provided by [runc](https://github.com/opencontainers/runc). + +Development (`-dev`) and pre-releases of containerd may depend features in `runc` +that have not yet been released, and may require a specific runc build. The version +of runc that is tested against in our CI can be found in the [`script/setup/runc-version`](../script/setup/runc-version) +file, which may point to a git-commit (for pre releases) or tag in the runc +repository. + +For regular (non-pre-)releases of containerd releases, we attempt to use released +(tagged) versions of runc. We recommend using a version of runc that's equal to +or higher than the version of runc described in [`script/setup/runc-version`](../script/setup/runc-version). + +If you encounter any runtime errors, make sure your runc is in sync with the +commit or tag provided in that file. + +## building + +> For more information on how to clone and build runc also refer to the runc +> building [documentation](https://github.com/opencontainers/runc#building). + +Before building runc you may need to install additional build dependencies, which +will vary by platform. For example, you may need to install `libseccomp` e.g. +`libseccomp-dev` for Ubuntu. + +From within your `opencontainers/runc` repository run: + +```bash +make && sudo make install +``` + +Starting with runc 1.0.0-rc93, the "selinux" and "apparmor" buildtags have been +removed, and runc builds have SELinux, AppArmor, and seccomp support enabled +by default. Note that "seccomp" can be disabled by passing an empty `BUILDTAGS` +make variable, but is highly recommended to keep enabled. + +By default, runc is compiled with kernel-memory limiting support enabled. This +functionality is deprecated in kernel 5.4 and up, and is known to be broken on +RHEL7 and CentOS 7 3.10 kernels. For these kernels, we recommend disabling kmem +support using the `nokmem` build-tag. When doing so, be sure to set the `seccomp` +build-tag to enable seccomp support, for example: + +```sh +make BUILDTAGS='nokmem seccomp' && make install +``` + +For details about the `nokmem` build-tag, refer to the discussion on [opencontainers/runc#2594](https://github.com/opencontainers/runc/pull/2594). +For further details on building runc, refer to the [build instructions in the runc README](https://github.com/opencontainers/runc#building). Binary files /tmp/tmp4z7_tba8/FAzrZmqiYm/containerd-1.2.6/docs/SECURITY_AUDIT.pdf and /tmp/tmp4z7_tba8/Bfxrm9w9fP/containerd-1.5.9/docs/SECURITY_AUDIT.pdf differ diff -Nru containerd-1.2.6/docs/stream_processors.md containerd-1.5.9/docs/stream_processors.md --- containerd-1.2.6/docs/stream_processors.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/docs/stream_processors.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +# Stream Processors + +## Processor API + +Processors are a binary API that works off of content streams. + +The incoming content stream will be provided to the binary via `STDIN` +and the stream processor is expected to output the processed stream on +`STDOUT`. If errors are encountered, errors MUST be returned via `STDERR` +with a non-zero exit status. + +Additional information can be provided to stream processors via a payload. +Payloads are marshaled as `protobuf.Any` types and can wrap any type of +serialized data structure. + +On Unix systems, the payload, if available, is provided on `fd 3` for the process. + +On Windows systems, the payload, if available, is provided via a named pipe with the +pipe's path set as the value of the environment variable `STREAM_PROCESSOR_PIPE`. + +## Configuration + +To configure stream processors for containerd, entries in the config file need to be made. +The `stream_processors` field is a map so that users can chain together multiple processors +to mutate content streams. + +Processor Fields: + +* Key - ID of the processor, used for passing a specific payload to the processor. +* `accepts` - Accepted media-types for the processor that it can handle. +* `returns` - The media-type that the processor returns. +* `path` - Path to the processor binary. +* `args` - Arguments passed to the processor binary. + +```toml +[stream_processors] + [stream_processors."io.containerd.processor.v1.pigz"] + accepts = ["application/vnd.docker.image.rootfs.diff.tar.gzip"] + returns = "application/vnd.oci.image.layer.v1.tar" + path = "unpigz" + args = ["-d", "-c"] +``` diff -Nru containerd-1.2.6/.empty-mod/go.mod containerd-1.5.9/.empty-mod/go.mod --- containerd-1.2.6/.empty-mod/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.empty-mod/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +// module empty-mod is an empty module that's used to help with containerd +// having a circular dependency on itself through plugin modules. +// +// We use this module as a "replace" rule in containerd's go.mod, to prevent +// relying on transitive dependencies (coming from older versions of containerd +// defined on plugin go.mod). +// +// The replace rule forces go modules to consider the "current" version of +// containerd to be the source of truth, helping us catch missing go.mod rules, +// or version changes early. +module empty-mod diff -Nru containerd-1.2.6/errdefs/errors.go containerd-1.5.9/errdefs/errors.go --- containerd-1.2.6/errdefs/errors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/errdefs/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,7 +26,11 @@ // client-side errors to the correct types. package errdefs -import "github.com/pkg/errors" +import ( + "context" + + "github.com/pkg/errors" +) // Definitions of common error types used throughout containerd. All containerd // errors returned by most packages will map into one of these errors classes. @@ -47,32 +51,43 @@ // IsInvalidArgument returns true if the error is due to an invalid argument func IsInvalidArgument(err error) bool { - return errors.Cause(err) == ErrInvalidArgument + return errors.Is(err, ErrInvalidArgument) } // IsNotFound returns true if the error is due to a missing object func IsNotFound(err error) bool { - return errors.Cause(err) == ErrNotFound + return errors.Is(err, ErrNotFound) } // IsAlreadyExists returns true if the error is due to an already existing // metadata item func IsAlreadyExists(err error) bool { - return errors.Cause(err) == ErrAlreadyExists + return errors.Is(err, ErrAlreadyExists) } // IsFailedPrecondition returns true if an operation could not proceed to the // lack of a particular condition func IsFailedPrecondition(err error) bool { - return errors.Cause(err) == ErrFailedPrecondition + return errors.Is(err, ErrFailedPrecondition) } // IsUnavailable returns true if the error is due to a resource being unavailable func IsUnavailable(err error) bool { - return errors.Cause(err) == ErrUnavailable + return errors.Is(err, ErrUnavailable) } // IsNotImplemented returns true if the error is due to not being implemented func IsNotImplemented(err error) bool { - return errors.Cause(err) == ErrNotImplemented + return errors.Is(err, ErrNotImplemented) +} + +// IsCanceled returns true if the error is due to `context.Canceled`. +func IsCanceled(err error) bool { + return errors.Is(err, context.Canceled) +} + +// IsDeadlineExceeded returns true if the error is due to +// `context.DeadlineExceeded`. +func IsDeadlineExceeded(err error) bool { + return errors.Is(err, context.DeadlineExceeded) } diff -Nru containerd-1.2.6/errdefs/grpc.go containerd-1.5.9/errdefs/grpc.go --- containerd-1.2.6/errdefs/grpc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/errdefs/grpc.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package errdefs import ( + "context" "strings" "github.com/pkg/errors" @@ -55,6 +56,10 @@ return status.Errorf(codes.Unavailable, err.Error()) case IsNotImplemented(err): return status.Errorf(codes.Unimplemented, err.Error()) + case IsCanceled(err): + return status.Errorf(codes.Canceled, err.Error()) + case IsDeadlineExceeded(err): + return status.Errorf(codes.DeadlineExceeded, err.Error()) } return err @@ -89,13 +94,17 @@ cls = ErrFailedPrecondition case codes.Unimplemented: cls = ErrNotImplemented + case codes.Canceled: + cls = context.Canceled + case codes.DeadlineExceeded: + cls = context.DeadlineExceeded default: cls = ErrUnknown } msg := rebaseMessage(cls, err) if msg != "" { - err = errors.Wrapf(cls, msg) + err = errors.Wrap(cls, msg) } else { err = errors.WithStack(cls) } diff -Nru containerd-1.2.6/errdefs/grpc_test.go containerd-1.5.9/errdefs/grpc_test.go --- containerd-1.2.6/errdefs/grpc_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/errdefs/grpc_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package errdefs import ( + "context" "testing" "google.golang.org/grpc/codes" @@ -56,6 +57,26 @@ cause: ErrUnknown, str: errShouldLeaveAlone.Error() + ": " + ErrUnknown.Error(), }, + { + input: context.Canceled, + cause: context.Canceled, + str: "context canceled", + }, + { + input: errors.Wrapf(context.Canceled, "this is a test cancel"), + cause: context.Canceled, + str: "this is a test cancel: context canceled", + }, + { + input: context.DeadlineExceeded, + cause: context.DeadlineExceeded, + str: "context deadline exceeded", + }, + { + input: errors.Wrapf(context.DeadlineExceeded, "this is a test deadline exceeded"), + cause: context.DeadlineExceeded, + str: "this is a test deadline exceeded: context deadline exceeded", + }, } { t.Run(testcase.input.Error(), func(t *testing.T) { t.Logf("input: %v", testcase.input) @@ -67,6 +88,9 @@ if errors.Cause(ferr) != testcase.cause { t.Fatalf("unexpected cause: %v != %v", errors.Cause(ferr), testcase.cause) } + if !errors.Is(ferr, testcase.cause) { + t.Fatalf("unexpected cause: !errors.Is(%v, %v)", ferr, testcase.cause) + } expected := testcase.str if expected == "" { diff -Nru containerd-1.2.6/events/exchange/exchange.go containerd-1.5.9/events/exchange/exchange.go --- containerd-1.2.6/events/exchange/exchange.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/events/exchange/exchange.go 2022-01-05 17:30:58.000000000 +0000 @@ -50,7 +50,7 @@ var _ events.Forwarder = &Exchange{} var _ events.Subscriber = &Exchange{} -// Forward accepts an envelope to be direcly distributed on the exchange. +// Forward accepts an envelope to be directly distributed on the exchange. // // This is useful when an event is forwarded on behalf of another namespace or // when the event is propagated on behalf of another publisher. @@ -138,10 +138,10 @@ ) closeAll := func() { - defer close(errq) - defer e.broadcaster.Remove(dst) - defer queue.Close() - defer channel.Close() + channel.Close() + queue.Close() + e.broadcaster.Remove(dst) + close(errq) } ch = evch @@ -225,7 +225,7 @@ } func validateEnvelope(envelope *events.Envelope) error { - if err := namespaces.Validate(envelope.Namespace); err != nil { + if err := identifiers.Validate(envelope.Namespace); err != nil { return errors.Wrapf(err, "event envelope has invalid namespace") } diff -Nru containerd-1.2.6/events/exchange/exchange_test.go containerd-1.5.9/events/exchange/exchange_test.go --- containerd-1.2.6/events/exchange/exchange_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/events/exchange/exchange_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,6 @@ import ( "context" "reflect" - "sync" "testing" "time" @@ -52,11 +51,8 @@ eventq2, errq2 := exchange.Subscribe(ctx2) t.Log("publish") - var wg sync.WaitGroup - wg.Add(1) errChan := make(chan error) go func() { - defer wg.Done() defer close(errChan) for _, event := range testevents { if err := exchange.Publish(ctx, "/test", event); err != nil { @@ -69,7 +65,6 @@ }() t.Log("waiting") - wg.Wait() if err := <-errChan; err != nil { t.Fatal(err) } @@ -225,11 +220,8 @@ } t.Log("publish") - var wg sync.WaitGroup - wg.Add(1) errChan := make(chan error) go func() { - defer wg.Done() defer close(errChan) for _, es := range testEventSets { for _, e := range es.events { @@ -244,7 +236,6 @@ }() t.Log("waiting") - wg.Wait() if err := <-errChan; err != nil { t.Fatal(err) } @@ -300,7 +291,7 @@ } { t.Run(testcase.input, func(t *testing.T) { event := &eventstypes.ContainerCreate{ID: t.Name()} - if err := exchange.Publish(ctx, testcase.input, event); errors.Cause(err) != testcase.err { + if err := exchange.Publish(ctx, testcase.input, event); !errors.Is(err, testcase.err) { if err == nil { t.Fatalf("expected error %v, received nil", testcase.err) } else { @@ -321,7 +312,7 @@ } // make sure we get same errors with forward. - if err := exchange.Forward(ctx, &envelope); errors.Cause(err) != testcase.err { + if err := exchange.Forward(ctx, &envelope); !errors.Is(err, testcase.err) { if err == nil { t.Fatalf("expected error %v, received nil", testcase.err) } else { diff -Nru containerd-1.2.6/export.go containerd-1.5.9/export.go --- containerd-1.2.6/export.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/export.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,39 +20,12 @@ "context" "io" - "github.com/containerd/containerd/images" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" + "github.com/containerd/containerd/images/archive" ) -type exportOpts struct { -} - -// ExportOpt allows the caller to specify export-specific options -type ExportOpt func(c *exportOpts) error - -func resolveExportOpt(opts ...ExportOpt) (exportOpts, error) { - var eopts exportOpts - for _, o := range opts { - if err := o(&eopts); err != nil { - return eopts, err - } - } - return eopts, nil -} - -// Export exports an image to a Tar stream. -// OCI format is used by default. -// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc. -// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream. -func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) { - _, err := resolveExportOpt(opts...) // unused now - if err != nil { - return nil, err - } - pr, pw := io.Pipe() - go func() { - pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed")) - }() - return pr, nil +// Export exports images to a Tar stream. +// The tar archive is in OCI format with a Docker compatible manifest +// when a single target platform is given. +func (c *Client) Export(ctx context.Context, w io.Writer, opts ...archive.ExportOpt) error { + return archive.Export(ctx, c.ContentStore(), w, opts...) } diff -Nru containerd-1.2.6/export_test.go containerd-1.5.9/export_test.go --- containerd-1.2.6/export_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/export_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "archive/tar" - "io" - "runtime" - "testing" - - "github.com/containerd/containerd/images/oci" -) - -// TestOCIExport exports testImage as a tar stream -func TestOCIExport(t *testing.T) { - // TODO: support windows - if testing.Short() || runtime.GOOS == "windows" { - t.Skip() - } - ctx, cancel := testContext() - defer cancel() - - client, err := New(address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - pulled, err := client.Fetch(ctx, testImage) - if err != nil { - t.Fatal(err) - } - exportedStream, err := client.Export(ctx, &oci.V1Exporter{}, pulled.Target) - if err != nil { - t.Fatal(err) - } - assertOCITar(t, exportedStream) -} - -func assertOCITar(t *testing.T, r io.Reader) { - // TODO: add more assertion - tr := tar.NewReader(r) - foundOCILayout := false - foundIndexJSON := false - for { - h, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - t.Error(err) - continue - } - if h.Name == "oci-layout" { - foundOCILayout = true - } - if h.Name == "index.json" { - foundIndexJSON = true - } - } - if !foundOCILayout { - t.Error("oci-layout not found") - } - if !foundIndexJSON { - t.Error("index.json not found") - } -} diff -Nru containerd-1.2.6/filters/filter_test.go containerd-1.5.9/filters/filter_test.go --- containerd-1.2.6/filters/filter_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/filters/filter_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -272,6 +272,16 @@ input: "image~=,id?=?fbaq", errString: `filters: parse error: [image~= >|,|< id?=?fbaq]: expected value or quoted`, }, + { + name: "FieldQuotedLiteralNotTerminated", + input: "labels.ns/key==value", + errString: `filters: parse error: [labels.ns >|/|< key==value]: quoted literal not terminated`, + }, + { + name: "ValueQuotedLiteralNotTerminated", + input: "labels.key==/value", + errString: `filters: parse error: [labels.key== >|/|< value]: quoted literal not terminated`, + }, } { t.Run(testcase.name, func(t *testing.T) { filter, err := Parse(testcase.input) @@ -307,3 +317,20 @@ }) } } + +func TestOperatorStrings(t *testing.T) { + for _, testcase := range []struct { + op operator + expected string + }{ + {operatorPresent, "?"}, + {operatorEqual, "=="}, + {operatorNotEqual, "!="}, + {operatorMatches, "~="}, + {10, "unknown"}, + } { + if !reflect.DeepEqual(testcase.op.String(), testcase.expected) { + t.Fatalf("return value unexpected: %v != %v", testcase.op.String(), testcase.expected) + } + } +} diff -Nru containerd-1.2.6/filters/parser.go containerd-1.5.9/filters/parser.go --- containerd-1.2.6/filters/parser.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/filters/parser.go 2022-01-05 17:30:58.000000000 +0000 @@ -71,7 +71,7 @@ for _, s := range ss { f, err := Parse(s) if err != nil { - return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error()) + return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error()) } fs = append(fs, f) @@ -209,6 +209,8 @@ return s, nil case tokenQuoted: return p.unquote(pos, s, false) + case tokenIllegal: + return "", p.mkerr(pos, p.scanner.err) } return "", p.mkerr(pos, "expected field or quoted") @@ -228,6 +230,8 @@ default: return 0, p.mkerr(pos, "unsupported operator %q", s) } + case tokenIllegal: + return 0, p.mkerr(pos, p.scanner.err) } return 0, p.mkerr(pos, `expected an operator ("=="|"!="|"~=")`) @@ -241,6 +245,8 @@ return s, nil case tokenQuoted: return p.unquote(pos, s, allowAltQuotes) + case tokenIllegal: + return "", p.mkerr(pos, p.scanner.err) } return "", p.mkerr(pos, "expected value or quoted") diff -Nru containerd-1.2.6/filters/scanner.go containerd-1.5.9/filters/scanner.go --- containerd-1.2.6/filters/scanner.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/filters/scanner.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,7 +17,6 @@ package filters import ( - "fmt" "unicode" "unicode/utf8" ) @@ -64,6 +63,7 @@ pos int ppos int // bounds the current rune in the string value bool + err string } func (s *scanner) init(input string) { @@ -82,12 +82,14 @@ s.ppos += w if r == utf8.RuneError { if w > 0 { + s.error("rune error") return tokenIllegal } return tokenEOF } if r == 0 { + s.error("unexpected null") return tokenIllegal } @@ -114,7 +116,9 @@ case ch == tokenEOF: case ch == tokenIllegal: case isQuoteRune(ch): - s.scanQuoted(ch) + if !s.scanQuoted(ch) { + return pos, tokenIllegal, s.input[pos:s.ppos] + } return pos, tokenQuoted, s.input[pos:s.ppos] case isSeparatorRune(ch): s.value = false @@ -172,54 +176,64 @@ } } -func (s *scanner) scanQuoted(quote rune) { +func (s *scanner) scanQuoted(quote rune) bool { + var illegal bool ch := s.next() // read character after quote for ch != quote { if ch == '\n' || ch < 0 { - s.error("literal not terminated") - return + s.error("quoted literal not terminated") + return false } if ch == '\\' { - ch = s.scanEscape(quote) + var legal bool + ch, legal = s.scanEscape(quote) + if !legal { + illegal = true + } } else { ch = s.next() } } + return !illegal } -func (s *scanner) scanEscape(quote rune) rune { - ch := s.next() // read character after '/' +func (s *scanner) scanEscape(quote rune) (ch rune, legal bool) { + ch = s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote: // nothing to do ch = s.next() + legal = true case '0', '1', '2', '3', '4', '5', '6', '7': - ch = s.scanDigits(ch, 8, 3) + ch, legal = s.scanDigits(ch, 8, 3) case 'x': - ch = s.scanDigits(s.next(), 16, 2) + ch, legal = s.scanDigits(s.next(), 16, 2) case 'u': - ch = s.scanDigits(s.next(), 16, 4) + ch, legal = s.scanDigits(s.next(), 16, 4) case 'U': - ch = s.scanDigits(s.next(), 16, 8) + ch, legal = s.scanDigits(s.next(), 16, 8) default: - s.error("illegal char escape") + s.error("illegal escape sequence") } - return ch + return } -func (s *scanner) scanDigits(ch rune, base, n int) rune { +func (s *scanner) scanDigits(ch rune, base, n int) (rune, bool) { for n > 0 && digitVal(ch) < base { ch = s.next() n-- } if n > 0 { - s.error("illegal char escape") + s.error("illegal numeric escape sequence") + return ch, false } - return ch + return ch, true } func (s *scanner) error(msg string) { - fmt.Println("error fixme", msg) + if s.err == "" { + s.err = msg + } } func digitVal(ch rune) int { diff -Nru containerd-1.2.6/filters/scanner_test.go containerd-1.5.9/filters/scanner_test.go --- containerd-1.2.6/filters/scanner_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/filters/scanner_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,9 +25,13 @@ pos int token token text string + err string } func (tr tokenResult) String() string { + if tr.err != "" { + return fmt.Sprintf("{pos: %v, token: %v, text: %q, err: %q}", tr.pos, tr.token, tr.text, tr.err) + } return fmt.Sprintf("{pos: %v, token: %v, text: %q}", tr.pos, tr.token, tr.text) } @@ -171,7 +175,7 @@ input: "foo\x00bar", expected: []tokenResult{ {pos: 0, token: tokenField, text: "foo"}, - {pos: 3, token: tokenIllegal}, + {pos: 3, token: tokenIllegal, err: "unexpected null"}, {pos: 4, token: tokenField, text: "bar"}, {pos: 7, token: tokenEOF}, }, @@ -271,6 +275,51 @@ {pos: 23, token: tokenEOF}, }, }, + { + name: "IllegalQuoted", + input: "labels.containerd.io/key==value", + expected: []tokenResult{ + {pos: 0, token: tokenField, text: "labels"}, + {pos: 6, token: tokenSeparator, text: "."}, + {pos: 7, token: tokenField, text: "containerd"}, + {pos: 17, token: tokenSeparator, text: "."}, + {pos: 18, token: tokenField, text: "io"}, + {pos: 20, token: tokenIllegal, text: "/key==value", err: "quoted literal not terminated"}, + {pos: 31, token: tokenEOF}, + }, + }, + { + name: "IllegalQuotedWithNewLine", + input: "labels.\"containerd.io\nkey\"==value", + expected: []tokenResult{ + {pos: 0, token: tokenField, text: "labels"}, + {pos: 6, token: tokenSeparator, text: "."}, + {pos: 7, token: tokenIllegal, text: "\"containerd.io\n", err: "quoted literal not terminated"}, + {pos: 22, token: tokenField, text: "key"}, + {pos: 25, token: tokenIllegal, text: "\"==value", err: "quoted literal not terminated"}, + {pos: 33, token: tokenEOF}, + }, + }, + { + name: "IllegalEscapeSequence", + input: `labels."\g"`, + expected: []tokenResult{ + {pos: 0, token: tokenField, text: "labels"}, + {pos: 6, token: tokenSeparator, text: "."}, + {pos: 7, token: tokenIllegal, text: `"\g"`, err: "illegal escape sequence"}, + {pos: 11, token: tokenEOF}, + }, + }, + { + name: "IllegalNumericEscapeSequence", + input: `labels."\xaz"`, + expected: []tokenResult{ + {pos: 0, token: tokenField, text: "labels"}, + {pos: 6, token: tokenSeparator, text: "."}, + {pos: 7, token: tokenIllegal, text: `"\xaz"`, err: "illegal numeric escape sequence"}, + {pos: 13, token: tokenEOF}, + }, + }, } { t.Run(testcase.name, func(t *testing.T) { var sc scanner @@ -296,6 +345,9 @@ if i >= len(testcase.expected) { t.Fatalf("too many tokens parsed") } + if tok == tokenIllegal { + tokv.err = sc.err + } if tokv != testcase.expected[i] { t.Fatalf("token unexpected: %v != %v", tokv, testcase.expected[i]) @@ -305,6 +357,7 @@ if tok == tokenEOF { break } + } // make sure we've eof'd diff -Nru containerd-1.2.6/gc/gc.go containerd-1.5.9/gc/gc.go --- containerd-1.2.6/gc/gc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/gc/gc.go 2022-01-05 17:30:58.000000000 +0000 @@ -30,6 +30,11 @@ // ResourceType represents type of resource at a node type ResourceType uint8 +// ResourceMax represents the max resource. +// Upper bits are stripped out during the mark phase, allowing the upper 3 bits +// to be used by the caller reference function. +const ResourceMax = ResourceType(0x1F) + // Node presents a resource which has a type and key, // this node can be used to lookup other nodes. type Node struct { @@ -80,6 +85,8 @@ } } + // strip bits above max resource type + id.Type = id.Type & ResourceMax // mark as black when done reachable[id] = struct{}{} } @@ -165,7 +172,7 @@ return seen, nil } -// Sweep removes all nodes returned through the channel which are not in +// Sweep removes all nodes returned through the slice which are not in // the reachable set by calling the provided remove function. func Sweep(reachable map[Node]struct{}, all []Node, remove func(Node) error) error { // All black objects are now reachable, and all white objects are diff -Nru containerd-1.2.6/gc/scheduler/scheduler_test.go containerd-1.5.9/gc/scheduler/scheduler_test.go --- containerd-1.2.6/gc/scheduler/scheduler_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/gc/scheduler/scheduler_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,7 +23,7 @@ "time" "github.com/containerd/containerd/gc" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) func TestPauseThreshold(t *testing.T) { @@ -98,7 +98,7 @@ select { case <-gcWait: - case <-time.After(time.Millisecond * 10): + case <-time.After(time.Millisecond * 30): t.Fatal("GC wait timed out") } @@ -162,7 +162,7 @@ defer cancel() go scheduler.run(ctx) - time.Sleep(time.Millisecond * 5) + time.Sleep(time.Millisecond * 30) if c := tc.runCount(); c != 1 { t.Fatalf("unexpected gc run count %d, expected 1", c) diff -Nru containerd-1.2.6/.gitattributes containerd-1.5.9/.gitattributes --- containerd-1.2.6/.gitattributes 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.gitattributes 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +*.go text eol=lf \ No newline at end of file diff -Nru containerd-1.2.6/.github/ISSUE_TEMPLATE/bug_report.md containerd-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md --- containerd-1.2.6/.github/ISSUE_TEMPLATE/bug_report.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +--- +name: Bug report +about: Create a bug report to help improve containerd +title: '' +labels: kind/bug +assignees: '' +--- + + + +**Description** + + + +**Steps to reproduce the issue:** +1. +2. +3. + +**Describe the results you received:** + + +**Describe the results you expected:** + + +**What version of containerd are you using:** + +``` +$ containerd --version + +``` + +**Any other relevant information (runC version, CRI configuration, OS/Kernel version, etc.):** + + + +
runc --version
+$ runc --version
+
+
+ + + +
crictl info
+$ crictl info
+
+
+ + +
uname -a
+$ uname -a
+
+
diff -Nru containerd-1.2.6/.github/ISSUE_TEMPLATE/config.yml containerd-1.5.9/.github/ISSUE_TEMPLATE/config.yml --- containerd-1.2.6/.github/ISSUE_TEMPLATE/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/ISSUE_TEMPLATE/config.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +blank_issues_enabled: true +contact_links: + - name: Ask a question (GitHub Discussions) + url: https://github.com/containerd/containerd/discussions + about: | + Please do not submit "a bug report" for asking a question. + In most cases, GitHub Discussions is the best place to ask a question. + If you are not sure whether you are going to report a bug or ask a question, + please consider asking in GitHub Discussions first. + - name: Chat with containerd users and developers + url: https://slack.cncf.io/ + about: CNCF slack has `#containerd` and `#containerd-dev` channels diff -Nru containerd-1.2.6/.github/ISSUE_TEMPLATE/feature_request.md containerd-1.5.9/.github/ISSUE_TEMPLATE/feature_request.md --- containerd-1.2.6/.github/ISSUE_TEMPLATE/feature_request.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/ISSUE_TEMPLATE/feature_request.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +--- +name: Feature request +about: Suggest an idea for containerd +title: '' +labels: kind/feature +assignees: '' +--- + +**What is the problem you're trying to solve** +A clear and concise description of what the problem is. + +**Describe the solution you'd like** +A clear and concise description of what you'd like to happen. + +**Additional context** +Add any other context about the feature request here. \ No newline at end of file diff -Nru containerd-1.2.6/.github/ISSUE_TEMPLATE.md containerd-1.5.9/.github/ISSUE_TEMPLATE.md --- containerd-1.2.6/.github/ISSUE_TEMPLATE.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.github/ISSUE_TEMPLATE.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - -**Description** - - - -**Steps to reproduce the issue:** -1. -2. -3. - -**Describe the results you received:** - - -**Describe the results you expected:** - - -**Output of `containerd --version`:** - -``` -(paste your output here) -``` diff -Nru containerd-1.2.6/.github/workflows/ci.yml containerd-1.5.9/.github/workflows/ci.yml --- containerd-1.2.6/.github/workflows/ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/workflows/ci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,588 @@ +name: CI +on: + push: + branches: + - master + - 'release/**' + pull_request: + branches: + - master + - 'release/**' + +jobs: + # + # golangci-lint + # + linters: + name: Linters + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + + strategy: + matrix: + go-version: [1.16.12] + os: [ubuntu-18.04, macos-10.15, windows-2019] + + steps: + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - uses: golangci/golangci-lint-action@v2 + with: + version: v1.36.0 + working-directory: src/github.com/containerd/containerd + args: --timeout=5m + + # + # Project checks + # + project: + name: Project Checks + runs-on: ubuntu-18.04 + timeout-minutes: 5 + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + fetch-depth: 100 + + - uses: containerd/project-checks@v1 + with: + working-directory: src/github.com/containerd/containerd + + # + # Protobuf checks + # + protos: + name: Protobuf + runs-on: ubuntu-18.04 + timeout-minutes: 5 + + defaults: + run: + working-directory: src/github.com/containerd/containerd + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "GO111MODULE=off" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - name: Install protobuf + run: | + sudo -E PATH=$PATH script/setup/install-protobuf + sudo chmod +x /usr/local/bin/protoc + sudo chmod og+rx /usr/local/include/google /usr/local/include/google/protobuf /usr/local/include/google/protobuf/compiler + sudo chmod -R og+r /usr/local/include/google/protobuf/ + protoc --version + + - run: script/setup/install-dev-tools + - run: make proto-fmt + - run: make check-protos check-api-descriptors + + man: + name: Manpages + runs-on: ubuntu-18.04 + timeout-minutes: 5 + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - run: GO111MODULE=on go get github.com/cpuguy83/go-md2man/v2@v2.0.0 + + - run: make man + working-directory: src/github.com/containerd/containerd + + # Make sure binaries compile with other platforms + crossbuild: + name: Crossbuild Binaries + needs: [project, linters, protos, man] + runs-on: ubuntu-18.04 + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - goos: linux + goarch: arm64 + - goos: linux + goarch: arm + goarm: "7" + - goos: linux + goarch: arm + goarm: "5" + - goos: freebsd + goarch: amd64 + - goos: freebsd + goarch: arm64 + - goos: windows + goarch: arm + goarm: "7" + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + - run: | + set -e -x + + packages="" + platform="${{matrix.goos}}/${{matrix.goarch}}" + if [ -n "${{matrix.goarm}}" ]; then + platform+="/v${{matrix.goarm}}" + fi + + case "${platform}" in + linux/arm/v5) + packages+=" crossbuild-essential-armel" + echo "CGO_ENABLED=1" >> $GITHUB_ENV + echo "CC=arm-linux-gnueabi-gcc" >> $GITHUB_ENV + ;; + linux/arm/v7) + packages+=" crossbuild-essential-armhf" + echo "CGO_ENABLED=1" >> $GITHUB_ENV + echo "CC=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV + ;; + linux/arm64) + packages+=" crossbuild-essential-arm64" + echo "CGO_ENABLED=1" >> $GITHUB_ENV + echo "CC=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + ;; + windows/arm/v7) + echo "CGO_ENABLED=0" >> $GITHUB_ENV + ;; + esac + + if [ -n "${packages}" ]; then + sudo apt-get update && sudo apt-get install -y ${packages} + fi + name: install deps + - name: Build + working-directory: src/github.com/containerd/containerd + env: + GOOS: ${{matrix.goos}} + GOARCH: ${{matrix.goarch}} + GOARM: ${{matrix.goarm}} + run: | + make build + make binaries + + # + # Build containerd binaries + # + binaries: + name: Binaries + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + needs: [project, linters, protos, man] + + strategy: + matrix: + os: [ubuntu-18.04, macos-10.15, windows-2019] + go-version: ['1.16.12'] + include: + # Go 1.13.x is still used by Docker/Moby + - go-version: '1.13.x' + os: ubuntu-18.04 + + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Make + run: | + make build + make binaries + working-directory: src/github.com/containerd/containerd + + # + # Integration and CRI tests + # + integration-windows: + name: Windows Integration + runs-on: windows-2019 + timeout-minutes: 30 + needs: [project, linters, protos, man] + env: + GOTEST: gotestsum -- + + defaults: + run: + shell: bash + working-directory: src/github.com/containerd/containerd + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - uses: actions/checkout@v2 + with: + repository: Microsoft/hcsshim + path: src/github.com/Microsoft/hcsshim + + - name: Set env + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + echo "${{ github.workspace }}/src/github.com/containerd/containerd/bin" >> $GITHUB_PATH + + - run: script/setup/install-dev-tools + + - name: Binaries + env: + CGO_ENABLED: 1 + run: | + set -o xtrace + mingw32-make.exe binaries + bindir="$(pwd)" + SHIM_COMMIT=$(grep 'Microsoft/hcsshim ' go.mod | awk '{print $2}') + cd ../../Microsoft/hcsshim + git fetch --tags origin "${SHIM_COMMIT}" + git checkout "${SHIM_COMMIT}" + GO111MODULE=on go build -mod=vendor -o "${bindir}/integration/client/containerd-shim-runhcs-v1.exe" ./cmd/containerd-shim-runhcs-v1 + + - run: script/setup/install-gotestsum + - name: Tests + env: + CGO_ENABLED: 1 + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-unit-root.xml + run: mingw32-make.exe test root-test + + - name: Integration 1 + env: + CGO_ENABLED: 1 + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-serial-junit.xml + run: mingw32-make.exe integration + + # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 + - name: Integration 2 + env: + TESTFLAGS_PARALLEL: 1 + CGO_ENABLED: 1 + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-parallel-junit.xml + run: mingw32-make.exe integration + - uses: actions/upload-artifact@v2 + if: always() + with: + name: TestResults Windows + path: | + ${{github.workspace}}/*-junit.xml + + integration-linux: + name: Linux Integration + runs-on: ubuntu-18.04 + timeout-minutes: 40 + needs: [project, linters, protos, man] + + strategy: + fail-fast: false + matrix: + runtime: [io.containerd.runtime.v1.linux, io.containerd.runc.v1, io.containerd.runc.v2] + runc: [runc, crun] + exclude: + - runtime: io.containerd.runc.v1 + runc: crun + - runtime: io.containerd.runtime.v1.linux + runc: crun + + env: + GOTEST: gotestsum -- + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - name: Install containerd dependencies + env: + RUNC_FLAVOR: ${{ matrix.runc }} + run: | + sudo apt-get install -y gperf + sudo -E PATH=$PATH script/setup/install-seccomp + sudo -E PATH=$PATH script/setup/install-runc + sudo -E PATH=$PATH script/setup/install-cni + sudo -E PATH=$PATH script/setup/install-critools + working-directory: src/github.com/containerd/containerd + + - name: Install criu + run: | + sudo apt-get install -y \ + libprotobuf-dev \ + libprotobuf-c-dev \ + protobuf-c-compiler \ + protobuf-compiler \ + python-protobuf \ + libnl-3-dev \ + libnet-dev \ + libcap-dev \ + python-future + wget https://github.com/checkpoint-restore/criu/archive/v3.13.tar.gz -O criu.tar.gz + tar -zxf criu.tar.gz + cd criu-3.13 + sudo make install-criu + + - name: Install containerd + env: + CGO_ENABLED: 1 + run: | + make binaries + sudo -E PATH=$PATH make install + working-directory: src/github.com/containerd/containerd + + - run: sudo -E PATH=$PATH script/setup/install-gotestsum + working-directory: src/github.com/containerd/containerd + - name: Tests + env: + GOPROXY: direct + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-unit-root-junit.xml + run: | + make test + sudo -E PATH=$PATH make root-test + working-directory: src/github.com/containerd/containerd + + - name: Integration 1 + env: + GOPROXY: direct + TEST_RUNTIME: ${{ matrix.runtime }} + RUNC_FLAVOR: ${{ matrix.runc }} + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-serial-junit.xml + run: | + sudo -E PATH=$PATH make integration EXTRA_TESTFLAGS=-no-criu TESTFLAGS_RACE=-race + working-directory: src/github.com/containerd/containerd + + # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 + - name: Integration 2 + env: + GOPROXY: direct + TEST_RUNTIME: ${{ matrix.runtime }} + RUNC_FLAVOR: ${{ matrix.runc }} + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-parallel-junit.xml + run: | + sudo -E PATH=$PATH TESTFLAGS_PARALLEL=1 make integration EXTRA_TESTFLAGS=-no-criu + working-directory: src/github.com/containerd/containerd + + # CRIU wouldn't work with overlay snapshotter yet. + # See https://github.com/containerd/containerd/pull/4708#issuecomment-724322294. + - name: CRIU Integration + env: + GOPROXY: direct + TEST_RUNTIME: ${{ matrix.runtime }} + RUNC_FLAVOR: ${{ matrix.runc }} + GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-criu-junit.xml + # crun doesn't have "checkpoint" command. + if: ${{ matrix.runc == 'runc' }} + run: | + sudo -E PATH=$PATH \ + TESTFLAGS_PARALLEL=1 \ + TEST_SNAPSHOTTER=native \ + make integration EXTRA_TESTFLAGS='-run TestCheckpoint' + working-directory: src/github.com/containerd/containerd + + - name: CRI Integration Test + env: + TEST_RUNTIME: ${{ matrix.runtime }} + run: | + CONTAINERD_RUNTIME=$TEST_RUNTIME make cri-integration + working-directory: src/github.com/containerd/containerd + + - name: cri-tools critest + env: + TEST_RUNTIME: ${{ matrix.runtime }} + run: | + BDIR="$(mktemp -d -p $PWD)" + mkdir -p ${BDIR}/{root,state} + cat > ${BDIR}/config.toml < ${BDIR}/containerd-cri.log & + sudo -E PATH=$PATH /usr/local/bin/ctr -a ${BDIR}/c.sock version + sudo -E PATH=$PATH critest --report-dir "${{github.workspace}}/critestreport" --runtime-endpoint=unix:///${BDIR}/c.sock --parallel=8 + TEST_RC=$? + test $TEST_RC -ne 0 && cat ${BDIR}/containerd-cri.log + sudo pkill containerd + sudo -E rm -rf ${BDIR} + test $TEST_RC -eq 0 || /bin/false + + # Log the status of this VM to investigate issues like + # https://github.com/containerd/containerd/issues/4969 + - name: Host Status + if: always() + run: | + set -x + mount + df + losetup -l + - uses: actions/upload-artifact@v2 + if: always() + with: + name: TestResults ${{ matrix.runtime }} ${{matrix.runc}} + path: | + *-junit.xml + ${{github.workspace}}/critestreport/*.xml + + tests-mac-os: + name: MacOS unit tests + runs-on: macos-10.15 + timeout-minutes: 10 + needs: [project, linters, protos, man] + env: + GOTEST: gotestsum -- + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - run: sudo -E PATH=$PATH script/setup/install-gotestsum + working-directory: src/github.com/containerd/containerd + - name: Tests + env: + GOPROXY: direct + GOTESTSUM_JUNITFILE: "${{ github.workspace }}/macos-test-junit.xml" + run: | + make test + working-directory: src/github.com/containerd/containerd + - uses: actions/upload-artifact@v2 + if: always() + with: + name: TestResults MacOS + path: | + *-junit.xml + + cgroup2: + name: CGroupsV2 and SELinux Integration + # nested virtualization is only available on macOS hosts + runs-on: macos-10.15 + timeout-minutes: 45 + needs: [project, linters, protos, man] + strategy: + matrix: + # Currently crun is disabled to decrease CI flakiness. + # We can enable crun again when we get a better CI infra. + runc: [runc] + env: + GOTEST: gotestsum -- + steps: + - uses: actions/checkout@v2 + + - name: "Cache ~/.vagrant.d/boxes" + uses: actions/cache@v2 + with: + path: ~/.vagrant.d/boxes + key: vagrant-${{ hashFiles('Vagrantfile*') }} + + - name: Vagrant start + run: | + # Retry if it fails (download.fedoraproject.org returns 404 sometimes) + vagrant up || vagrant up + + - name: Integration + env: + RUNC_FLAVOR: ${{ matrix.runc }} + SELINUX: Enforcing + GOTESTSUM_JUNITFILE: /tmp/test-integration-junit.xml + run: vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-integration + + - name: CRI test + env: + RUNC_FLAVOR: ${{ matrix.runc }} + SELINUX: Enforcing + REPORT_DIR: /tmp/critestreport + run: vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-cri + - name: Get test reports + if: always() + run: | + set -e + vagrant plugin install vagrant-vbguest + vagrant plugin install vagrant-scp + vagrant scp :/tmp/test-integration-junit.xml "${{ github.workspace }}/" + vagrant scp :/tmp/critestreport "${{ github.workspace }}/critestreport" + - uses: actions/upload-artifact@v2 + if: always() + with: + name: TestResults cgroup2 ${{ matrix.runtime }} ${{matrix.runc}} + path: | + ${{github.workspace}}/*-junit.xml + ${{github.workspace}}/critestreport/* diff -Nru containerd-1.2.6/.github/workflows/codeql.yml containerd-1.5.9/.github/workflows/codeql.yml --- containerd-1.2.6/.github/workflows/codeql.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/workflows/codeql.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,49 @@ +name: "CodeQL Scan" + +on: + push: + schedule: + - cron: '0 0 * * 0' + pull_request: + paths: + - '.github/workflows/codeql.yml' + +jobs: + CodeQL-Build: + + strategy: + fail-fast: false + + + # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below). + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # â„¹ï¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœï¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff -Nru containerd-1.2.6/.github/workflows/nightly.yml containerd-1.5.9/.github/workflows/nightly.yml --- containerd-1.2.6/.github/workflows/nightly.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/workflows/nightly.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,161 @@ +name: Nightly +on: + schedule: + - cron: '0 0 * * *' # Every day at midnight + pull_request: + paths: + - '.github/workflows/nightly.yml' + +jobs: + linux: + name: Linux + runs-on: ubuntu-latest + + defaults: + run: + working-directory: src/github.com/containerd/containerd + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + # + # Build + # + + - name: Install dependencies + run: | + sudo add-apt-repository "deb [arch=arm64,s390x,ppc64el] http://ports.ubuntu.com/ubuntu-ports/ $(lsb_release -sc) main" || true + sudo add-apt-repository "deb [arch=arm64,s390x,ppc64el] http://ports.ubuntu.com/ubuntu-ports/ $(lsb_release -sc)-updates main" || true + + sudo dpkg --add-architecture arm64 + sudo dpkg --add-architecture s390x + sudo dpkg --add-architecture ppc64el + + sudo apt-get update || true + + sudo apt-get install -y \ + crossbuild-essential-arm64 \ + crossbuild-essential-s390x \ + crossbuild-essential-ppc64el \ + libseccomp-dev:amd64 \ + libseccomp-dev:arm64 \ + libseccomp-dev:s390x \ + libseccomp-dev:ppc64el \ + libbtrfs-dev:amd64 \ + libbtrfs-dev:arm64 \ + libbtrfs-dev:s390x \ + libbtrfs-dev:ppc64el + + - name: Build amd64 + env: + GOOS: linux + GOARCH: amd64 + run: | + make binaries + mv bin bin_amd64 + + - name: Build arm64 + env: + GOOS: linux + GOARCH: arm64 + CC: aarch64-linux-gnu-gcc + CGO_ENABLED: 1 + run: | + make binaries + mv bin bin_arm64 + + - name: Build s390x + env: + GOOS: linux + GOARCH: s390x + CGO_ENABLED: 1 + CC: s390x-linux-gnu-gcc + run: | + make binaries + mv bin bin_s390x + + - name: Build ppc64le + env: + GOOS: linux + GOARCH: ppc64le + CGO_ENABLED: 1 + CC: powerpc64le-linux-gnu-gcc + run: | + make binaries + mv bin bin_ppc64le + + # + # Upload + # + + - name: Upload artifacts (linux_amd64) + uses: actions/upload-artifact@v1 + with: + name: linux_amd64 + path: src/github.com/containerd/containerd/bin_amd64 + + - name: Upload artifacts (linux_arm64) + uses: actions/upload-artifact@v1 + with: + name: linux_arm64 + path: src/github.com/containerd/containerd/bin_arm64 + + - name: Upload artifacts (linux_s390x) + uses: actions/upload-artifact@v1 + with: + name: linux_s390x + path: src/github.com/containerd/containerd/bin_s390x + + - name: Upload artifacts (linux_ppc64le) + uses: actions/upload-artifact@v1 + with: + name: linux_ppc64le + path: src/github.com/containerd/containerd/bin_ppc64le + + windows: + name: Windows + runs-on: windows-latest + + defaults: + run: + working-directory: src/github.com/containerd/containerd + + steps: + - uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - uses: actions/checkout@v2 + with: + path: src/github.com/containerd/containerd + + - name: Set env + shell: bash + run: | + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - name: Build amd64 + env: + GOOS: windows + GOARCH: amd64 + run: | + make binaries + + - name: Upload artifacts (windows_amd64) + uses: actions/upload-artifact@v1 + with: + name: windows_amd64 + path: src/github.com/containerd/containerd/bin/ diff -Nru containerd-1.2.6/.github/workflows/release.yml containerd-1.5.9/.github/workflows/release.yml --- containerd-1.2.6/.github/workflows/release.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.github/workflows/release.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,255 @@ +on: + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Containerd Release + +jobs: + check: + name: Check Signed Tag + runs-on: ubuntu-18.04 + timeout-minutes: 5 + outputs: + stringver: ${{ steps.contentrel.outputs.stringver }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.ref }} + path: src/github.com/containerd/containerd + + - name: Check signature + run: | + releasever=${{ github.ref }} + releasever="${releasever#refs/tags/}" + TAGCHECK=$(git tag -v ${releasever} 2>&1 >/dev/null) || + echo "${TAGCHECK}" | grep -q "error" && { + echo "::error::tag ${releasever} is not a signed tag. Failing release process." + exit 1 + } || { + echo "Tag ${releasever} is signed." + exit 0 + } + working-directory: src/github.com/containerd/containerd + + - name: Release content + id: contentrel + run: | + RELEASEVER=${{ github.ref }} + echo "::set-output name=stringver::${RELEASEVER#refs/tags/v}" + git tag -l ${RELEASEVER#refs/tags/} -n20000 | tail -n +3 | cut -c 5- >release-notes.md + working-directory: src/github.com/containerd/containerd + + - name: Save release notes + uses: actions/upload-artifact@v2 + with: + name: containerd-release-notes + path: src/github.com/containerd/containerd/release-notes.md + + build: + name: Build Release Binaries + runs-on: ${{ matrix.os }} + needs: [check] + timeout-minutes: 10 + + strategy: + matrix: + os: [ubuntu-18.04, windows-2019] + + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.16.12' + + - name: Set env + shell: bash + env: + MOS: ${{ matrix.os }} + run: | + releasever=${{ github.ref }} + releasever="${releasever#refs/tags/}" + os=linux + [[ "${MOS}" =~ "windows" ]] && { + os=windows + } + echo "RELEASE_VER=${releasever}" >> $GITHUB_ENV + echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV + echo "OS=${os}" >> $GITHUB_ENV + echo "${{ github.workspace }}/bin" >> $GITHUB_PATH + + - name: Checkout containerd + uses: actions/checkout@v2 + with: + repository: containerd/containerd + ref: ${{ github.ref }} + path: src/github.com/containerd/containerd + + - name: HCS Shim commit + id: hcsshim_commit + if: startsWith(matrix.os, 'windows') + shell: bash + run: echo "::set-output name=sha::$(grep 'Microsoft/hcsshim ' go.mod | awk '{print $2}')" + working-directory: src/github.com/containerd/containerd + + - name: Checkout hcsshim source + if: startsWith(matrix.os, 'windows') + uses: actions/checkout@v2 + with: + repository: Microsoft/hcsshim + ref: ${{ steps.hcsshim_commit.outputs.sha }} + path: src/github.com/Microsoft/hcsshim + + - name: Make + shell: bash + run: | + make build + make binaries + rm bin/containerd-stress* + [[ "${OS}" == "windows" ]] && { + ( + bindir="$(pwd)/bin" + cd ../../Microsoft/hcsshim + GO111MODULE=on go build -mod=vendor -o "${bindir}/containerd-shim-runhcs-v1.exe" ./cmd/containerd-shim-runhcs-v1 + ) + } + TARFILE="containerd-${RELEASE_VER#v}-${OS}-amd64.tar.gz" + tar czf ${TARFILE} bin/ + sha256sum ${TARFILE} >${TARFILE}.sha256sum + working-directory: src/github.com/containerd/containerd + + - name: Save build binaries + uses: actions/upload-artifact@v2 + with: + name: containerd-binaries-${{ matrix.os }} + path: src/github.com/containerd/containerd/*.tar.gz* + + - name: Make cri-containerd tar + shell: bash + env: + RUNC_FLAVOR: runc + run: | + if [[ "${OS}" == "linux" ]]; then + sudo apt-get update + sudo apt-get install -y gperf + sudo -E PATH=$PATH script/setup/install-seccomp + fi + make cri-cni-release + working-directory: src/github.com/containerd/containerd + + - name: Save cri-containerd binaries + uses: actions/upload-artifact@v2 + with: + name: cri-containerd-binaries-${{ matrix.os }} + path: src/github.com/containerd/containerd/releases/cri-containerd-cni-*.tar.gz* + + release: + name: Create containerd Release + runs-on: ubuntu-18.04 + timeout-minutes: 10 + needs: [build, check] + + steps: + - name: Download builds and release notes + uses: actions/download-artifact@v2 + with: + path: builds + - name: Catalog build assets for upload + id: catalog + run: | + _filenum=1 + for i in "ubuntu-18.04" "windows-2019"; do + for f in `ls builds/containerd-binaries-${i}`; do + echo "::set-output name=file${_filenum}::${f}" + let "_filenum+=1" + done + for f in `ls builds/cri-containerd-binaries-${i}`; do + echo "::set-output name=file${_filenum}::${f}" + let "_filenum+=1" + done + done + - name: Create Release + id: create_release + uses: actions/create-release@v1.1.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: containerd ${{ needs.check.outputs.stringver }} + body_path: ./builds/containerd-release-notes/release-notes.md + draft: false + prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + - name: Upload Linux containerd tarball + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/containerd-binaries-ubuntu-18.04/${{ steps.catalog.outputs.file1 }} + asset_name: ${{ steps.catalog.outputs.file1 }} + asset_content_type: application/gzip + - name: Upload Linux sha256 sum + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/containerd-binaries-ubuntu-18.04/${{ steps.catalog.outputs.file2 }} + asset_name: ${{ steps.catalog.outputs.file2 }} + asset_content_type: text/plain + - name: Upload Linux cri containerd tarball + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/cri-containerd-binaries-ubuntu-18.04/${{ steps.catalog.outputs.file3 }} + asset_name: ${{ steps.catalog.outputs.file3 }} + asset_content_type: application/gzip + - name: Upload Linux cri sha256 sum + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/cri-containerd-binaries-ubuntu-18.04/${{ steps.catalog.outputs.file4 }} + asset_name: ${{ steps.catalog.outputs.file4 }} + asset_content_type: text/plain + - name: Upload Windows containerd tarball + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/containerd-binaries-windows-2019/${{ steps.catalog.outputs.file5 }} + asset_name: ${{ steps.catalog.outputs.file5 }} + asset_content_type: application/gzip + - name: Upload Windows sha256 sum + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/containerd-binaries-windows-2019/${{ steps.catalog.outputs.file6 }} + asset_name: ${{ steps.catalog.outputs.file6 }} + asset_content_type: text/plain + - name: Upload Windows cri containerd tarball + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/cri-containerd-binaries-windows-2019/${{ steps.catalog.outputs.file7 }} + asset_name: ${{ steps.catalog.outputs.file7 }} + asset_content_type: application/gzip + - name: Upload Windows cri sha256 sum + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./builds/cri-containerd-binaries-windows-2019/${{ steps.catalog.outputs.file8 }} + asset_name: ${{ steps.catalog.outputs.file8 }} + asset_content_type: text/plain diff -Nru containerd-1.2.6/.gitignore containerd-1.5.9/.gitignore --- containerd-1.2.6/.gitignore 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -4,3 +4,7 @@ profile.out containerd.test _site/ +releases/*.tar.gz +releases/*.tar.gz.sha256sum +_output/ +.vagrant/ diff -Nru containerd-1.2.6/.golangci.yml containerd-1.5.9/.golangci.yml --- containerd-1.2.6/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +issues: + include: + - EXC0002 + +run: + timeout: 3m + skip-dirs: + - api + - design + - docs + - docs/man diff -Nru containerd-1.2.6/.gometalinter.json containerd-1.5.9/.gometalinter.json --- containerd-1.2.6/.gometalinter.json 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.gometalinter.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -{ - "Vendor": true, - "Deadline": "2m", - "Sort": ["linter", "severity", "path", "line"], - "Exclude": [ - ".*\\.pb\\.go", - "fetch\\.go:.*::error: unrecognized printf verb 'r'" - ], - "EnableGC": true, - - "Enable": [ - "structcheck", - "varcheck", - "staticcheck", - "unconvert", - - "gofmt", - "goimports", - "golint", - "ineffassign", - "vet" - ] -} diff -Nru containerd-1.2.6/go.mod containerd-1.5.9/go.mod --- containerd-1.2.6/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +module github.com/containerd/containerd + +go 1.16 + +require ( + github.com/Microsoft/go-winio v0.4.17 + github.com/Microsoft/hcsshim v0.8.23 + github.com/containerd/aufs v1.0.0 + github.com/containerd/btrfs v1.0.0 + github.com/containerd/cgroups v1.0.1 + github.com/containerd/console v1.0.2 + github.com/containerd/continuity v0.1.0 + github.com/containerd/fifo v1.0.0 + github.com/containerd/go-cni v1.0.2 + github.com/containerd/go-runc v1.0.0 + github.com/containerd/imgcrypt v1.1.1 + github.com/containerd/nri v0.1.0 + github.com/containerd/ttrpc v1.1.0 + github.com/containerd/typeurl v1.0.2 + github.com/containerd/zfs v1.0.0 + github.com/containernetworking/plugins v0.9.1 + github.com/coreos/go-systemd/v22 v22.3.2 + github.com/davecgh/go-spew v1.1.1 + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c + github.com/docker/go-metrics v0.0.1 + github.com/docker/go-units v0.4.0 + github.com/emicklei/go-restful v2.9.5+incompatible + github.com/fsnotify/fsnotify v1.4.9 + github.com/gogo/googleapis v1.4.0 + github.com/gogo/protobuf v1.3.2 + github.com/golang/protobuf v1.5.0 + github.com/google/go-cmp v0.5.5 + github.com/google/uuid v1.2.0 + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 + github.com/hashicorp/go-multierror v1.0.0 + github.com/imdario/mergo v0.3.12 + github.com/klauspost/compress v1.11.13 + github.com/moby/locker v1.0.1 + github.com/moby/sys/mountinfo v0.4.1 + github.com/moby/sys/symlink v0.1.0 + github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/image-spec v1.0.2 + github.com/opencontainers/runc v1.0.2 + github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 + github.com/opencontainers/selinux v1.8.2 + github.com/pelletier/go-toml v1.8.1 + github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.7.1 + github.com/satori/go.uuid v1.2.0 // indirect + github.com/sirupsen/logrus v1.8.1 + github.com/stretchr/testify v1.6.1 + github.com/tchap/go-patricia v2.2.6+incompatible + github.com/urfave/cli v1.22.2 + go.etcd.io/bbolt v1.3.5 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a + golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 + google.golang.org/grpc v1.33.2 + gotest.tools/v3 v3.0.3 + k8s.io/api v0.20.6 + k8s.io/apimachinery v0.20.6 + k8s.io/apiserver v0.20.6 + k8s.io/client-go v0.20.6 + k8s.io/component-base v0.20.6 + k8s.io/cri-api v0.20.6 + k8s.io/klog/v2 v2.4.0 + k8s.io/utils v0.0.0-20201110183641-67b214c5f920 +) + +// When updating replace rules, make sure to also update the rules in integration/client/go.mod +replace ( + // prevent transitional dependencies due to containerd having a circular + // dependency on itself through plugins. see .empty-mod/go.mod for details + github.com/containerd/containerd => ./.empty-mod/ + github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2 + github.com/golang/protobuf => github.com/golang/protobuf v1.3.5 + // urfave/cli must be <= v1.22.1 due to a regression: https://github.com/urfave/cli/issues/1092 + github.com/urfave/cli => github.com/urfave/cli v1.22.1 + google.golang.org/genproto => google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 + google.golang.org/grpc => google.golang.org/grpc v1.27.1 +) diff -Nru containerd-1.2.6/go.sum containerd-1.5.9/go.sum --- containerd-1.2.6/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,754 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v1.0.0 h1:2oeJiwX5HstO7shSrPZjrohJZLzK36wvpdmzDRkL/LY= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v1.0.0 h1:osn1exbzdub9L5SouXO5swW4ea/xVdJZ3wokxN5GrnA= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.2 h1:YbJAhpTevL2v6u8JC1NhCYRwf+3Vzxcc5vGnYoJ7VeE= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0 h1:oU+lLv1ULm5taqgV/CJivypVODI4SUz1znWjv3nNYS0= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.1.1 h1:LBwiTfoUsdiEGAR1TpvxE+Gzt7469oVu87iR3mv3Byc= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.1.0 h1:6QioHRlThlKh2RkRTR4kIT3PKAcrLo3gIWnjkM4dQmQ= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v1.0.0 h1:cXLJbx+4Jj7rNsTiqVfm6i+RNLx6FFA2fMmDlEf+Wm8= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.9.1 h1:FD1tADPls2EEi3flPc2OegIY1M9pUa9r2Quag7HMLV8= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.1.1 h1:prL8l9w3ntVqXvNH1CiNn5ENjcCnr38JqpSyvKKB4GI= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c= +github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0 h1:MTFZ74KtNI6qQQpuBxU+uKCim4WtOMokr03hCfJcazE= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 h1:lIOOHPEbXzO3vnmx2gok1Tfs31Q8GQqKLc8vVqyQq/I= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible h1:JvoDL7JSoIP2HDE8AbDH3zC8QBPxmzYe32HHy5yQ+Ck= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 h1:YzfoEYWbODU5Fbt37+h7X16BWQbad7Q4S6gclTKFXM8= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.6 h1:bgdZrW++LqgrLikWYNruIKAtltXbSCX2l5mJu11hrVE= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/apimachinery v0.20.6 h1:R5p3SlhaABYShQSO6LpPsYHjV05Q+79eBUR0Ut/f4tk= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apiserver v0.20.6 h1:NnVriMMOpqQX+dshbDoZixqmBhfgrPk2uOh2fzp9vHE= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/client-go v0.20.6 h1:nJZOfolnsVtDtbGJNCxzOtKUAu7zvXjB8+pMo9UNxZo= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/component-base v0.20.6 h1:G0inASS5vAqCpzs7M4Sp9dv9d0aElpz39zDHbSB4f4g= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/cri-api v0.20.6 h1:iXX0K2pRrbR8yXbZtDK/bSnmg/uSqIFiVJK1x4LUOMc= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3 h1:4oyYo8NREp49LBBhKxEqCulFjg26rawYKrnCmg+Sr6c= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/helpers_unix_test.go containerd-1.5.9/helpers_unix_test.go --- containerd-1.2.6/helpers_unix_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/helpers_unix_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "fmt" - - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" - specs "github.com/opencontainers/runtime-spec/specs-go" -) - -const newLine = "\n" - -func withExitStatus(es int) oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Process.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)} - return nil - } -} - -func withProcessArgs(args ...string) oci.SpecOpts { - return oci.WithProcessArgs(args...) -} - -func withCat() oci.SpecOpts { - return oci.WithProcessArgs("cat") -} - -func withTrue() oci.SpecOpts { - return oci.WithProcessArgs("true") -} - -func withExecExitStatus(s *specs.Process, es int) { - s.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)} -} - -func withExecArgs(s *specs.Process, args ...string) { - s.Args = args -} diff -Nru containerd-1.2.6/helpers_windows_test.go containerd-1.5.9/helpers_windows_test.go --- containerd-1.2.6/helpers_windows_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/helpers_windows_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "strconv" - - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" - specs "github.com/opencontainers/runtime-spec/specs-go" -) - -const newLine = "\r\n" - -func withExitStatus(es int) oci.SpecOpts { - return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { - s.Process.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)} - return nil - } -} - -func withProcessArgs(args ...string) oci.SpecOpts { - return oci.WithProcessArgs(append([]string{"powershell", "-noprofile"}, args...)...) -} - -func withCat() oci.SpecOpts { - return oci.WithProcessArgs("cmd", "/c", "more") -} - -func withTrue() oci.SpecOpts { - return oci.WithProcessArgs("cmd", "/c") -} - -func withExecExitStatus(s *specs.Process, es int) { - s.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)} -} - -func withExecArgs(s *specs.Process, args ...string) { - s.Args = append([]string{"powershell", "-noprofile"}, args...) -} diff -Nru containerd-1.2.6/identifiers/validate.go containerd-1.5.9/identifiers/validate.go --- containerd-1.2.6/identifiers/validate.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/identifiers/validate.go 2022-01-05 17:30:58.000000000 +0000 @@ -42,13 +42,13 @@ identifierRe = regexp.MustCompile(reAnchor(alphanum + reGroup(separators+reGroup(alphanum)) + "*")) ) -// Validate return nil if the string s is a valid identifier. +// Validate returns nil if the string s is a valid identifier. // -// identifiers must be valid domain names according to RFC 1035, section 2.3.1. To -// enforce case insensitvity, all characters must be lower case. +// identifiers are similar to the domain name rules according to RFC 1035, section 2.3.1. However +// rules in this package are relaxed to allow numerals to follow period (".") and mixed case is +// allowed. // -// In general, identifiers that pass this validation, should be safe for use as -// a domain names or filesystem path component. +// In general identifiers that pass this validation should be safe for use as filesystem path components. func Validate(s string) error { if len(s) == 0 { return errors.Wrapf(errdefs.ErrInvalidArgument, "identifier must not be empty") diff -Nru containerd-1.2.6/identifiers/validate_test.go containerd-1.5.9/identifiers/validate_test.go --- containerd-1.2.6/identifiers/validate_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/identifiers/validate_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -34,6 +34,7 @@ "swarmkit.docker.io", "0912341234", "task.0.0123456789", + "container.system-75-f19a.00", "underscores_are_allowed", strings.Repeat("a", maxLength), } { diff -Nru containerd-1.2.6/image.go containerd-1.5.9/image.go --- containerd-1.2.6/image.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/image.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,17 +18,23 @@ import ( "context" + "encoding/json" "fmt" + "strings" + "sync/atomic" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/diff" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/rootfs" - digest "github.com/opencontainers/go-digest" + "github.com/containerd/containerd/snapshots" + "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" + "golang.org/x/sync/semaphore" ) // Image describes an image used by containers @@ -40,17 +46,64 @@ // Labels of the image Labels() map[string]string // Unpack unpacks the image's content into a snapshot - Unpack(context.Context, string) error + Unpack(context.Context, string, ...UnpackOpt) error // RootFS returns the unpacked diffids that make up images rootfs. RootFS(ctx context.Context) ([]digest.Digest, error) // Size returns the total size of the image's packed resources. Size(ctx context.Context) (int64, error) + // Usage returns a usage calculation for the image. + Usage(context.Context, ...UsageOpt) (int64, error) // Config descriptor for the image. Config(ctx context.Context) (ocispec.Descriptor, error) // IsUnpacked returns whether or not an image is unpacked. IsUnpacked(context.Context, string) (bool, error) // ContentStore provides a content store which contains image blob data ContentStore() content.Store + // Metadata returns the underlying image metadata + Metadata() images.Image +} + +type usageOptions struct { + manifestLimit *int + manifestOnly bool + snapshots bool +} + +// UsageOpt is used to configure the usage calculation +type UsageOpt func(*usageOptions) error + +// WithUsageManifestLimit sets the limit to the number of manifests which will +// be walked for usage. Setting this value to 0 will require all manifests to +// be walked, returning ErrNotFound if manifests are missing. +// NOTE: By default all manifests which exist will be walked +// and any non-existent manifests and their subobjects will be ignored. +func WithUsageManifestLimit(i int) UsageOpt { + // If 0 then don't filter any manifests + // By default limits to current platform + return func(o *usageOptions) error { + o.manifestLimit = &i + return nil + } +} + +// WithSnapshotUsage will check for referenced snapshots from the image objects +// and include the snapshot size in the total usage. +func WithSnapshotUsage() UsageOpt { + return func(o *usageOptions) error { + o.snapshots = true + return nil + } +} + +// WithManifestUsage is used to get the usage for an image based on what is +// reported by the manifests rather than what exists in the content store. +// NOTE: This function is best used with the manifest limit set to get a +// consistent value, otherwise non-existent manifests will be excluded. +func WithManifestUsage() UsageOpt { + return func(o *usageOptions) error { + o.manifestOnly = true + return nil + } } var _ = (Image)(&image{}) @@ -60,7 +113,7 @@ return &image{ client: client, i: i, - platform: platforms.Default(), + platform: client.platform, } } @@ -80,6 +133,10 @@ platform platforms.MatchComparer } +func (i *image) Metadata() images.Image { + return i.i +} + func (i *image) Name() string { return i.i.Name } @@ -98,8 +155,97 @@ } func (i *image) Size(ctx context.Context) (int64, error) { - provider := i.client.ContentStore() - return i.i.Size(ctx, provider, i.platform) + return i.Usage(ctx, WithUsageManifestLimit(1), WithManifestUsage()) +} + +func (i *image) Usage(ctx context.Context, opts ...UsageOpt) (int64, error) { + var config usageOptions + for _, opt := range opts { + if err := opt(&config); err != nil { + return 0, err + } + } + + var ( + provider = i.client.ContentStore() + handler = images.ChildrenHandler(provider) + size int64 + mustExist bool + ) + + if config.manifestLimit != nil { + handler = images.LimitManifests(handler, i.platform, *config.manifestLimit) + mustExist = true + } + + var wh images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + var usage int64 + children, err := handler(ctx, desc) + if err != nil { + if !errdefs.IsNotFound(err) || mustExist { + return nil, err + } + if !config.manifestOnly { + // Do not count size of non-existent objects + desc.Size = 0 + } + } else if config.snapshots || !config.manifestOnly { + info, err := provider.Info(ctx, desc.Digest) + if err != nil { + if !errdefs.IsNotFound(err) { + return nil, err + } + if !config.manifestOnly { + // Do not count size of non-existent objects + desc.Size = 0 + } + } else if info.Size > desc.Size { + // Count actual usage, Size may be unset or -1 + desc.Size = info.Size + } + + if config.snapshots { + for k, v := range info.Labels { + const prefix = "containerd.io/gc.ref.snapshot." + if !strings.HasPrefix(k, prefix) { + continue + } + + sn := i.client.SnapshotService(k[len(prefix):]) + if sn == nil { + continue + } + + u, err := sn.Usage(ctx, v) + if err != nil { + if !errdefs.IsNotFound(err) && !errdefs.IsInvalidArgument(err) { + return nil, err + } + } else { + usage += u.Size + } + } + } + } + + // Ignore unknown sizes. Generally unknown sizes should + // never be set in manifests, however, the usage + // calculation does not need to enforce this. + if desc.Size >= 0 { + usage += desc.Size + } + + atomic.AddInt64(&size, usage) + + return children, nil + } + + l := semaphore.NewWeighted(3) + if err := images.Dispatch(ctx, wh, l, i.i.Target); err != nil { + return 0, err + } + + return size, nil } func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { @@ -108,7 +254,10 @@ } func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) { - sn := i.client.SnapshotService(snapshotterName) + sn, err := i.client.getSnapshotter(ctx, snapshotterName) + if err != nil { + return false, err + } cs := i.client.ContentStore() diffs, err := i.i.RootFS(ctx, cs, i.platform) @@ -127,28 +276,75 @@ return false, nil } -func (i *image) Unpack(ctx context.Context, snapshotterName string) error { +// UnpackConfig provides configuration for the unpack of an image +type UnpackConfig struct { + // ApplyOpts for applying a diff to a snapshotter + ApplyOpts []diff.ApplyOpt + // SnapshotOpts for configuring a snapshotter + SnapshotOpts []snapshots.Opt + // CheckPlatformSupported is whether to validate that a snapshotter + // supports an image's platform before unpacking + CheckPlatformSupported bool +} + +// UnpackOpt provides configuration for unpack +type UnpackOpt func(context.Context, *UnpackConfig) error + +// WithSnapshotterPlatformCheck sets `CheckPlatformSupported` on the UnpackConfig +func WithSnapshotterPlatformCheck() UnpackOpt { + return func(ctx context.Context, uc *UnpackConfig) error { + uc.CheckPlatformSupported = true + return nil + } +} + +func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...UnpackOpt) error { ctx, done, err := i.client.WithLease(ctx) if err != nil { return err } defer done(ctx) - layers, err := i.getLayers(ctx, i.platform) + var config UnpackConfig + for _, o := range opts { + if err := o(ctx, &config); err != nil { + return err + } + } + + manifest, err := i.getManifest(ctx, i.platform) + if err != nil { + return err + } + + layers, err := i.getLayers(ctx, i.platform, manifest) if err != nil { return err } var ( - sn = i.client.SnapshotService(snapshotterName) a = i.client.DiffService() cs = i.client.ContentStore() chain []digest.Digest unpacked bool ) + snapshotterName, err = i.client.resolveSnapshotterName(ctx, snapshotterName) + if err != nil { + return err + } + sn, err := i.client.getSnapshotter(ctx, snapshotterName) + if err != nil { + return err + } + if config.CheckPlatformSupported { + if err := i.checkSnapshotterSupport(ctx, snapshotterName, manifest); err != nil { + return err + } + } + for _, layer := range layers { - unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a) + unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts) if err != nil { return err } @@ -188,14 +384,17 @@ return err } -func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) { - cs := i.client.ContentStore() - +func (i *image) getManifest(ctx context.Context, platform platforms.MatchComparer) (ocispec.Manifest, error) { + cs := i.ContentStore() manifest, err := images.Manifest(ctx, cs, i.i.Target, platform) if err != nil { - return nil, err + return ocispec.Manifest{}, err } + return manifest, nil +} +func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer, manifest ocispec.Manifest) ([]rootfs.Layer, error) { + cs := i.ContentStore() diffIDs, err := i.i.RootFS(ctx, cs, platform) if err != nil { return nil, errors.Wrap(err, "failed to resolve rootfs") @@ -215,6 +414,37 @@ return layers, nil } +func (i *image) getManifestPlatform(ctx context.Context, manifest ocispec.Manifest) (ocispec.Platform, error) { + cs := i.ContentStore() + p, err := content.ReadBlob(ctx, cs, manifest.Config) + if err != nil { + return ocispec.Platform{}, err + } + + var image ocispec.Image + if err := json.Unmarshal(p, &image); err != nil { + return ocispec.Platform{}, err + } + return platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}), nil +} + +func (i *image) checkSnapshotterSupport(ctx context.Context, snapshotterName string, manifest ocispec.Manifest) error { + snapshotterPlatformMatcher, err := i.client.GetSnapshotterSupportedPlatforms(ctx, snapshotterName) + if err != nil { + return err + } + + manifestPlatform, err := i.getManifestPlatform(ctx, manifest) + if err != nil { + return err + } + + if snapshotterPlatformMatcher.Match(manifestPlatform) { + return nil + } + return fmt.Errorf("snapshotter %s does not support platform %s for image %s", snapshotterName, manifestPlatform, manifest.Config.Digest) +} + func (i *image) ContentStore() content.Store { return i.client.ContentStore() } diff -Nru containerd-1.2.6/images/annotations.go containerd-1.5.9/images/annotations.go --- containerd-1.2.6/images/annotations.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/annotations.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +const ( + // AnnotationImageName is an annotation on a Descriptor in an index.json + // containing the `Name` value as used by an `Image` struct + AnnotationImageName = "io.containerd.image.name" +) diff -Nru containerd-1.2.6/images/archive/exporter.go containerd-1.5.9/images/archive/exporter.go --- containerd-1.2.6/images/archive/exporter.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/archive/exporter.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,501 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "archive/tar" + "context" + "encoding/json" + "io" + "path" + "sort" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + digest "github.com/opencontainers/go-digest" + ocispecs "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +type exportOptions struct { + manifests []ocispec.Descriptor + platform platforms.MatchComparer + allPlatforms bool + skipDockerManifest bool + blobRecordOptions blobRecordOptions +} + +// ExportOpt defines options for configuring exported descriptors +type ExportOpt func(context.Context, *exportOptions) error + +// WithPlatform defines the platform to require manifest lists have +// not exporting all platforms. +// Additionally, platform is used to resolve image configs for +// Docker v1.1, v1.2 format compatibility. +func WithPlatform(p platforms.MatchComparer) ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + o.platform = p + return nil + } +} + +// WithAllPlatforms exports all manifests from a manifest list. +// Missing content will fail the export. +func WithAllPlatforms() ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + o.allPlatforms = true + return nil + } +} + +// WithSkipDockerManifest skips creation of the Docker compatible +// manifest.json file. +func WithSkipDockerManifest() ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + o.skipDockerManifest = true + return nil + } +} + +// WithImage adds the provided images to the exported archive. +func WithImage(is images.Store, name string) ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + img, err := is.Get(ctx, name) + if err != nil { + return err + } + + img.Target.Annotations = addNameAnnotation(name, img.Target.Annotations) + o.manifests = append(o.manifests, img.Target) + + return nil + } +} + +// WithManifest adds a manifest to the exported archive. +// When names are given they will be set on the manifest in the +// exported archive, creating an index record for each name. +// When no names are provided, it is up to caller to put name annotation to +// on the manifest descriptor if needed. +func WithManifest(manifest ocispec.Descriptor, names ...string) ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + if len(names) == 0 { + o.manifests = append(o.manifests, manifest) + } + for _, name := range names { + mc := manifest + mc.Annotations = addNameAnnotation(name, manifest.Annotations) + o.manifests = append(o.manifests, mc) + } + + return nil + } +} + +// BlobFilter returns false if the blob should not be included in the archive. +type BlobFilter func(ocispec.Descriptor) bool + +// WithBlobFilter specifies BlobFilter. +func WithBlobFilter(f BlobFilter) ExportOpt { + return func(ctx context.Context, o *exportOptions) error { + o.blobRecordOptions.blobFilter = f + return nil + } +} + +// WithSkipNonDistributableBlobs excludes non-distributable blobs such as Windows base layers. +func WithSkipNonDistributableBlobs() ExportOpt { + f := func(desc ocispec.Descriptor) bool { + return !images.IsNonDistributable(desc.MediaType) + } + return WithBlobFilter(f) +} + +func addNameAnnotation(name string, base map[string]string) map[string]string { + annotations := map[string]string{} + for k, v := range base { + annotations[k] = v + } + + annotations[images.AnnotationImageName] = name + annotations[ocispec.AnnotationRefName] = ociReferenceName(name) + + return annotations +} + +// Export implements Exporter. +func Export(ctx context.Context, store content.Provider, writer io.Writer, opts ...ExportOpt) error { + var eo exportOptions + for _, opt := range opts { + if err := opt(ctx, &eo); err != nil { + return err + } + } + + records := []tarRecord{ + ociLayoutFile(""), + ociIndexRecord(eo.manifests), + } + + algorithms := map[string]struct{}{} + dManifests := map[digest.Digest]*exportManifest{} + resolvedIndex := map[digest.Digest]digest.Digest{} + for _, desc := range eo.manifests { + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + mt, ok := dManifests[desc.Digest] + if !ok { + // TODO(containerd): Skip if already added + r, err := getRecords(ctx, store, desc, algorithms, &eo.blobRecordOptions) + if err != nil { + return err + } + records = append(records, r...) + + mt = &exportManifest{ + manifest: desc, + } + dManifests[desc.Digest] = mt + } + + name := desc.Annotations[images.AnnotationImageName] + if name != "" && !eo.skipDockerManifest { + mt.names = append(mt.names, name) + } + case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + d, ok := resolvedIndex[desc.Digest] + if !ok { + records = append(records, blobRecord(store, desc, &eo.blobRecordOptions)) + + p, err := content.ReadBlob(ctx, store, desc) + if err != nil { + return err + } + + var index ocispec.Index + if err := json.Unmarshal(p, &index); err != nil { + return err + } + + var manifests []ocispec.Descriptor + for _, m := range index.Manifests { + if eo.platform != nil { + if m.Platform == nil || eo.platform.Match(*m.Platform) { + manifests = append(manifests, m) + } else if !eo.allPlatforms { + continue + } + } + + r, err := getRecords(ctx, store, m, algorithms, &eo.blobRecordOptions) + if err != nil { + return err + } + + records = append(records, r...) + } + + if !eo.skipDockerManifest { + if len(manifests) >= 1 { + if len(manifests) > 1 { + sort.SliceStable(manifests, func(i, j int) bool { + if manifests[i].Platform == nil { + return false + } + if manifests[j].Platform == nil { + return true + } + return eo.platform.Less(*manifests[i].Platform, *manifests[j].Platform) + }) + } + d = manifests[0].Digest + dManifests[d] = &exportManifest{ + manifest: manifests[0], + } + } else if eo.platform != nil { + return errors.Wrap(errdefs.ErrNotFound, "no manifest found for platform") + } + } + resolvedIndex[desc.Digest] = d + } + if d != "" { + if name := desc.Annotations[images.AnnotationImageName]; name != "" { + mt := dManifests[d] + mt.names = append(mt.names, name) + } + + } + default: + return errors.Wrap(errdefs.ErrInvalidArgument, "only manifests may be exported") + } + } + + if len(dManifests) > 0 { + tr, err := manifestsRecord(ctx, store, dManifests) + if err != nil { + return errors.Wrap(err, "unable to create manifests file") + } + + records = append(records, tr) + } + + if len(algorithms) > 0 { + records = append(records, directoryRecord("blobs/", 0755)) + for alg := range algorithms { + records = append(records, directoryRecord("blobs/"+alg+"/", 0755)) + } + } + + tw := tar.NewWriter(writer) + defer tw.Close() + return writeTar(ctx, tw, records) +} + +func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descriptor, algorithms map[string]struct{}, brOpts *blobRecordOptions) ([]tarRecord, error) { + var records []tarRecord + exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + records = append(records, blobRecord(store, desc, brOpts)) + algorithms[desc.Digest.Algorithm().String()] = struct{}{} + return nil, nil + } + + childrenHandler := images.ChildrenHandler(store) + + handlers := images.Handlers( + childrenHandler, + images.HandlerFunc(exportHandler), + ) + + // Walk sequentially since the number of fetches is likely one and doing in + // parallel requires locking the export handler + if err := images.Walk(ctx, handlers, desc); err != nil { + return nil, err + } + + return records, nil +} + +type tarRecord struct { + Header *tar.Header + CopyTo func(context.Context, io.Writer) (int64, error) +} + +type blobRecordOptions struct { + blobFilter BlobFilter +} + +func blobRecord(cs content.Provider, desc ocispec.Descriptor, opts *blobRecordOptions) tarRecord { + if opts != nil && opts.blobFilter != nil && !opts.blobFilter(desc) { + return tarRecord{} + } + path := path.Join("blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) + return tarRecord{ + Header: &tar.Header{ + Name: path, + Mode: 0444, + Size: desc.Size, + Typeflag: tar.TypeReg, + }, + CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { + r, err := cs.ReaderAt(ctx, desc) + if err != nil { + return 0, errors.Wrap(err, "failed to get reader") + } + defer r.Close() + + // Verify digest + dgstr := desc.Digest.Algorithm().Digester() + + n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r)) + if err != nil { + return 0, errors.Wrap(err, "failed to copy to tar") + } + if dgstr.Digest() != desc.Digest { + return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest()) + } + return n, nil + }, + } +} + +func directoryRecord(name string, mode int64) tarRecord { + return tarRecord{ + Header: &tar.Header{ + Name: name, + Mode: mode, + Typeflag: tar.TypeDir, + }, + } +} + +func ociLayoutFile(version string) tarRecord { + if version == "" { + version = ocispec.ImageLayoutVersion + } + layout := ocispec.ImageLayout{ + Version: version, + } + + b, err := json.Marshal(layout) + if err != nil { + panic(err) + } + + return tarRecord{ + Header: &tar.Header{ + Name: ocispec.ImageLayoutFile, + Mode: 0444, + Size: int64(len(b)), + Typeflag: tar.TypeReg, + }, + CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { + n, err := w.Write(b) + return int64(n), err + }, + } + +} + +func ociIndexRecord(manifests []ocispec.Descriptor) tarRecord { + index := ocispec.Index{ + Versioned: ocispecs.Versioned{ + SchemaVersion: 2, + }, + Manifests: manifests, + } + + b, err := json.Marshal(index) + if err != nil { + panic(err) + } + + return tarRecord{ + Header: &tar.Header{ + Name: "index.json", + Mode: 0644, + Size: int64(len(b)), + Typeflag: tar.TypeReg, + }, + CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { + n, err := w.Write(b) + return int64(n), err + }, + } +} + +type exportManifest struct { + manifest ocispec.Descriptor + names []string +} + +func manifestsRecord(ctx context.Context, store content.Provider, manifests map[digest.Digest]*exportManifest) (tarRecord, error) { + mfsts := make([]struct { + Config string + RepoTags []string + Layers []string + }, len(manifests)) + + var i int + for _, m := range manifests { + p, err := content.ReadBlob(ctx, store, m.manifest) + if err != nil { + return tarRecord{}, err + } + + var manifest ocispec.Manifest + if err := json.Unmarshal(p, &manifest); err != nil { + return tarRecord{}, err + } + if err := manifest.Config.Digest.Validate(); err != nil { + return tarRecord{}, errors.Wrapf(err, "invalid manifest %q", m.manifest.Digest) + } + + dgst := manifest.Config.Digest + mfsts[i].Config = path.Join("blobs", dgst.Algorithm().String(), dgst.Encoded()) + for _, l := range manifest.Layers { + path := path.Join("blobs", l.Digest.Algorithm().String(), l.Digest.Encoded()) + mfsts[i].Layers = append(mfsts[i].Layers, path) + } + + for _, name := range m.names { + nname, err := familiarizeReference(name) + if err != nil { + return tarRecord{}, err + } + + mfsts[i].RepoTags = append(mfsts[i].RepoTags, nname) + } + + i++ + } + + b, err := json.Marshal(mfsts) + if err != nil { + return tarRecord{}, err + } + + return tarRecord{ + Header: &tar.Header{ + Name: "manifest.json", + Mode: 0644, + Size: int64(len(b)), + Typeflag: tar.TypeReg, + }, + CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { + n, err := w.Write(b) + return int64(n), err + }, + }, nil +} + +func writeTar(ctx context.Context, tw *tar.Writer, recordsWithEmpty []tarRecord) error { + var records []tarRecord + for _, r := range recordsWithEmpty { + if r.Header != nil { + records = append(records, r) + } + } + sort.Slice(records, func(i, j int) bool { + return records[i].Header.Name < records[j].Header.Name + }) + + var last string + for _, record := range records { + if record.Header.Name == last { + continue + } + last = record.Header.Name + if err := tw.WriteHeader(record.Header); err != nil { + return err + } + if record.CopyTo != nil { + n, err := record.CopyTo(ctx, tw) + if err != nil { + return err + } + if n != record.Header.Size { + return errors.Errorf("unexpected copy size for %s", record.Header.Name) + } + } else if record.Header.Size > 0 { + return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name) + } + } + return nil +} diff -Nru containerd-1.2.6/images/archive/importer.go containerd-1.5.9/images/archive/importer.go --- containerd-1.2.6/images/archive/importer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/archive/importer.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,12 +22,14 @@ "bytes" "context" "encoding/json" + "fmt" "io" "io/ioutil" "path" "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" digest "github.com/opencontainers/go-digest" @@ -36,6 +38,22 @@ "github.com/pkg/errors" ) +type importOpts struct { + compress bool +} + +// ImportOpt is an option for importing an OCI index +type ImportOpt func(*importOpts) error + +// WithImportCompression compresses uncompressed layers on import. +// This is used for import formats which do not include the manifest. +func WithImportCompression() ImportOpt { + return func(io *importOpts) error { + io.compress = true + return nil + } +} + // ImportIndex imports an index from a tar archive image bundle // - implements Docker v1.1, v1.2 and OCI v1. // - prefers OCI v1 when provided @@ -43,8 +61,7 @@ // - normalizes Docker references and adds as OCI ref name // e.g. alpine:latest -> docker.io/library/alpine:latest // - existing OCI reference names are untouched -// - TODO: support option to compress layers on ingest -func ImportIndex(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error) { +func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opts ...ImportOpt) (ocispec.Descriptor, error) { var ( tr = tar.NewReader(reader) @@ -56,7 +73,15 @@ } symlinks = make(map[string]string) blobs = make(map[string]ocispec.Descriptor) + iopts importOpts ) + + for _, o := range opts { + if err := o(&iopts); err != nil { + return ocispec.Descriptor{}, err + } + } + for { hdr, err := tr.Next() if err == io.EOF { @@ -99,7 +124,7 @@ } // If OCI layout was given, interpret the tar as an OCI layout. - // When not provided, the layout of the tar will be interpretted + // When not provided, the layout of the tar will be interpreted // as Docker v1.1 or v1.2. if ociLayout.Version != "" { if ociLayout.Version != ocispec.ImageLayoutVersion { @@ -137,22 +162,26 @@ if !ok { return ocispec.Descriptor{}, errors.Errorf("image config %q not found", mfst.Config) } - config.MediaType = ocispec.MediaTypeImageConfig + config.MediaType = images.MediaTypeDockerSchema2Config - layers, err := resolveLayers(ctx, store, mfst.Layers, blobs) + layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress) if err != nil { return ocispec.Descriptor{}, errors.Wrap(err, "failed to resolve layers") } - manifest := ocispec.Manifest{ - Versioned: specs.Versioned{ - SchemaVersion: 2, - }, - Config: config, - Layers: layers, + manifest := struct { + SchemaVersion int `json:"schemaVersion"` + MediaType string `json:"mediaType"` + Config ocispec.Descriptor `json:"config"` + Layers []ocispec.Descriptor `json:"layers"` + }{ + SchemaVersion: 2, + MediaType: images.MediaTypeDockerSchema2Manifest, + Config: config, + Layers: layers, } - desc, err := writeManifest(ctx, store, manifest, ocispec.MediaTypeImageManifest) + desc, err := writeManifest(ctx, store, manifest, manifest.MediaType) if err != nil { return ocispec.Descriptor{}, errors.Wrap(err, "write docker manifest") } @@ -181,7 +210,8 @@ } mfstdesc.Annotations = map[string]string{ - ocispec.AnnotationRefName: normalized, + images.AnnotationImageName: normalized, + ocispec.AnnotationRefName: ociReferenceName(normalized), } idx.Manifests = append(idx.Manifests, mfstdesc) @@ -197,10 +227,7 @@ if err != nil { return err } - if err := json.Unmarshal(b, j); err != nil { - return err - } - return nil + return json.Unmarshal(b, j) } func onUntarBlob(ctx context.Context, r io.Reader, store content.Ingester, size int64, ref string) (digest.Digest, error) { @@ -213,36 +240,118 @@ return dgstr.Digest(), nil } -func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor) ([]ocispec.Descriptor, error) { - var layers []ocispec.Descriptor - for _, f := range layerFiles { +func resolveLayers(ctx context.Context, store content.Store, layerFiles []string, blobs map[string]ocispec.Descriptor, compress bool) ([]ocispec.Descriptor, error) { + layers := make([]ocispec.Descriptor, len(layerFiles)) + descs := map[digest.Digest]*ocispec.Descriptor{} + filters := []string{} + for i, f := range layerFiles { desc, ok := blobs[f] if !ok { return nil, errors.Errorf("layer %q not found", f) } + layers[i] = desc + descs[desc.Digest] = &layers[i] + filters = append(filters, "labels.\"containerd.io/uncompressed\"=="+desc.Digest.String()) + } + + err := store.Walk(ctx, func(info content.Info) error { + dgst, ok := info.Labels["containerd.io/uncompressed"] + if ok { + desc := descs[digest.Digest(dgst)] + if desc != nil { + desc.MediaType = images.MediaTypeDockerSchema2LayerGzip + desc.Digest = info.Digest + desc.Size = info.Size + } + } + return nil + }, filters...) + if err != nil { + return nil, errors.Wrap(err, "failure checking for compressed blobs") + } + for i, desc := range layers { + if desc.MediaType != "" { + continue + } // Open blob, resolve media type ra, err := store.ReaderAt(ctx, desc) if err != nil { - return nil, errors.Wrapf(err, "failed to open %q (%s)", f, desc.Digest) + return nil, errors.Wrapf(err, "failed to open %q (%s)", layerFiles[i], desc.Digest) } s, err := compression.DecompressStream(content.NewReader(ra)) if err != nil { - return nil, errors.Wrapf(err, "failed to detect compression for %q", f) + return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i]) } if s.GetCompression() == compression.Uncompressed { - // TODO: Support compressing and writing back to content store - desc.MediaType = ocispec.MediaTypeImageLayer + if compress { + ref := fmt.Sprintf("compress-blob-%s-%s", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) + labels := map[string]string{ + "containerd.io/uncompressed": desc.Digest.String(), + } + layers[i], err = compressBlob(ctx, store, s, ref, content.WithLabels(labels)) + if err != nil { + s.Close() + return nil, err + } + layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip + } else { + layers[i].MediaType = images.MediaTypeDockerSchema2Layer + } } else { - desc.MediaType = ocispec.MediaTypeImageLayerGzip + layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip } s.Close() - layers = append(layers, desc) } return layers, nil } +func compressBlob(ctx context.Context, cs content.Store, r io.Reader, ref string, opts ...content.Opt) (desc ocispec.Descriptor, err error) { + w, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) + if err != nil { + return ocispec.Descriptor{}, errors.Wrap(err, "failed to open writer") + } + + defer func() { + w.Close() + if err != nil { + cs.Abort(ctx, ref) + } + }() + if err := w.Truncate(0); err != nil { + return ocispec.Descriptor{}, errors.Wrap(err, "failed to truncate writer") + } + + cw, err := compression.CompressStream(w, compression.Gzip) + if err != nil { + return ocispec.Descriptor{}, err + } + + if _, err := io.Copy(cw, r); err != nil { + return ocispec.Descriptor{}, err + } + if err := cw.Close(); err != nil { + return ocispec.Descriptor{}, err + } + + cst, err := w.Status() + if err != nil { + return ocispec.Descriptor{}, errors.Wrap(err, "failed to get writer status") + } + + desc.Digest = w.Digest() + desc.Size = cst.Offset + + if err := w.Commit(ctx, desc.Size, desc.Digest, opts...); err != nil { + if !errdefs.IsAlreadyExists(err) { + return ocispec.Descriptor{}, errors.Wrap(err, "failed to commit") + } + } + + return desc, nil +} + func writeManifest(ctx context.Context, cs content.Ingester, manifest interface{}, mediaType string) (ocispec.Descriptor, error) { manifestBytes, err := json.Marshal(manifest) if err != nil { diff -Nru containerd-1.2.6/images/archive/reference.go containerd-1.5.9/images/archive/reference.go --- containerd-1.2.6/images/archive/reference.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/archive/reference.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,8 @@ import ( "strings" - "github.com/docker/distribution/reference" + "github.com/containerd/containerd/reference" + distref "github.com/containerd/containerd/reference/docker" "github.com/opencontainers/go-digest" "github.com/pkg/errors" ) @@ -69,7 +70,7 @@ func normalizeReference(ref string) (string, error) { // TODO: Replace this function to not depend on reference package - normalized, err := reference.ParseDockerRef(ref) + normalized, err := distref.ParseDockerRef(ref) if err != nil { return "", errors.Wrapf(err, "normalize image ref %q", ref) } @@ -77,6 +78,31 @@ return normalized.String(), nil } +func familiarizeReference(ref string) (string, error) { + named, err := distref.ParseNormalizedNamed(ref) + if err != nil { + return "", errors.Wrapf(err, "failed to parse %q", ref) + } + named = distref.TagNameOnly(named) + + return distref.FamiliarString(named), nil +} + +func ociReferenceName(name string) string { + // OCI defines the reference name as only a tag excluding the + // repository. The containerd annotation contains the full image name + // since the tag is insufficient for correctly naming and referring to an + // image + var ociRef string + if spec, err := reference.Parse(name); err == nil { + ociRef = spec.Object + } else { + ociRef = name + } + + return ociRef +} + // DigestTranslator creates a digest reference by adding the // digest to an image name func DigestTranslator(prefix string) func(digest.Digest) string { diff -Nru containerd-1.2.6/images/converter/converter.go containerd-1.5.9/images/converter/converter.go --- containerd-1.2.6/images/converter/converter.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/converter/converter.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,126 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package converter provides image converter +package converter + +import ( + "context" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/platforms" +) + +type convertOpts struct { + layerConvertFunc ConvertFunc + docker2oci bool + indexConvertFunc ConvertFunc + platformMC platforms.MatchComparer +} + +// Opt is an option for Convert() +type Opt func(*convertOpts) error + +// WithLayerConvertFunc specifies the function that converts layers. +func WithLayerConvertFunc(fn ConvertFunc) Opt { + return func(copts *convertOpts) error { + copts.layerConvertFunc = fn + return nil + } +} + +// WithDockerToOCI converts Docker media types into OCI ones. +func WithDockerToOCI(v bool) Opt { + return func(copts *convertOpts) error { + copts.docker2oci = true + return nil + } +} + +// WithPlatform specifies the platform. +// Defaults to all platforms. +func WithPlatform(p platforms.MatchComparer) Opt { + return func(copts *convertOpts) error { + copts.platformMC = p + return nil + } +} + +// WithIndexConvertFunc specifies the function that converts manifests and index (manifest lists). +// Defaults to DefaultIndexConvertFunc. +func WithIndexConvertFunc(fn ConvertFunc) Opt { + return func(copts *convertOpts) error { + copts.indexConvertFunc = fn + return nil + } +} + +// Client is implemented by *containerd.Client . +type Client interface { + WithLease(ctx context.Context, opts ...leases.Opt) (context.Context, func(context.Context) error, error) + ContentStore() content.Store + ImageService() images.Store +} + +// Convert converts an image. +func Convert(ctx context.Context, client Client, dstRef, srcRef string, opts ...Opt) (*images.Image, error) { + var copts convertOpts + for _, o := range opts { + if err := o(&copts); err != nil { + return nil, err + } + } + if copts.platformMC == nil { + copts.platformMC = platforms.All + } + if copts.indexConvertFunc == nil { + copts.indexConvertFunc = DefaultIndexConvertFunc(copts.layerConvertFunc, copts.docker2oci, copts.platformMC) + } + + ctx, done, err := client.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + cs := client.ContentStore() + is := client.ImageService() + srcImg, err := is.Get(ctx, srcRef) + if err != nil { + return nil, err + } + + dstDesc, err := copts.indexConvertFunc(ctx, cs, srcImg.Target) + if err != nil { + return nil, err + } + + dstImg := srcImg + dstImg.Name = dstRef + if dstDesc != nil { + dstImg.Target = *dstDesc + } + var res images.Image + if dstRef != srcRef { + _ = is.Delete(ctx, dstRef) + res, err = is.Create(ctx, dstImg) + } else { + res, err = is.Update(ctx, dstImg) + } + return &res, err +} diff -Nru containerd-1.2.6/images/converter/default.go containerd-1.5.9/images/converter/default.go --- containerd-1.2.6/images/converter/default.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/converter/default.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,440 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package converter + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "strings" + "sync" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" +) + +// ConvertFunc returns a converted content descriptor. +// When the content was not converted, ConvertFunc returns nil. +type ConvertFunc func(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) + +// DefaultIndexConvertFunc is the default convert func used by Convert. +func DefaultIndexConvertFunc(layerConvertFunc ConvertFunc, docker2oci bool, platformMC platforms.MatchComparer) ConvertFunc { + c := &defaultConverter{ + layerConvertFunc: layerConvertFunc, + docker2oci: docker2oci, + platformMC: platformMC, + diffIDMap: make(map[digest.Digest]digest.Digest), + } + return c.convert +} + +type defaultConverter struct { + layerConvertFunc ConvertFunc + docker2oci bool + platformMC platforms.MatchComparer + diffIDMap map[digest.Digest]digest.Digest // key: old diffID, value: new diffID + diffIDMapMu sync.RWMutex +} + +// convert dispatches desc.MediaType and calls c.convert{Layer,Manifest,Index,Config}. +// +// Also converts media type if c.docker2oci is set. +func (c *defaultConverter) convert(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + var ( + newDesc *ocispec.Descriptor + err error + ) + if images.IsLayerType(desc.MediaType) { + newDesc, err = c.convertLayer(ctx, cs, desc) + } else if images.IsManifestType(desc.MediaType) { + newDesc, err = c.convertManifest(ctx, cs, desc) + } else if images.IsIndexType(desc.MediaType) { + newDesc, err = c.convertIndex(ctx, cs, desc) + } else if images.IsConfigType(desc.MediaType) { + newDesc, err = c.convertConfig(ctx, cs, desc) + } + if err != nil { + return nil, err + } + if images.IsDockerType(desc.MediaType) { + if c.docker2oci { + if newDesc == nil { + newDesc = copyDesc(desc) + } + newDesc.MediaType = ConvertDockerMediaTypeToOCI(newDesc.MediaType) + } else if (newDesc == nil && len(desc.Annotations) != 0) || (newDesc != nil && len(newDesc.Annotations) != 0) { + // Annotations is supported only on OCI manifest. + // We need to remove annotations for Docker media types. + if newDesc == nil { + newDesc = copyDesc(desc) + } + newDesc.Annotations = nil + } + } + logrus.WithField("old", desc).WithField("new", newDesc).Debugf("converted") + return newDesc, nil +} + +func copyDesc(desc ocispec.Descriptor) *ocispec.Descriptor { + descCopy := desc + return &descCopy +} + +// convertLayer converts image image layers if c.layerConvertFunc is set. +// +// c.layerConvertFunc can be nil, e.g., for converting Docker media types to OCI ones. +func (c *defaultConverter) convertLayer(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + if c.layerConvertFunc != nil { + return c.layerConvertFunc(ctx, cs, desc) + } + return nil, nil +} + +// convertManifest converts image manifests. +// +// - converts `.mediaType` if the target format is OCI +// - records diff ID changes in c.diffIDMap +func (c *defaultConverter) convertManifest(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + var ( + manifest ocispec.Manifest + modified bool + ) + labels, err := readJSON(ctx, cs, &manifest, desc) + if err != nil { + return nil, err + } + if labels == nil { + labels = make(map[string]string) + } + if images.IsDockerType(manifest.MediaType) && c.docker2oci { + manifest.MediaType = ConvertDockerMediaTypeToOCI(manifest.MediaType) + modified = true + } + var mu sync.Mutex + eg, ctx2 := errgroup.WithContext(ctx) + for i, l := range manifest.Layers { + i := i + l := l + oldDiffID, err := images.GetDiffID(ctx, cs, l) + if err != nil { + return nil, err + } + eg.Go(func() error { + newL, err := c.convert(ctx2, cs, l) + if err != nil { + return err + } + if newL != nil { + mu.Lock() + // update GC labels + ClearGCLabels(labels, l.Digest) + labelKey := fmt.Sprintf("containerd.io/gc.ref.content.l.%d", i) + labels[labelKey] = newL.Digest.String() + manifest.Layers[i] = *newL + modified = true + mu.Unlock() + + // diffID changes if the tar entries were modified. + // diffID stays same if only the compression type was changed. + // When diffID changed, add a map entry so that we can update image config. + newDiffID, err := images.GetDiffID(ctx, cs, *newL) + if err != nil { + return err + } + if newDiffID != oldDiffID { + c.diffIDMapMu.Lock() + c.diffIDMap[oldDiffID] = newDiffID + c.diffIDMapMu.Unlock() + } + } + return nil + }) + } + if err := eg.Wait(); err != nil { + return nil, err + } + + newConfig, err := c.convert(ctx, cs, manifest.Config) + if err != nil { + return nil, err + } + if newConfig != nil { + ClearGCLabels(labels, manifest.Config.Digest) + labels["containerd.io/gc.ref.content.config"] = newConfig.Digest.String() + manifest.Config = *newConfig + modified = true + } + + if modified { + return writeJSON(ctx, cs, &manifest, desc, labels) + } + return nil, nil +} + +// convertIndex converts image index. +// +// - converts `.mediaType` if the target format is OCI +// - clears manifest entries that do not match c.platformMC +func (c *defaultConverter) convertIndex(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + var ( + index ocispec.Index + modified bool + ) + labels, err := readJSON(ctx, cs, &index, desc) + if err != nil { + return nil, err + } + if labels == nil { + labels = make(map[string]string) + } + if images.IsDockerType(index.MediaType) && c.docker2oci { + index.MediaType = ConvertDockerMediaTypeToOCI(index.MediaType) + modified = true + } + + newManifests := make([]ocispec.Descriptor, len(index.Manifests)) + newManifestsToBeRemoved := make(map[int]struct{}) // slice index + var mu sync.Mutex + eg, ctx2 := errgroup.WithContext(ctx) + for i, mani := range index.Manifests { + i := i + mani := mani + labelKey := fmt.Sprintf("containerd.io/gc.ref.content.m.%d", i) + eg.Go(func() error { + if mani.Platform != nil && !c.platformMC.Match(*mani.Platform) { + mu.Lock() + ClearGCLabels(labels, mani.Digest) + newManifestsToBeRemoved[i] = struct{}{} + modified = true + mu.Unlock() + return nil + } + newMani, err := c.convert(ctx2, cs, mani) + if err != nil { + return err + } + mu.Lock() + if newMani != nil { + ClearGCLabels(labels, mani.Digest) + labels[labelKey] = newMani.Digest.String() + // NOTE: for keeping manifest order, we specify `i` index explicitly + newManifests[i] = *newMani + modified = true + } else { + newManifests[i] = mani + } + mu.Unlock() + return nil + }) + } + if err := eg.Wait(); err != nil { + return nil, err + } + if modified { + var newManifestsClean []ocispec.Descriptor + for i, m := range newManifests { + if _, ok := newManifestsToBeRemoved[i]; !ok { + newManifestsClean = append(newManifestsClean, m) + } + } + index.Manifests = newManifestsClean + return writeJSON(ctx, cs, &index, desc, labels) + } + return nil, nil +} + +// convertConfig converts image config contents. +// +// - updates `.rootfs.diff_ids` using c.diffIDMap . +// +// - clears legacy `.config.Image` and `.container_config.Image` fields if `.rootfs.diff_ids` was updated. +func (c *defaultConverter) convertConfig(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + var ( + cfg DualConfig + cfgAsOCI ocispec.Image // read only, used for parsing cfg + modified bool + ) + + labels, err := readJSON(ctx, cs, &cfg, desc) + if err != nil { + return nil, err + } + if labels == nil { + labels = make(map[string]string) + } + if _, err := readJSON(ctx, cs, &cfgAsOCI, desc); err != nil { + return nil, err + } + + if rootfs := cfgAsOCI.RootFS; rootfs.Type == "layers" { + rootfsModified := false + c.diffIDMapMu.RLock() + for i, oldDiffID := range rootfs.DiffIDs { + if newDiffID, ok := c.diffIDMap[oldDiffID]; ok && newDiffID != oldDiffID { + rootfs.DiffIDs[i] = newDiffID + rootfsModified = true + } + } + c.diffIDMapMu.RUnlock() + if rootfsModified { + rootfsB, err := json.Marshal(rootfs) + if err != nil { + return nil, err + } + cfg["rootfs"] = (*json.RawMessage)(&rootfsB) + modified = true + } + } + + if modified { + // cfg may have dummy value for legacy `.config.Image` and `.container_config.Image` + // We should clear the ID if we changed the diff IDs. + if _, err := clearDockerV1DummyID(cfg); err != nil { + return nil, err + } + return writeJSON(ctx, cs, &cfg, desc, labels) + } + return nil, nil +} + +// clearDockerV1DummyID clears the dummy values for legacy `.config.Image` and `.container_config.Image`. +// Returns true if the cfg was modified. +func clearDockerV1DummyID(cfg DualConfig) (bool, error) { + var modified bool + f := func(k string) error { + if configX, ok := cfg[k]; ok && configX != nil { + var configField map[string]*json.RawMessage + if err := json.Unmarshal(*configX, &configField); err != nil { + return err + } + delete(configField, "Image") + b, err := json.Marshal(configField) + if err != nil { + return err + } + cfg[k] = (*json.RawMessage)(&b) + modified = true + } + return nil + } + if err := f("config"); err != nil { + return modified, err + } + if err := f("container_config"); err != nil { + return modified, err + } + return modified, nil +} + +// ObjectWithMediaType represents an object with a MediaType field +// Deprecated +type ObjectWithMediaType struct { + // MediaType appears on Docker manifests and manifest lists. + MediaType string `json:"mediaType,omitempty"` +} + +// DualManifest covers Docker manifest and OCI manifest +// Deprecated: use github.com/opencontainers/image-spec/specs-go/v1.Manifest +type DualManifest struct { + ocispec.Manifest +} + +// DualIndex covers Docker manifest list and OCI index +// Deprecated: use github.com/opencontainers/image-spec/specs-go/v1.Index +type DualIndex struct { + ocispec.Index +} + +// DualConfig covers Docker config (v1.0, v1.1, v1.2) and OCI config. +// Unmarshalled as map[string]*json.RawMessage to retain unknown fields on remarshalling. +type DualConfig map[string]*json.RawMessage + +func readJSON(ctx context.Context, cs content.Store, x interface{}, desc ocispec.Descriptor) (map[string]string, error) { + info, err := cs.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + labels := info.Labels + b, err := content.ReadBlob(ctx, cs, desc) + if err != nil { + return nil, err + } + if err := json.Unmarshal(b, x); err != nil { + return nil, err + } + return labels, nil +} + +func writeJSON(ctx context.Context, cs content.Store, x interface{}, oldDesc ocispec.Descriptor, labels map[string]string) (*ocispec.Descriptor, error) { + b, err := json.Marshal(x) + if err != nil { + return nil, err + } + dgst := digest.SHA256.FromBytes(b) + ref := fmt.Sprintf("converter-write-json-%s", dgst.String()) + w, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) + if err != nil { + return nil, err + } + if err := content.Copy(ctx, w, bytes.NewReader(b), int64(len(b)), dgst, content.WithLabels(labels)); err != nil { + return nil, err + } + if err := w.Close(); err != nil { + return nil, err + } + newDesc := oldDesc + newDesc.Size = int64(len(b)) + newDesc.Digest = dgst + return &newDesc, nil +} + +// ConvertDockerMediaTypeToOCI converts a media type string +func ConvertDockerMediaTypeToOCI(mt string) string { + switch mt { + case images.MediaTypeDockerSchema2ManifestList: + return ocispec.MediaTypeImageIndex + case images.MediaTypeDockerSchema2Manifest: + return ocispec.MediaTypeImageManifest + case images.MediaTypeDockerSchema2LayerGzip: + return ocispec.MediaTypeImageLayerGzip + case images.MediaTypeDockerSchema2LayerForeignGzip: + return ocispec.MediaTypeImageLayerNonDistributableGzip + case images.MediaTypeDockerSchema2Layer: + return ocispec.MediaTypeImageLayer + case images.MediaTypeDockerSchema2LayerForeign: + return ocispec.MediaTypeImageLayerNonDistributable + case images.MediaTypeDockerSchema2Config: + return ocispec.MediaTypeImageConfig + default: + return mt + } +} + +// ClearGCLabels clears GC labels for the given digest. +func ClearGCLabels(labels map[string]string, dgst digest.Digest) { + for k, v := range labels { + if v == dgst.String() && strings.HasPrefix(k, "containerd.io/gc.ref.content") { + delete(labels, k) + } + } +} diff -Nru containerd-1.2.6/images/converter/uncompress/uncompress.go containerd-1.5.9/images/converter/uncompress/uncompress.go --- containerd-1.2.6/images/converter/uncompress/uncompress.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/converter/uncompress/uncompress.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,122 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package uncompress + +import ( + "compress/gzip" + "context" + "fmt" + "io" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/images/converter" + "github.com/containerd/containerd/labels" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +var _ converter.ConvertFunc = LayerConvertFunc + +// LayerConvertFunc converts tar.gz layers into uncompressed tar layers. +// Media type is changed, e.g., "application/vnd.oci.image.layer.v1.tar+gzip" -> "application/vnd.oci.image.layer.v1.tar" +func LayerConvertFunc(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { + if !images.IsLayerType(desc.MediaType) || IsUncompressedType(desc.MediaType) { + // No conversion. No need to return an error here. + return nil, nil + } + info, err := cs.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + readerAt, err := cs.ReaderAt(ctx, desc) + if err != nil { + return nil, err + } + defer readerAt.Close() + sr := io.NewSectionReader(readerAt, 0, desc.Size) + newR, err := gzip.NewReader(sr) + if err != nil { + return nil, err + } + defer newR.Close() + ref := fmt.Sprintf("convert-uncompress-from-%s", desc.Digest) + w, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) + if err != nil { + return nil, err + } + defer w.Close() + + // Reset the writing position + // Old writer possibly remains without aborted + // (e.g. conversion interrupted by a signal) + if err := w.Truncate(0); err != nil { + return nil, err + } + + n, err := io.Copy(w, newR) + if err != nil { + return nil, err + } + if err := newR.Close(); err != nil { + return nil, err + } + // no need to retain "containerd.io/uncompressed" label, but retain other labels ("containerd.io/distribution.source.*") + labelsMap := info.Labels + delete(labelsMap, labels.LabelUncompressed) + if err = w.Commit(ctx, 0, "", content.WithLabels(labelsMap)); err != nil && !errdefs.IsAlreadyExists(err) { + return nil, err + } + if err := w.Close(); err != nil { + return nil, err + } + newDesc := desc + newDesc.Digest = w.Digest() + newDesc.Size = n + newDesc.MediaType = convertMediaType(newDesc.MediaType) + return &newDesc, nil +} + +// IsUncompressedType returns whether the provided media type is considered +// an uncompressed layer type +func IsUncompressedType(mt string) bool { + switch mt { + case + images.MediaTypeDockerSchema2Layer, + images.MediaTypeDockerSchema2LayerForeign, + ocispec.MediaTypeImageLayer, + ocispec.MediaTypeImageLayerNonDistributable: + return true + default: + return false + } +} + +func convertMediaType(mt string) string { + switch mt { + case images.MediaTypeDockerSchema2LayerGzip: + return images.MediaTypeDockerSchema2Layer + case images.MediaTypeDockerSchema2LayerForeignGzip: + return images.MediaTypeDockerSchema2LayerForeign + case ocispec.MediaTypeImageLayerGzip: + return ocispec.MediaTypeImageLayer + case ocispec.MediaTypeImageLayerNonDistributableGzip: + return ocispec.MediaTypeImageLayerNonDistributable + default: + return mt + } +} diff -Nru containerd-1.2.6/images/diffid.go containerd-1.5.9/images/diffid.go --- containerd-1.2.6/images/diffid.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/diffid.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "context" + "io" + + "github.com/containerd/containerd/archive/compression" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/labels" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sirupsen/logrus" +) + +// GetDiffID gets the diff ID of the layer blob descriptor. +func GetDiffID(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (digest.Digest, error) { + switch desc.MediaType { + case + // If the layer is already uncompressed, we can just return its digest + MediaTypeDockerSchema2Layer, + ocispec.MediaTypeImageLayer, + MediaTypeDockerSchema2LayerForeign, + ocispec.MediaTypeImageLayerNonDistributable: + return desc.Digest, nil + } + info, err := cs.Info(ctx, desc.Digest) + if err != nil { + return "", err + } + v, ok := info.Labels[labels.LabelUncompressed] + if ok { + // Fast path: if the image is already unpacked, we can use the label value + return digest.Parse(v) + } + // if the image is not unpacked, we may not have the label + ra, err := cs.ReaderAt(ctx, desc) + if err != nil { + return "", err + } + defer ra.Close() + r := content.NewReader(ra) + uR, err := compression.DecompressStream(r) + if err != nil { + return "", err + } + defer uR.Close() + digester := digest.Canonical.Digester() + hashW := digester.Hash() + if _, err := io.Copy(hashW, uR); err != nil { + return "", err + } + if err := ra.Close(); err != nil { + return "", err + } + digest := digester.Digest() + // memorize the computed value + if info.Labels == nil { + info.Labels = make(map[string]string) + } + info.Labels[labels.LabelUncompressed] = digest.String() + if _, err := cs.Update(ctx, info, "labels"); err != nil { + logrus.WithError(err).Warnf("failed to set %s label for %s", labels.LabelUncompressed, desc.Digest) + } + return digest, nil +} diff -Nru containerd-1.2.6/images/handlers.go containerd-1.5.9/images/handlers.go --- containerd-1.2.6/images/handlers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/handlers.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,10 +22,12 @@ "sort" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/platforms" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" + "golang.org/x/sync/semaphore" ) var ( @@ -62,7 +64,7 @@ for _, handler := range handlers { ch, err := handler.Handle(ctx, desc) if err != nil { - if errors.Cause(err) == ErrStopHandler { + if errors.Is(err, ErrStopHandler) { break } return nil, err @@ -85,7 +87,7 @@ children, err := handler.Handle(ctx, desc) if err != nil { - if errors.Cause(err) == ErrSkipDesc { + if errors.Is(err, ErrSkipDesc) { continue // don't traverse the children. } return err @@ -108,28 +110,40 @@ // handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse // any children. // +// A concurrency limiter can be passed in to limit the number of concurrent +// handlers running. When limiter is nil, there is no limit. +// // Typically, this function will be used with `FetchHandler`, often composed // with other handlers. // // If any handler returns an error, the dispatch session will be canceled. -func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error { - eg, ctx := errgroup.WithContext(ctx) +func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error { + eg, ctx2 := errgroup.WithContext(ctx) for _, desc := range descs { desc := desc + if limiter != nil { + if err := limiter.Acquire(ctx, 1); err != nil { + return err + } + } + eg.Go(func() error { desc := desc - children, err := handler.Handle(ctx, desc) + children, err := handler.Handle(ctx2, desc) + if limiter != nil { + limiter.Release(1) + } if err != nil { - if errors.Cause(err) == ErrSkipDesc { + if errors.Is(err, ErrSkipDesc) { return nil // don't traverse the children. } return err } if len(children) > 0 { - return Dispatch(ctx, handler, children...) + return Dispatch(ctx2, handler, limiter, children...) } return nil @@ -156,6 +170,19 @@ // the children returned by the handler and passes through the children. // Must follow a handler that returns the children to be labeled. func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc { + return SetChildrenMappedLabels(manager, f, nil) +} + +// SetChildrenMappedLabels is a handler wrapper which sets labels for the content on +// the children returned by the handler and passes through the children. +// Must follow a handler that returns the children to be labeled. +// The label map allows the caller to control the labels per child descriptor. +// For returned labels, the index of the child will be appended to the end +// except for the first index when the returned label does not end with '.'. +func SetChildrenMappedLabels(manager content.Manager, f HandlerFunc, labelMap func(ocispec.Descriptor) []string) HandlerFunc { + if labelMap == nil { + labelMap = ChildGCLabels + } return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { children, err := f(ctx, desc) if err != nil { @@ -163,14 +190,26 @@ } if len(children) > 0 { - info := content.Info{ - Digest: desc.Digest, - Labels: map[string]string{}, - } - fields := []string{} - for i, ch := range children { - info.Labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = ch.Digest.String() - fields = append(fields, fmt.Sprintf("labels.containerd.io/gc.ref.content.%d", i)) + var ( + info = content.Info{ + Digest: desc.Digest, + Labels: map[string]string{}, + } + fields = []string{} + keys = map[string]uint{} + ) + for _, ch := range children { + labelKeys := labelMap(ch) + for _, key := range labelKeys { + idx := keys[key] + keys[key] = idx + 1 + if idx > 0 || key[len(key)-1] == '.' { + key = fmt.Sprintf("%s%d", key, idx) + } + + info.Labels[key] = ch.Digest.String() + fields = append(fields, "labels."+key) + } } _, err := manager.Update(ctx, info, fields...) @@ -213,6 +252,7 @@ // The results will be ordered according to the comparison operator and // use the ordering in the manifests for equal matches. // A limit of 0 or less is considered no limit. +// A not found error is returned if no manifest is matched. func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { children, err := f(ctx, desc) @@ -232,8 +272,13 @@ return m.Less(*children[i].Platform, *children[j].Platform) }) - if n > 0 && len(children) > n { - children = children[:n] + if n > 0 { + if len(children) == 0 { + return children, errors.Wrap(errdefs.ErrNotFound, "no match for platform in manifest") + } + if len(children) > n { + children = children[:n] + } } default: // only limit manifests from an index diff -Nru containerd-1.2.6/images/image.go containerd-1.5.9/images/image.go --- containerd-1.2.6/images/image.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/image.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,8 +19,8 @@ import ( "context" "encoding/json" + "fmt" "sort" - "strings" "time" "github.com/containerd/containerd/content" @@ -119,7 +119,7 @@ } size += desc.Size return nil, nil - }), FilterPlatforms(ChildrenHandler(provider), platform)), image.Target) + }), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target) } type platformManifest struct { @@ -142,6 +142,7 @@ // this direction because this abstraction is not needed.` func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) { var ( + limit = 1 m []platformManifest wasIndex bool ) @@ -154,6 +155,10 @@ return nil, err } + if err := validateMediaType(p, desc.MediaType); err != nil { + return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest) + } + var manifest ocispec.Manifest if err := json.Unmarshal(p, &manifest); err != nil { return nil, err @@ -194,6 +199,10 @@ return nil, err } + if err := validateMediaType(p, desc.MediaType); err != nil { + return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest) + } + var idx ocispec.Index if err := json.Unmarshal(p, &idx); err != nil { return nil, err @@ -210,10 +219,22 @@ } } + sort.SliceStable(descs, func(i, j int) bool { + if descs[i].Platform == nil { + return false + } + if descs[j].Platform == nil { + return true + } + return platform.Less(*descs[i].Platform, *descs[j].Platform) + }) + wasIndex = true + if len(descs) > limit { + return descs[:limit], nil + } return descs, nil - } return nil, errors.Wrapf(errdefs.ErrNotFound, "unexpected media type %v for %v", desc.MediaType, desc.Digest) }), image); err != nil { @@ -227,17 +248,6 @@ } return ocispec.Manifest{}, err } - - sort.SliceStable(m, func(i, j int) bool { - if m[i].p == nil { - return false - } - if m[j].p == nil { - return true - } - return platform.Less(*m[i].p, *m[j].p) - }) - return *m[0].m, nil } @@ -288,7 +298,7 @@ // If available is true, the caller can assume that required represents the // complete set of content required for the image. // -// missing will have the components that are part of required but not avaiiable +// missing will have the components that are part of required but not available // in the provider. // // If there is a problem resolving content, an error will be returned. @@ -335,6 +345,10 @@ return nil, err } + if err := validateMediaType(p, desc.MediaType); err != nil { + return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest) + } + // TODO(stevvooe): We just assume oci manifest, for now. There may be // subtle differences from the docker version. var manifest ocispec.Manifest @@ -350,27 +364,65 @@ return nil, err } + if err := validateMediaType(p, desc.MediaType); err != nil { + return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest) + } + var index ocispec.Index if err := json.Unmarshal(p, &index); err != nil { return nil, err } descs = append(descs, index.Manifests...) - case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, - MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip, - MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig, - ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip, - ocispec.MediaTypeImageLayerNonDistributable, ocispec.MediaTypeImageLayerNonDistributableGzip, - MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig: - // childless data types. - return nil, nil default: - log.G(ctx).Warnf("encountered unknown type %v; children may not be fetched", desc.MediaType) + if IsLayerType(desc.MediaType) || IsKnownConfig(desc.MediaType) { + // childless data types. + return nil, nil + } + log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType) } return descs, nil } +// unknownDocument represents a manifest, manifest list, or index that has not +// yet been validated. +type unknownDocument struct { + MediaType string `json:"mediaType,omitempty"` + Config json.RawMessage `json:"config,omitempty"` + Layers json.RawMessage `json:"layers,omitempty"` + Manifests json.RawMessage `json:"manifests,omitempty"` + FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1 +} + +// validateMediaType returns an error if the byte slice is invalid JSON or if +// the media type identifies the blob as one format but it contains elements of +// another format. +func validateMediaType(b []byte, mt string) error { + var doc unknownDocument + if err := json.Unmarshal(b, &doc); err != nil { + return err + } + if len(doc.FSLayers) != 0 { + return fmt.Errorf("media-type: schema 1 not supported") + } + switch mt { + case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + if len(doc.Manifests) != 0 || + doc.MediaType == MediaTypeDockerSchema2ManifestList || + doc.MediaType == ocispec.MediaTypeImageIndex { + return fmt.Errorf("media-type: expected manifest but found index (%s)", mt) + } + case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + if len(doc.Config) != 0 || len(doc.Layers) != 0 || + doc.MediaType == MediaTypeDockerSchema2Manifest || + doc.MediaType == ocispec.MediaTypeImageManifest { + return fmt.Errorf("media-type: expected index but found manifest (%s)", mt) + } + } + return nil +} + // RootFS returns the unpacked diffids that make up and images rootfs. // // These are used to verify that a set of layers unpacked to the expected @@ -387,22 +439,3 @@ } return config.RootFS.DiffIDs, nil } - -// IsCompressedDiff returns true if mediaType is a known compressed diff media type. -// It returns false if the media type is a diff, but not compressed. If the media type -// is not a known diff type, it returns errdefs.ErrNotImplemented -func IsCompressedDiff(ctx context.Context, mediaType string) (bool, error) { - switch mediaType { - case ocispec.MediaTypeImageLayer, MediaTypeDockerSchema2Layer: - case ocispec.MediaTypeImageLayerGzip, MediaTypeDockerSchema2LayerGzip: - return true, nil - default: - // Still apply all generic media types *.tar[.+]gzip and *.tar - if strings.HasSuffix(mediaType, ".tar.gzip") || strings.HasSuffix(mediaType, ".tar+gzip") { - return true, nil - } else if !strings.HasSuffix(mediaType, ".tar") { - return false, errdefs.ErrNotImplemented - } - } - return false, nil -} diff -Nru containerd-1.2.6/images/image_test.go containerd-1.5.9/images/image_test.go --- containerd-1.2.6/images/image_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/images/image_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,127 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package images + +import ( + "encoding/json" + "testing" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateMediaType(t *testing.T) { + docTests := []struct { + mt string + index bool + }{ + {MediaTypeDockerSchema2Manifest, false}, + {ocispec.MediaTypeImageManifest, false}, + {MediaTypeDockerSchema2ManifestList, true}, + {ocispec.MediaTypeImageIndex, true}, + } + for _, tc := range docTests { + t.Run("manifest-"+tc.mt, func(t *testing.T) { + manifest := ocispec.Manifest{ + Config: ocispec.Descriptor{Size: 1}, + Layers: []ocispec.Descriptor{{Size: 2}}, + } + b, err := json.Marshal(manifest) + require.NoError(t, err, "failed to marshal manifest") + + err = validateMediaType(b, tc.mt) + if tc.index { + assert.Error(t, err, "manifest should not be a valid index") + } else { + assert.NoError(t, err, "manifest should be valid") + } + }) + t.Run("index-"+tc.mt, func(t *testing.T) { + index := ocispec.Index{ + Manifests: []ocispec.Descriptor{{Size: 1}}, + } + b, err := json.Marshal(index) + require.NoError(t, err, "failed to marshal index") + + err = validateMediaType(b, tc.mt) + if tc.index { + assert.NoError(t, err, "index should be valid") + } else { + assert.Error(t, err, "index should not be a valid manifest") + } + }) + } + + mtTests := []struct { + mt string + valid []string + invalid []string + }{{ + MediaTypeDockerSchema2Manifest, + []string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest}, + []string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex}, + }, { + ocispec.MediaTypeImageManifest, + []string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest}, + []string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex}, + }, { + MediaTypeDockerSchema2ManifestList, + []string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex}, + []string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest}, + }, { + ocispec.MediaTypeImageIndex, + []string{MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex}, + []string{MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest}, + }} + for _, tc := range mtTests { + for _, v := range tc.valid { + t.Run("valid-"+tc.mt+"-"+v, func(t *testing.T) { + doc := struct { + MediaType string `json:"mediaType"` + }{MediaType: v} + b, err := json.Marshal(doc) + require.NoError(t, err, "failed to marshal document") + + err = validateMediaType(b, tc.mt) + assert.NoError(t, err, "document should be valid") + }) + } + for _, iv := range tc.invalid { + t.Run("invalid-"+tc.mt+"-"+iv, func(t *testing.T) { + doc := struct { + MediaType string `json:"mediaType"` + }{MediaType: iv} + b, err := json.Marshal(doc) + require.NoError(t, err, "failed to marshal document") + + err = validateMediaType(b, tc.mt) + assert.Error(t, err, "document should not be valid") + }) + } + } + t.Run("schema1", func(t *testing.T) { + doc := struct { + FSLayers []string `json:"fsLayers"` + }{FSLayers: []string{"1"}} + b, err := json.Marshal(doc) + require.NoError(t, err, "failed to marshal document") + + err = validateMediaType(b, "") + assert.Error(t, err, "document should not be valid") + }) +} diff -Nru containerd-1.2.6/images/mediatypes.go containerd-1.5.9/images/mediatypes.go --- containerd-1.2.6/images/mediatypes.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/mediatypes.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,6 +16,16 @@ package images +import ( + "context" + "sort" + "strings" + + "github.com/containerd/containerd/errdefs" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + // mediatype definitions for image components handled in containerd. // // oci components are generally referenced directly, although we may centralize @@ -29,11 +39,166 @@ MediaTypeDockerSchema2Manifest = "application/vnd.docker.distribution.manifest.v2+json" MediaTypeDockerSchema2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" // Checkpoint/Restore Media Types - MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar" - MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar" - MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar" - MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar" - MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto" + MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar" + MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar" + MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar" + MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar" + MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto" + MediaTypeContainerd1CheckpointOptions = "application/vnd.containerd.container.checkpoint.options.v1+proto" + MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name" + MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto" // Legacy Docker schema1 manifest MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws" + // Encypted media types + MediaTypeImageLayerEncrypted = ocispec.MediaTypeImageLayer + "+encrypted" + MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted" ) + +// DiffCompression returns the compression as defined by the layer diff media +// type. For Docker media types without compression, "unknown" is returned to +// indicate that the media type may be compressed. If the media type is not +// recognized as a layer diff, then it returns errdefs.ErrNotImplemented +func DiffCompression(ctx context.Context, mediaType string) (string, error) { + base, ext := parseMediaTypes(mediaType) + switch base { + case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign: + if len(ext) > 0 { + // Type is wrapped + return "", nil + } + // These media types may have been compressed but failed to + // use the correct media type. The decompression function + // should detect and handle this case. + return "unknown", nil + case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip: + if len(ext) > 0 { + // Type is wrapped + return "", nil + } + return "gzip", nil + case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable: + if len(ext) > 0 { + switch ext[len(ext)-1] { + case "gzip": + return "gzip", nil + case "zstd": + return "zstd", nil + } + } + return "", nil + default: + return "", errors.Wrapf(errdefs.ErrNotImplemented, "unrecognised mediatype %s", mediaType) + } +} + +// parseMediaTypes splits the media type into the base type and +// an array of sorted extensions +func parseMediaTypes(mt string) (string, []string) { + if mt == "" { + return "", []string{} + } + + s := strings.Split(mt, "+") + ext := s[1:] + sort.Strings(ext) + + return s[0], ext +} + +// IsNonDistributable returns true if the media type is non-distributable. +func IsNonDistributable(mt string) bool { + return strings.HasPrefix(mt, "application/vnd.oci.image.layer.nondistributable.") || + strings.HasPrefix(mt, "application/vnd.docker.image.rootfs.foreign.") +} + +// IsLayerType returns true if the media type is a layer +func IsLayerType(mt string) bool { + if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") { + return true + } + + // Parse Docker media types, strip off any + suffixes first + base, _ := parseMediaTypes(mt) + switch base { + case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, + MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip: + return true + } + return false +} + +// IsDockerType returns true if the media type has "application/vnd.docker." prefix +func IsDockerType(mt string) bool { + return strings.HasPrefix(mt, "application/vnd.docker.") +} + +// IsManifestType returns true if the media type is an OCI-compatible manifest. +// No support for schema1 manifest. +func IsManifestType(mt string) bool { + switch mt { + case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + return true + default: + return false + } +} + +// IsIndexType returns true if the media type is an OCI-compatible index. +func IsIndexType(mt string) bool { + switch mt { + case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList: + return true + default: + return false + } +} + +// IsConfigType returns true if the media type is an OCI-compatible image config. +// No support for containerd checkpoint configs. +func IsConfigType(mt string) bool { + switch mt { + case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: + return true + default: + return false + } +} + +// IsKnownConfig returns true if the media type is a known config type, +// including containerd checkpoint configs +func IsKnownConfig(mt string) bool { + switch mt { + case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig, + MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig: + return true + } + return false +} + +// ChildGCLabels returns the label for a given descriptor to reference it +func ChildGCLabels(desc ocispec.Descriptor) []string { + mt := desc.MediaType + if IsKnownConfig(mt) { + return []string{"containerd.io/gc.ref.content.config"} + } + + switch mt { + case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + return []string{"containerd.io/gc.ref.content.m."} + } + + if IsLayerType(mt) { + return []string{"containerd.io/gc.ref.content.l."} + } + + return []string{"containerd.io/gc.ref.content."} +} + +// ChildGCLabelsFilterLayers returns the labels for a given descriptor to +// reference it, skipping layer media types +func ChildGCLabelsFilterLayers(desc ocispec.Descriptor) []string { + if IsLayerType(desc.MediaType) { + return nil + } + return ChildGCLabels(desc) +} diff -Nru containerd-1.2.6/images/oci/exporter.go containerd-1.5.9/images/oci/exporter.go --- containerd-1.2.6/images/oci/exporter.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/images/oci/exporter.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,203 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package oci - -import ( - "archive/tar" - "context" - "encoding/json" - "io" - "sort" - - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/images" - ocispecs "github.com/opencontainers/image-spec/specs-go" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" -) - -// V1Exporter implements OCI Image Spec v1. -// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc. -// -// TODO(AkihiroSuda): add V1Exporter{TranslateMediaTypes: true} that transforms media types, -// e.g. application/vnd.docker.image.rootfs.diff.tar.gzip -// -> application/vnd.oci.image.layer.v1.tar+gzip -type V1Exporter struct { -} - -// Export implements Exporter. -func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error { - tw := tar.NewWriter(writer) - defer tw.Close() - - records := []tarRecord{ - ociLayoutFile(""), - ociIndexRecord(desc), - } - - algorithms := map[string]struct{}{} - exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { - records = append(records, blobRecord(store, desc)) - algorithms[desc.Digest.Algorithm().String()] = struct{}{} - return nil, nil - } - - handlers := images.Handlers( - images.ChildrenHandler(store), - images.HandlerFunc(exportHandler), - ) - - // Walk sequentially since the number of fetchs is likely one and doing in - // parallel requires locking the export handler - if err := images.Walk(ctx, handlers, desc); err != nil { - return err - } - - if len(algorithms) > 0 { - records = append(records, directoryRecord("blobs/", 0755)) - for alg := range algorithms { - records = append(records, directoryRecord("blobs/"+alg+"/", 0755)) - } - } - - return writeTar(ctx, tw, records) -} - -type tarRecord struct { - Header *tar.Header - CopyTo func(context.Context, io.Writer) (int64, error) -} - -func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord { - path := "blobs/" + desc.Digest.Algorithm().String() + "/" + desc.Digest.Hex() - return tarRecord{ - Header: &tar.Header{ - Name: path, - Mode: 0444, - Size: desc.Size, - Typeflag: tar.TypeReg, - }, - CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { - r, err := cs.ReaderAt(ctx, desc) - if err != nil { - return 0, errors.Wrap(err, "failed to get reader") - } - defer r.Close() - - // Verify digest - dgstr := desc.Digest.Algorithm().Digester() - - n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r)) - if err != nil { - return 0, errors.Wrap(err, "failed to copy to tar") - } - if dgstr.Digest() != desc.Digest { - return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest()) - } - return n, nil - }, - } -} - -func directoryRecord(name string, mode int64) tarRecord { - return tarRecord{ - Header: &tar.Header{ - Name: name, - Mode: mode, - Typeflag: tar.TypeDir, - }, - } -} - -func ociLayoutFile(version string) tarRecord { - if version == "" { - version = ocispec.ImageLayoutVersion - } - layout := ocispec.ImageLayout{ - Version: version, - } - - b, err := json.Marshal(layout) - if err != nil { - panic(err) - } - - return tarRecord{ - Header: &tar.Header{ - Name: ocispec.ImageLayoutFile, - Mode: 0444, - Size: int64(len(b)), - Typeflag: tar.TypeReg, - }, - CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { - n, err := w.Write(b) - return int64(n), err - }, - } - -} - -func ociIndexRecord(manifests ...ocispec.Descriptor) tarRecord { - index := ocispec.Index{ - Versioned: ocispecs.Versioned{ - SchemaVersion: 2, - }, - Manifests: manifests, - } - - b, err := json.Marshal(index) - if err != nil { - panic(err) - } - - return tarRecord{ - Header: &tar.Header{ - Name: "index.json", - Mode: 0644, - Size: int64(len(b)), - Typeflag: tar.TypeReg, - }, - CopyTo: func(ctx context.Context, w io.Writer) (int64, error) { - n, err := w.Write(b) - return int64(n), err - }, - } -} - -func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error { - sort.Slice(records, func(i, j int) bool { - return records[i].Header.Name < records[j].Header.Name - }) - - for _, record := range records { - if err := tw.WriteHeader(record.Header); err != nil { - return err - } - if record.CopyTo != nil { - n, err := record.CopyTo(ctx, tw) - if err != nil { - return err - } - if n != record.Header.Size { - return errors.Errorf("unexpected copy size for %s", record.Header.Name) - } - } else if record.Header.Size > 0 { - return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name) - } - } - return nil -} diff -Nru containerd-1.2.6/image_store.go containerd-1.5.9/image_store.go --- containerd-1.2.6/image_store.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/image_store.go 2022-01-05 17:30:58.000000000 +0000 @@ -137,16 +137,18 @@ func descFromProto(desc *types.Descriptor) ocispec.Descriptor { return ocispec.Descriptor{ - MediaType: desc.MediaType, - Size: desc.Size_, - Digest: desc.Digest, + MediaType: desc.MediaType, + Size: desc.Size_, + Digest: desc.Digest, + Annotations: desc.Annotations, } } func descToProto(desc *ocispec.Descriptor) types.Descriptor { return types.Descriptor{ - MediaType: desc.MediaType, - Size_: desc.Size, - Digest: desc.Digest, + MediaType: desc.MediaType, + Size_: desc.Size, + Digest: desc.Digest, + Annotations: desc.Annotations, } } diff -Nru containerd-1.2.6/image_test.go containerd-1.5.9/image_test.go --- containerd-1.2.6/image_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/image_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "runtime" - "testing" - - "github.com/containerd/containerd/errdefs" -) - -func TestImageIsUnpacked(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip() - } - - const imageName = "docker.io/library/busybox:latest" - ctx, cancel := testContext() - defer cancel() - - client, err := newClient(t, address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - // Cleanup - err = client.ImageService().Delete(ctx, imageName) - if err != nil && !errdefs.IsNotFound(err) { - t.Fatal(err) - } - - // By default pull does not unpack an image - image, err := client.Pull(ctx, imageName, WithPlatform("linux/amd64")) - if err != nil { - t.Fatal(err) - } - - // Check that image is not unpacked - unpacked, err := image.IsUnpacked(ctx, DefaultSnapshotter) - if err != nil { - t.Fatal(err) - } - if unpacked { - t.Fatalf("image should not be unpacked") - } - - // Check that image is unpacked - err = image.Unpack(ctx, DefaultSnapshotter) - if err != nil { - t.Fatal(err) - } - unpacked, err = image.IsUnpacked(ctx, DefaultSnapshotter) - if err != nil { - t.Fatal(err) - } - if !unpacked { - t.Fatalf("image should be unpacked") - } -} diff -Nru containerd-1.2.6/import.go containerd-1.5.9/import.go --- containerd-1.2.6/import.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/import.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,14 +25,17 @@ "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/images/archive" + "github.com/containerd/containerd/platforms" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type importOpts struct { - indexName string - imageRefT func(string) string - dgstRefT func(digest.Digest) string + indexName string + imageRefT func(string) string + dgstRefT func(digest.Digest) string + allPlatforms bool + compress bool } // ImportOpt allows the caller to specify import specific options @@ -64,9 +67,26 @@ } } +// WithAllPlatforms is used to import content for all platforms. +func WithAllPlatforms(allPlatforms bool) ImportOpt { + return func(c *importOpts) error { + c.allPlatforms = allPlatforms + return nil + } +} + +// WithImportCompression compresses uncompressed layers on import. +// This is used for import formats which do not include the manifest. +func WithImportCompression() ImportOpt { + return func(c *importOpts) error { + c.compress = true + return nil + } +} + // Import imports an image from a Tar stream using reader. // Caller needs to specify importer. Future version may use oci.v1 as the default. -// Note that unreferrenced blobs may be imported to the content store as well. +// Note that unreferenced blobs may be imported to the content store as well. func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt) ([]images.Image, error) { var iopts importOpts for _, o := range opts { @@ -81,7 +101,12 @@ } defer done(ctx) - index, err := archive.ImportIndex(ctx, c.ContentStore(), reader) + var aio []archive.ImportOpt + if iopts.compress { + aio = append(aio, archive.WithImportCompression()) + } + + index, err := archive.ImportIndex(ctx, c.ContentStore(), reader, aio...) if err != nil { return nil, err } @@ -98,6 +123,10 @@ Target: index, }) } + var platformMatcher = platforms.All + if !iopts.allPlatforms { + platformMatcher = c.platform + } var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { // Only save images at top level @@ -116,16 +145,12 @@ } for _, m := range idx.Manifests { - if ref := m.Annotations[ocispec.AnnotationRefName]; ref != "" { - if iopts.imageRefT != nil { - ref = iopts.imageRefT(ref) - } - if ref != "" { - imgs = append(imgs, images.Image{ - Name: ref, - Target: m, - }) - } + name := imageName(m.Annotations, iopts.imageRefT) + if name != "" { + imgs = append(imgs, images.Image{ + Name: name, + Target: m, + }) } if iopts.dgstRefT != nil { ref := iopts.dgstRefT(m.Digest) @@ -141,6 +166,7 @@ return idx.Manifests, nil } + handler = images.FilterPlatforms(handler, platformMatcher) handler = images.SetChildrenLabels(cs, handler) if err := images.Walk(ctx, handler, index); err != nil { return nil, err @@ -163,3 +189,17 @@ return imgs, nil } + +func imageName(annotations map[string]string, ociCleanup func(string) string) string { + name := annotations[images.AnnotationImageName] + if name != "" { + return name + } + name = annotations[ocispec.AnnotationRefName] + if name != "" { + if ociCleanup != nil { + name = ociCleanup(name) + } + } + return name +} diff -Nru containerd-1.2.6/import_test.go containerd-1.5.9/import_test.go --- containerd-1.2.6/import_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/import_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,343 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "encoding/json" - "io" - - "io/ioutil" - "math/rand" - "runtime" - "testing" - - "github.com/containerd/containerd/archive/tartest" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/images/archive" - "github.com/containerd/containerd/images/oci" - digest "github.com/opencontainers/go-digest" - specs "github.com/opencontainers/image-spec/specs-go" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" -) - -// TestOCIExportAndImport exports testImage as a tar stream, -// and import the tar stream as a new image. -func TestOCIExportAndImport(t *testing.T) { - // TODO: support windows - if testing.Short() || runtime.GOOS == "windows" { - t.Skip() - } - ctx, cancel := testContext() - defer cancel() - - client, err := New(address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - pulled, err := client.Fetch(ctx, testImage) - if err != nil { - t.Fatal(err) - } - - exported, err := client.Export(ctx, &oci.V1Exporter{}, pulled.Target) - if err != nil { - t.Fatal(err) - } - - opts := []ImportOpt{ - WithImageRefTranslator(archive.AddRefPrefix("foo/bar")), - } - imgrecs, err := client.Import(ctx, exported, opts...) - if err != nil { - t.Fatalf("Import failed: %+v", err) - } - - for _, imgrec := range imgrecs { - err = client.ImageService().Delete(ctx, imgrec.Name) - if err != nil { - t.Fatal(err) - } - } -} - -func TestImport(t *testing.T) { - ctx, cancel := testContext() - defer cancel() - - client, err := New(address) - if err != nil { - t.Fatal(err) - } - defer client.Close() - - tc := tartest.TarContext{} - - b1, d1 := createContent(256, 1) - empty := []byte("{}") - version := []byte("1.0") - - c1, d2 := createConfig() - - m1, d3 := createManifest(c1, [][]byte{b1}) - - provider := client.ContentStore() - - checkManifest := func(ctx context.Context, t *testing.T, d ocispec.Descriptor) { - m, err := images.Manifest(ctx, provider, d, nil) - if err != nil { - t.Fatalf("unable to read target blob: %+v", err) - } - - if m.Config.Digest != d2 { - t.Fatalf("unexpected digest hash %s, expected %s", m.Config.Digest, d2) - } - - if len(m.Layers) != 1 { - t.Fatalf("expected 1 layer, has %d", len(m.Layers)) - } - - if m.Layers[0].Digest != d1 { - t.Fatalf("unexpected layer hash %s, expected %s", m.Layers[0].Digest, d1) - } - } - - for _, tc := range []struct { - Name string - Writer tartest.WriterToTar - Check func(*testing.T, []images.Image) - Opts []ImportOpt - }{ - { - Name: "DockerV2.0", - Writer: tartest.TarAll( - tc.Dir("bd765cd43e95212f7aa2cab51d0a", 0755), - tc.File("bd765cd43e95212f7aa2cab51d0a/json", empty, 0644), - tc.File("bd765cd43e95212f7aa2cab51d0a/layer.tar", b1, 0644), - tc.File("bd765cd43e95212f7aa2cab51d0a/VERSION", version, 0644), - tc.File("repositories", []byte(`{"any":{"1":"bd765cd43e95212f7aa2cab51d0a"}}`), 0644), - ), - }, - { - Name: "DockerV2.1", - Writer: tartest.TarAll( - tc.Dir("bd765cd43e95212f7aa2cab51d0a", 0755), - tc.File("bd765cd43e95212f7aa2cab51d0a/json", empty, 0644), - tc.File("bd765cd43e95212f7aa2cab51d0a/layer.tar", b1, 0644), - tc.File("bd765cd43e95212f7aa2cab51d0a/VERSION", version, 0644), - tc.File("e95212f7aa2cab51d0abd765cd43.json", c1, 0644), - tc.File("manifest.json", []byte(`[{"Config":"e95212f7aa2cab51d0abd765cd43.json","RepoTags":["test-import:notlatest", "another/repo:tag"],"Layers":["bd765cd43e95212f7aa2cab51d0a/layer.tar"]}]`), 0644), - ), - Check: func(t *testing.T, imgs []images.Image) { - if len(imgs) == 0 { - t.Fatalf("no images") - } - - names := []string{ - "docker.io/library/test-import:notlatest", - "docker.io/another/repo:tag", - } - - checkImages(t, imgs[0].Target.Digest, imgs, names...) - checkManifest(ctx, t, imgs[0].Target) - }, - }, - { - Name: "OCI-BadFormat", - Writer: tartest.TarAll( - tc.File("oci-layout", []byte(`{"imageLayoutVersion":"2.0.0"}`), 0644), - ), - }, - { - Name: "OCI", - Writer: tartest.TarAll( - tc.Dir("blobs", 0755), - tc.Dir("blobs/sha256", 0755), - tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), - tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), - tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), - tc.File("index.json", createIndex(m1, "latest", "docker.io/lib/img:ok"), 0644), - tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), - ), - Check: func(t *testing.T, imgs []images.Image) { - names := []string{ - "latest", - "docker.io/lib/img:ok", - } - - checkImages(t, d3, imgs, names...) - checkManifest(ctx, t, imgs[0].Target) - }, - }, - { - Name: "OCIPrefixName", - Writer: tartest.TarAll( - tc.Dir("blobs", 0755), - tc.Dir("blobs/sha256", 0755), - tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), - tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), - tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), - tc.File("index.json", createIndex(m1, "latest", "docker.io/lib/img:ok"), 0644), - tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), - ), - Check: func(t *testing.T, imgs []images.Image) { - names := []string{ - "localhost:5000/myimage:latest", - "docker.io/lib/img:ok", - } - - checkImages(t, d3, imgs, names...) - checkManifest(ctx, t, imgs[0].Target) - }, - Opts: []ImportOpt{ - WithImageRefTranslator(archive.AddRefPrefix("localhost:5000/myimage")), - }, - }, - { - Name: "OCIPrefixName", - Writer: tartest.TarAll( - tc.Dir("blobs", 0755), - tc.Dir("blobs/sha256", 0755), - tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), - tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), - tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), - tc.File("index.json", createIndex(m1, "latest", "localhost:5000/myimage:old", "docker.io/lib/img:ok"), 0644), - tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), - ), - Check: func(t *testing.T, imgs []images.Image) { - names := []string{ - "localhost:5000/myimage:latest", - "localhost:5000/myimage:old", - } - - checkImages(t, d3, imgs, names...) - checkManifest(ctx, t, imgs[0].Target) - }, - Opts: []ImportOpt{ - WithImageRefTranslator(archive.FilterRefPrefix("localhost:5000/myimage")), - }, - }, - } { - t.Run(tc.Name, func(t *testing.T) { - images, err := client.Import(ctx, tartest.TarFromWriterTo(tc.Writer), tc.Opts...) - if err != nil { - if tc.Check != nil { - t.Errorf("unexpected import error: %+v", err) - } - return - } else if tc.Check == nil { - t.Fatalf("expected error on import") - } - - tc.Check(t, images) - }) - } -} - -func checkImages(t *testing.T, target digest.Digest, actual []images.Image, names ...string) { - if len(names) != len(actual) { - t.Fatalf("expected %d images, got %d", len(names), len(actual)) - } - - for i, n := range names { - if actual[i].Target.Digest != target { - t.Fatalf("image(%d) unexpected target %s, expected %s", i, actual[i].Target.Digest, target) - } - if actual[i].Name != n { - t.Fatalf("image(%d) unexpected name %q, expected %q", i, actual[i].Name, n) - } - - if actual[i].Target.MediaType != ocispec.MediaTypeImageManifest { - t.Fatalf("image(%d) unexpected media type: %s", i, actual[i].Target.MediaType) - } - } - -} - -func createContent(size int64, seed int64) ([]byte, digest.Digest) { - b, err := ioutil.ReadAll(io.LimitReader(rand.New(rand.NewSource(seed)), size)) - if err != nil { - panic(err) - } - return b, digest.FromBytes(b) -} - -func createConfig() ([]byte, digest.Digest) { - image := ocispec.Image{ - OS: "any", - Architecture: "any", - Author: "test", - } - b, _ := json.Marshal(image) - - return b, digest.FromBytes(b) -} - -func createManifest(config []byte, layers [][]byte) ([]byte, digest.Digest) { - manifest := ocispec.Manifest{ - Versioned: specs.Versioned{ - SchemaVersion: 2, - }, - Config: ocispec.Descriptor{ - MediaType: ocispec.MediaTypeImageConfig, - Digest: digest.FromBytes(config), - Size: int64(len(config)), - }, - } - for _, l := range layers { - manifest.Layers = append(manifest.Layers, ocispec.Descriptor{ - MediaType: ocispec.MediaTypeImageLayer, - Digest: digest.FromBytes(l), - Size: int64(len(l)), - }) - } - - b, _ := json.Marshal(manifest) - - return b, digest.FromBytes(b) -} - -func createIndex(manifest []byte, tags ...string) []byte { - idx := ocispec.Index{ - Versioned: specs.Versioned{ - SchemaVersion: 2, - }, - } - d := ocispec.Descriptor{ - MediaType: ocispec.MediaTypeImageManifest, - Digest: digest.FromBytes(manifest), - Size: int64(len(manifest)), - } - - if len(tags) == 0 { - idx.Manifests = append(idx.Manifests, d) - } else { - for _, t := range tags { - dt := d - dt.Annotations = map[string]string{ - ocispec.AnnotationRefName: t, - } - idx.Manifests = append(idx.Manifests, dt) - } - } - - b, _ := json.Marshal(idx) - - return b -} diff -Nru containerd-1.2.6/install.go containerd-1.5.9/install.go --- containerd-1.2.6/install.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/install.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,13 +21,13 @@ "context" "os" "path/filepath" + "runtime" + "strings" - introspectionapi "github.com/containerd/containerd/api/services/introspection/v1" "github.com/containerd/containerd/archive" "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" - "github.com/containerd/containerd/platforms" "github.com/pkg/errors" ) @@ -43,12 +43,21 @@ } var ( cs = image.ContentStore() - platform = platforms.Default() + platform = c.platform ) manifest, err := images.Manifest(ctx, cs, image.Target(), platform) if err != nil { return err } + + var binDir, libDir string + if runtime.GOOS == "windows" { + binDir = "Files\\bin" + libDir = "Files\\lib" + } else { + binDir = "bin" + libDir = "lib" + } for _, layer := range manifest.Layers { ra, err := cs.ReaderAt(ctx, layer) if err != nil { @@ -59,12 +68,16 @@ if err != nil { return err } - defer r.Close() if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) { d := filepath.Dir(hdr.Name) - result := d == "bin" + result := d == binDir + if config.Libs { - result = result || d == "lib" + result = result || d == libDir + } + + if runtime.GOOS == "windows" { + hdr.Name = strings.Replace(hdr.Name, "Files", "", 1) } if result && !config.Replace { if _, err := os.Lstat(filepath.Join(path, hdr.Name)); err == nil { @@ -73,8 +86,10 @@ } return result, nil })); err != nil { + r.Close() return err } + r.Close() } return nil } @@ -83,11 +98,8 @@ if config.Path != "" { return config.Path, nil } - resp, err := c.IntrospectionService().Plugins(ctx, &introspectionapi.PluginsRequest{ - Filters: []string{ - "id==opt", - }, - }) + filters := []string{"id==opt"} + resp, err := c.IntrospectionService().Plugins(ctx, filters) if err != nil { return "", err } diff -Nru containerd-1.2.6/integration/addition_gids_test.go containerd-1.5.9/integration/addition_gids_test.go --- containerd-1.2.6/integration/addition_gids_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/addition_gids_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestAdditionalGids(t *testing.T) { + testPodLogDir, err := ioutil.TempDir("/tmp", "additional-gids") + require.NoError(t, err) + defer os.RemoveAll(testPodLogDir) + + t.Log("Create a sandbox with log directory") + sbConfig := PodSandboxConfig("sandbox", "additional-gids", + WithPodLogDirectory(testPodLogDir)) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container to print id") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("id"), + WithLogPath(containerName), + WithSupplementalGroups([]int64{1 /*daemon*/, 1234 /*new group*/}), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Wait for container to finish running") + require.NoError(t, Eventually(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + if s.GetState() == runtime.ContainerState_CONTAINER_EXITED { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Log("Search additional groups in container log") + content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName)) + assert.NoError(t, err) + assert.Contains(t, string(content), "groups=1(daemon),10(wheel),1234") +} diff -Nru containerd-1.2.6/integration/client/benchmark_test.go containerd-1.5.9/integration/client/benchmark_test.go --- containerd-1.2.6/integration/client/benchmark_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/benchmark_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "fmt" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" +) + +func BenchmarkContainerCreate(b *testing.B) { + client, err := newClient(b, address) + if err != nil { + b.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(b) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + b.Error(err) + return + } + spec, err := oci.GenerateSpec(ctx, client, &containers.Container{ID: b.Name()}, oci.WithImageConfig(image), withTrue()) + if err != nil { + b.Error(err) + return + } + var containers []Container + defer func() { + for _, c := range containers { + if err := c.Delete(ctx, WithSnapshotCleanup); err != nil { + b.Error(err) + } + } + }() + + // reset the timer before creating containers + b.ResetTimer() + for i := 0; i < b.N; i++ { + id := fmt.Sprintf("%s-%d", b.Name(), i) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithSpec(spec)) + if err != nil { + b.Error(err) + return + } + containers = append(containers, container) + } + b.StopTimer() +} + +func BenchmarkContainerStart(b *testing.B) { + client, err := newClient(b, address) + if err != nil { + b.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(b) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + b.Error(err) + return + } + spec, err := oci.GenerateSpec(ctx, client, &containers.Container{ID: b.Name()}, oci.WithImageConfig(image), withTrue()) + if err != nil { + b.Error(err) + return + } + var containers []Container + defer func() { + for _, c := range containers { + if err := c.Delete(ctx, WithSnapshotCleanup); err != nil { + b.Error(err) + } + } + }() + + for i := 0; i < b.N; i++ { + id := fmt.Sprintf("%s-%d", b.Name(), i) + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithSpec(spec)) + if err != nil { + b.Error(err) + return + } + containers = append(containers, container) + + } + // reset the timer before starting tasks + b.ResetTimer() + for _, c := range containers { + task, err := c.NewTask(ctx, empty()) + if err != nil { + b.Error(err) + return + } + defer task.Delete(ctx) + if err := task.Start(ctx); err != nil { + b.Error(err) + return + } + } + b.StopTimer() +} diff -Nru containerd-1.2.6/integration/client/client_test.go containerd-1.5.9/integration/client/client_test.go --- containerd-1.2.6/integration/client/client_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/client_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,543 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bytes" + "context" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "testing" + "time" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/log/logtest" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/sys" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/identity" + "github.com/sirupsen/logrus" +) + +var ( + address string + noDaemon bool + noCriu bool + supportsCriu bool + testNamespace = "testing" + testSnapshotter = DefaultSnapshotter + ctrdStdioFilePath string + + ctrd = &daemon{} +) + +func init() { + flag.StringVar(&address, "address", defaultAddress, "The address to the containerd socket for use in the tests") + flag.BoolVar(&noDaemon, "no-daemon", false, "Do not start a dedicated daemon for the tests") + flag.BoolVar(&noCriu, "no-criu", false, "Do not run the checkpoint tests") +} + +func testContext(t testing.TB) (context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + ctx = namespaces.WithNamespace(ctx, testNamespace) + if t != nil { + ctx = logtest.WithT(ctx, t) + } + return ctx, cancel +} + +func TestMain(m *testing.M) { + flag.Parse() + if testing.Short() { + os.Exit(m.Run()) + } + testutil.RequiresRootM() + // check if criu is installed on the system + _, err := exec.LookPath("criu") + supportsCriu = err == nil && !noCriu + + var ( + buf = bytes.NewBuffer(nil) + ctx, cancel = testContext(nil) + ) + defer cancel() + + if !noDaemon { + sys.ForceRemoveAll(defaultRoot) + + stdioFile, err := ioutil.TempFile("", "") + if err != nil { + fmt.Fprintf(os.Stderr, "could not create a new stdio temp file: %s\n", err) + os.Exit(1) + } + defer func() { + stdioFile.Close() + os.Remove(stdioFile.Name()) + }() + ctrdStdioFilePath = stdioFile.Name() + stdioWriter := io.MultiWriter(stdioFile, buf) + + err = ctrd.start("containerd", address, []string{ + "--root", defaultRoot, + "--state", defaultState, + "--log-level", "debug", + "--config", createShimDebugConfig(), + }, stdioWriter, stdioWriter) + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String()) + os.Exit(1) + } + } + + waitCtx, waitCancel := context.WithTimeout(ctx, 4*time.Second) + client, err := ctrd.waitForStart(waitCtx) + waitCancel() + if err != nil { + ctrd.Kill() + ctrd.Wait() + fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String()) + os.Exit(1) + } + + // print out the version in information + version, err := client.Version(ctx) + if err != nil { + fmt.Fprintf(os.Stderr, "error getting version: %s\n", err) + os.Exit(1) + } + + // allow comparison with containerd under test + log.G(ctx).WithFields(logrus.Fields{ + "version": version.Version, + "revision": version.Revision, + "runtime": os.Getenv("TEST_RUNTIME"), + "snapshotter": os.Getenv("TEST_SNAPSHOTTER"), + }).Info("running tests against containerd") + + snapshotter := DefaultSnapshotter + if ss := os.Getenv("TEST_SNAPSHOTTER"); ss != "" { + snapshotter = ss + } + + ns, ok := namespaces.Namespace(ctx) + if !ok { + fmt.Fprintln(os.Stderr, "error getting namespace") + os.Exit(1) + } + err = client.NamespaceService().SetLabel(ctx, ns, defaults.DefaultSnapshotterNSLabel, snapshotter) + if err != nil { + fmt.Fprintf(os.Stderr, "error setting %s's default snapshotter as %s: %s\n", ns, snapshotter, err) + os.Exit(1) + } + + testSnapshotter = snapshotter + + // pull a seed image + log.G(ctx).WithField("image", testImage).Info("start to pull seed image") + if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil { + ctrd.Kill() + ctrd.Wait() + fmt.Fprintf(os.Stderr, "%s: %s\n", err, buf.String()) + os.Exit(1) + } + + if err := client.Close(); err != nil { + fmt.Fprintln(os.Stderr, "failed to close client", err) + } + + // run the test + status := m.Run() + + if !noDaemon { + // tear down the daemon and resources created + if err := ctrd.Stop(); err != nil { + if err := ctrd.Kill(); err != nil { + fmt.Fprintln(os.Stderr, "failed to signal containerd", err) + } + } + if err := ctrd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); !ok { + fmt.Fprintln(os.Stderr, "failed to wait for containerd", err) + } + } + + if err := sys.ForceRemoveAll(defaultRoot); err != nil { + fmt.Fprintln(os.Stderr, "failed to remove test root dir", err) + os.Exit(1) + } + + // only print containerd logs if the test failed or tests were run with -v + if status != 0 || testing.Verbose() { + fmt.Fprintln(os.Stderr, buf.String()) + } + } + os.Exit(status) +} + +func newClient(t testing.TB, address string, opts ...ClientOpt) (*Client, error) { + if testing.Short() { + t.Skip() + } + if rt := os.Getenv("TEST_RUNTIME"); rt != "" { + opts = append(opts, WithDefaultRuntime(rt)) + } + // testutil.RequiresRoot(t) is not needed here (already called in TestMain) + return New(address, opts...) +} + +func TestNewClient(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + if client == nil { + t.Fatal("New() returned nil client") + } + if err := client.Close(); err != nil { + t.Errorf("client closed returned error %v", err) + } +} + +// All the container's tests depends on this, we need it to run first. +func TestImagePull(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + _, err = client.Pull(ctx, testImage, WithPlatformMatcher(platforms.Default())) + if err != nil { + t.Fatal(err) + } +} + +func TestImagePullWithDiscardContent(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + + err = client.ImageService().Delete(ctx, testImage, images.SynchronousDelete()) + if err != nil { + t.Fatal(err) + } + + ls := client.LeasesService() + l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(24*time.Hour)) + if err != nil { + t.Fatal(err) + } + ctx = leases.WithLease(ctx, l.ID) + img, err := client.Pull(ctx, testImage, + WithPlatformMatcher(platforms.Default()), + WithPullUnpack, + WithChildLabelMap(images.ChildGCLabelsFilterLayers), + ) + // Synchronously garbage collect contents + if errL := ls.Delete(ctx, l, leases.SynchronousDelete); errL != nil { + t.Fatal(errL) + } + if err != nil { + t.Fatal(err) + } + + // Check if all layer contents have been unpacked and aren't preserved + var ( + diffIDs []digest.Digest + layers []digest.Digest + ) + cs := client.ContentStore() + manifest, err := images.Manifest(ctx, cs, img.Target(), platforms.Default()) + if err != nil { + t.Fatal(err) + } + if len(manifest.Layers) == 0 { + t.Fatalf("failed to get children from %v", img.Target()) + } + for _, l := range manifest.Layers { + layers = append(layers, l.Digest) + } + config, err := images.Config(ctx, cs, img.Target(), platforms.Default()) + if err != nil { + t.Fatal(err) + } + diffIDs, err = images.RootFS(ctx, cs, config) + if err != nil { + t.Fatal(err) + } + if len(layers) != len(diffIDs) { + t.Fatalf("number of layers and diffIDs don't match: %d != %d", len(layers), len(diffIDs)) + } else if len(layers) == 0 { + t.Fatalf("there is no layers in the target image(parent: %v)", img.Target()) + } + var ( + sn = client.SnapshotService(testSnapshotter) + chain []digest.Digest + ) + for i, dgst := range layers { + chain = append(chain, diffIDs[i]) + chainID := identity.ChainID(chain).String() + if _, err := sn.Stat(ctx, chainID); err != nil { + t.Errorf("snapshot %v must exist: %v", chainID, err) + } + if _, err := cs.Info(ctx, dgst); err == nil || !errdefs.IsNotFound(err) { + t.Errorf("content %v must be garbage collected: %v", dgst, err) + } + } +} + +func TestImagePullAllPlatforms(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + ctx, cancel := testContext(t) + defer cancel() + + cs := client.ContentStore() + img, err := client.Fetch(ctx, "k8s.gcr.io/pause:3.5") + if err != nil { + t.Fatal(err) + } + index := img.Target + manifests, err := images.Children(ctx, cs, index) + if err != nil { + t.Fatal(err) + } + for _, manifest := range manifests { + children, err := images.Children(ctx, cs, manifest) + if err != nil { + t.Fatal("Th") + } + // check if childless data type has blob in content store + for _, desc := range children { + ra, err := cs.ReaderAt(ctx, desc) + if err != nil { + t.Fatal(err) + } + ra.Close() + } + } +} + +func TestImagePullSomePlatforms(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + ctx, cancel := testContext(t) + defer cancel() + + cs := client.ContentStore() + platformList := []string{"linux/amd64", "linux/arm64/v8", "linux/s390x"} + m := make(map[string]platforms.Matcher) + var opts []RemoteOpt + + for _, platform := range platformList { + p, err := platforms.Parse(platform) + if err != nil { + t.Fatal(err) + } + m[platform] = platforms.NewMatcher(p) + opts = append(opts, WithPlatform(platform)) + } + + // Note: Must be different to the image used in TestImagePullAllPlatforms + // or it will see the content pulled by that, and fail. + img, err := client.Fetch(ctx, "k8s.gcr.io/pause:3.2", opts...) + if err != nil { + t.Fatal(err) + } + + index := img.Target + manifests, err := images.Children(ctx, cs, index) + if err != nil { + t.Fatal(err) + } + + count := 0 + for _, manifest := range manifests { + children, err := images.Children(ctx, cs, manifest) + + found := false + for _, matcher := range m { + if manifest.Platform == nil { + t.Fatal("manifest should have proper platform") + } + if matcher.Match(*manifest.Platform) { + count++ + found = true + } + } + + if found { + if len(children) == 0 { + t.Fatal("manifest should have pulled children content") + } + + // check if childless data type has blob in content store + for _, desc := range children { + ra, err := cs.ReaderAt(ctx, desc) + if err != nil { + t.Fatal(err) + } + ra.Close() + } + } else if err == nil { + t.Fatal("manifest should not have pulled children content") + } + } + + if count != len(platformList) { + t.Fatal("expected a different number of pulled manifests") + } +} + +func TestImagePullSchema1(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + schema1TestImage := "gcr.io/google_containers/pause:3.0@sha256:0d093c962a6c2dd8bb8727b661e2b5f13e9df884af9945b4cc7088d9350cd3ee" + _, err = client.Pull(ctx, schema1TestImage, WithPlatform(platforms.DefaultString()), WithSchema1Conversion) + if err != nil { + t.Fatal(err) + } +} + +func TestImagePullWithConcurrencyLimit(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + _, err = client.Pull(ctx, testImage, + WithPlatformMatcher(platforms.Default()), + WithMaxConcurrentDownloads(2)) + if err != nil { + t.Fatal(err) + } +} + +func TestClientReconnect(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + if client == nil { + t.Fatal("New() returned nil client") + } + ok, err := client.IsServing(ctx) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Fatal("containerd is not serving") + } + if err := client.Reconnect(); err != nil { + t.Fatal(err) + } + if ok, err = client.IsServing(ctx); err != nil { + t.Fatal(err) + } + if !ok { + t.Fatal("containerd is not serving") + } + if err := client.Close(); err != nil { + t.Errorf("client closed returned error %v", err) + } +} + +func createShimDebugConfig() string { + f, err := ioutil.TempFile("", "containerd-config-") + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to create config file: %s\n", err) + os.Exit(1) + } + defer f.Close() + if _, err := f.WriteString("version = 2\n"); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to config file %s: %s\n", f.Name(), err) + os.Exit(1) + } + + if _, err := f.WriteString("[plugins.\"io.containerd.runtime.v1.linux\"]\n\tshim_debug = true\n"); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to config file %s: %s\n", f.Name(), err) + os.Exit(1) + } + + return f.Name() +} + +func TestDefaultRuntimeWithNamespaceLabels(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + namespaces := client.NamespaceService() + testRuntime := "testRuntime" + runtimeLabel := defaults.DefaultRuntimeNSLabel + if err := namespaces.SetLabel(ctx, testNamespace, runtimeLabel, testRuntime); err != nil { + t.Fatal(err) + } + + testClient, err := New(address, WithDefaultNamespace(testNamespace)) + if err != nil { + t.Fatal(err) + } + defer testClient.Close() + if testClient.Runtime() != testRuntime { + t.Error("failed to set default runtime from namespace labels") + } +} diff -Nru containerd-1.2.6/integration/client/client_ttrpc_test.go containerd-1.5.9/integration/client/client_ttrpc_test.go --- containerd-1.2.6/integration/client/client_ttrpc_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/client_ttrpc_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,80 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "testing" + "time" + + v1 "github.com/containerd/containerd/api/services/ttrpc/events/v1" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/ttrpcutil" + "github.com/containerd/ttrpc" + "github.com/gogo/protobuf/types" + "gotest.tools/v3/assert" +) + +func TestClientTTRPC_New(t *testing.T) { + client, err := ttrpcutil.NewClient(address + ".ttrpc") + assert.NilError(t, err) + + err = client.Close() + assert.NilError(t, err) +} + +func TestClientTTRPC_Reconnect(t *testing.T) { + client, err := ttrpcutil.NewClient(address + ".ttrpc") + assert.NilError(t, err) + + err = client.Reconnect() + assert.NilError(t, err) + + service, err := client.EventsService() + assert.NilError(t, err) + + // Send test request to make sure its alive after reconnect + _, err = service.Forward(context.Background(), &v1.ForwardRequest{ + Envelope: &v1.Envelope{ + Timestamp: time.Now(), + Namespace: namespaces.Default, + Topic: "/test", + Event: &types.Any{}, + }, + }) + assert.NilError(t, err) + + err = client.Close() + assert.NilError(t, err) +} + +func TestClientTTRPC_Close(t *testing.T) { + client, err := ttrpcutil.NewClient(address + ".ttrpc") + assert.NilError(t, err) + + service, err := client.EventsService() + assert.NilError(t, err) + + err = client.Close() + assert.NilError(t, err) + + _, err = service.Forward(context.Background(), &v1.ForwardRequest{Envelope: &v1.Envelope{}}) + assert.Equal(t, err, ttrpc.ErrClosed) + + err = client.Close() + assert.NilError(t, err) +} diff -Nru containerd-1.2.6/integration/client/client_unix_test.go containerd-1.5.9/integration/client/client_unix_test.go --- containerd-1.2.6/integration/client/client_unix_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/client_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/platforms" +) + +const ( + defaultRoot = "/var/lib/containerd-test" + defaultState = "/run/containerd-test" + defaultAddress = "/run/containerd-test/containerd.sock" +) + +var ( + testImage = "ghcr.io/containerd/busybox:1.32" + shortCommand = withProcessArgs("true") + longCommand = withProcessArgs("/bin/sh", "-c", "while true; do sleep 1; done") +) + +func TestImagePullSchema1WithEmptyLayers(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + + schema1TestImageWithEmptyLayers := "gcr.io/google-containers/busybox@sha256:d8d3bc2c183ed2f9f10e7258f84971202325ee6011ba137112e01e30f206de67" + _, err = client.Pull(ctx, schema1TestImageWithEmptyLayers, WithPlatform(platforms.DefaultString()), WithSchema1Conversion, WithPullUnpack) + if err != nil { + t.Fatal(err) + } +} diff -Nru containerd-1.2.6/integration/client/client_windows_test.go containerd-1.5.9/integration/client/client_windows_test.go --- containerd-1.2.6/integration/client/client_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/client_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,65 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/Microsoft/hcsshim/osversion" + _ "github.com/Microsoft/hcsshim/test/functional/manifest" // For rsrc_amd64.syso +) + +const ( + defaultAddress = `\\.\pipe\containerd-containerd-test` +) + +var ( + defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test") + defaultState = filepath.Join(os.Getenv("programfiles"), "containerd", "state-test") + testImage string + shortCommand = withTrue() + longCommand = withProcessArgs("ping", "-t", "localhost") +) + +func init() { + b := osversion.Build() + switch b { + case osversion.RS1: + testImage = "mcr.microsoft.com/windows/nanoserver:sac2016" + case osversion.RS3: + testImage = "mcr.microsoft.com/windows/nanoserver:1709" + case osversion.RS4: + testImage = "mcr.microsoft.com/windows/nanoserver:1803" + case osversion.RS5: + testImage = "mcr.microsoft.com/windows/nanoserver:1809" + case osversion.V19H1: + testImage = "mcr.microsoft.com/windows/nanoserver:1903" + case osversion.V19H2: + testImage = "mcr.microsoft.com/windows/nanoserver:1909" + case osversion.V20H1: + testImage = "mcr.microsoft.com/windows/nanoserver:2004" + case osversion.V20H2: + testImage = "mcr.microsoft.com/windows/nanoserver:20H2" + default: + fmt.Println("No test image defined for Windows build version:", b) + panic("No windows test image found for this Windows build") + } + + fmt.Println("Windows test image:", testImage, ", Windows build version:", b) +} diff -Nru containerd-1.2.6/integration/client/container_checkpoint_test.go containerd-1.5.9/integration/client/container_checkpoint_test.go --- containerd-1.2.6/integration/client/container_checkpoint_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/container_checkpoint_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,615 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" + "syscall" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/plugin" +) + +const ( + testCheckpointName = "checkpoint-test:latest" +) + +func TestCheckpointRestorePTY(t *testing.T) { + if !supportsCriu { + t.Skip("system does not have criu installed") + } + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip() + } + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), + oci.WithProcessArgs("sh", "-c", "read A; echo z${A}z"), + oci.WithTTY), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + direct, err := newDirectIO(ctx, true) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + checkpoint, err := container.Checkpoint(ctx, testCheckpointName+"withpty", []CheckpointOpts{ + WithCheckpointRuntime, + WithCheckpointRW, + WithCheckpointTaskExit, + WithCheckpointTask, + }...) + if err != nil { + t.Fatal(err) + } + + <-statusC + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + direct.Delete() + if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { + t.Fatal(err) + } + + direct, err = newDirectIO(ctx, true) + if err != nil { + t.Fatal(err) + } + + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + if container, err = client.Restore(ctx, id, checkpoint, []RestoreOpts{ + WithRestoreImage, + WithRestoreSpec, + WithRestoreRuntime, + WithRestoreRW, + }...); err != nil { + t.Fatal(err) + } + if task, err = container.NewTask(ctx, direct.IOCreate, + WithTaskCheckpoint(checkpoint)); err != nil { + t.Fatal(err) + } + + statusC, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + direct.Stdin.Write([]byte("hello\n")) + <-statusC + wg.Wait() + + if err := direct.Close(); err != nil { + t.Error(err) + } + + out := buf.String() + if !strings.Contains(fmt.Sprintf("%#q", out), `zhelloz`) { + t.Fatalf(`expected \x00 in output: %s`, out) + } +} + +func TestCheckpointRestore(t *testing.T) { + if !supportsCriu { + t.Skip("system does not have criu installed") + } + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip() + } + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "10"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + checkpoint, err := container.Checkpoint(ctx, testCheckpointName+"restore", []CheckpointOpts{ + WithCheckpointRuntime, + WithCheckpointRW, + WithCheckpointTask, + }...) + if err != nil { + t.Fatal(err) + } + + <-statusC + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { + t.Fatal(err) + } + + if container, err = client.Restore(ctx, id, checkpoint, []RestoreOpts{ + WithRestoreImage, + WithRestoreSpec, + WithRestoreRuntime, + WithRestoreRW, + }...); err != nil { + t.Fatal(err) + } + if task, err = container.NewTask(ctx, empty(), WithTaskCheckpoint(checkpoint)); err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC +} + +func TestCheckpointRestoreNewContainer(t *testing.T) { + if !supportsCriu { + t.Skip("system does not have criu installed") + } + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip() + } + + id := t.Name() + ctx, cancel := testContext(t) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "5"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + checkpoint, err := container.Checkpoint(ctx, testCheckpointName+"newcontainer", []CheckpointOpts{ + WithCheckpointRuntime, + WithCheckpointRW, + WithCheckpointTask, + }...) + if err != nil { + t.Fatal(err) + } + + <-statusC + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { + t.Fatal(err) + } + if container, err = client.Restore(ctx, id, checkpoint, []RestoreOpts{ + WithRestoreImage, + WithRestoreSpec, + WithRestoreRuntime, + WithRestoreRW, + }...); err != nil { + t.Fatal(err) + } + if task, err = container.NewTask(ctx, empty(), WithTaskCheckpoint(checkpoint)); err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC +} + +func TestCheckpointLeaveRunning(t *testing.T) { + if testing.Short() { + t.Skip() + } + if !supportsCriu { + t.Skip("system does not have criu installed") + } + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip() + } + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + // checkpoint + if _, err := container.Checkpoint(ctx, testCheckpointName+"leaverunning", []CheckpointOpts{ + WithCheckpointRuntime, + WithCheckpointRW, + WithCheckpointTask, + }...); err != nil { + t.Fatal(err) + } + + status, err := task.Status(ctx) + if err != nil { + t.Fatal(err) + } + if status.Status != Running { + t.Fatalf("expected status %q but received %q", Running, status) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestCheckpointRestoreWithImagePath(t *testing.T) { + if !supportsCriu { + t.Skip("system does not have criu installed") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + ctx, cancel = testContext(t) + id = t.Name() + "-checkpoint" + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("top"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + // create image path store criu image files + crDir, err := ioutil.TempDir("", "test-cr") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(crDir) + imagePath := filepath.Join(crDir, "cr") + // checkpoint task + if _, err := task.Checkpoint(ctx, WithCheckpointImagePath(imagePath)); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC + task.Delete(ctx) + + // check image files have been dumped into image path + if files, err := ioutil.ReadDir(imagePath); err != nil || len(files) == 0 { + t.Fatal("failed to checkpoint with image path set") + } + + // restore task with same container image and checkpoint directory, + // the restore process should finish in millisecond level + id = t.Name() + "-restore" + ncontainer, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image))) + if err != nil { + t.Fatal(err) + } + defer ncontainer.Delete(ctx, WithSnapshotCleanup) + + ntask, err := ncontainer.NewTask(ctx, empty(), WithRestoreImagePath(imagePath)) + if err != nil { + t.Fatal(err) + } + statusC, err = ntask.Wait(ctx) + if err != nil { + t.Fatal(err) + } + if err := ntask.Start(ctx); err != nil { + t.Fatal(err) + } + + // check top process is existed in restored container + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + stdout := bytes.NewBuffer(nil) + spec.Process.Args = []string{"ps", "-ef"} + process, err := ntask.Exec(ctx, t.Name()+"_exec", spec.Process, cio.NewCreator(withByteBuffers(stdout))) + if err != nil { + t.Fatal(err) + } + processStatusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + <-processStatusC + if _, err := process.Delete(ctx); err != nil { + t.Fatal(err) + } + + if !strings.Contains(stdout.String(), "top") { + t.Errorf("except top process exists in restored container but not, got output %s", stdout.String()) + } + + // we wrote the same thing after attach + if err := ntask.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC + ntask.Delete(ctx) +} + +func TestCheckpointOnPauseStatus(t *testing.T) { + if !supportsCriu { + t.Skip("system does not have criu installed") + } + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip() + } + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "10"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer func() { + task.Resume(ctx) + task.Delete(ctx) + }() + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Pause(ctx); err != nil { + t.Fatal(err) + } + + _, err = container.Checkpoint(ctx, testCheckpointName+"on-pause", []CheckpointOpts{ + WithCheckpointRuntime, + WithCheckpointRW, + WithCheckpointTask, + }...) + if err != nil { + t.Fatal(err) + } + + status, err := task.Status(ctx) + if err != nil { + t.Fatal(err) + } + + if status.Status != Paused { + t.Fatalf("expected paused state, but got %s", status.Status) + } + + if err := task.Resume(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} diff -Nru containerd-1.2.6/integration/client/container_linux_test.go containerd-1.5.9/integration/client/container_linux_test.go --- containerd-1.2.6/integration/client/container_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/container_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2163 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" + "syscall" + "testing" + "time" + + "github.com/containerd/cgroups" + cgroupsv2 "github.com/containerd/cgroups/v2" + . "github.com/containerd/containerd" + apievents "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log/logtest" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/runtime/linux/runctypes" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/sys" + "github.com/containerd/typeurl" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const testUserNSImage = "ghcr.io/containerd/alpine:3.14.0" + +// TestRegressionIssue4769 verifies the number of task exit events. +// +// Issue: https://github.com/containerd/containerd/issues/4769. +func TestRegressionIssue4769(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + // use unique namespace to get unique task events + id := t.Name() + ns := fmt.Sprintf("%s-%s", testNamespace, id) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ctx = namespaces.WithNamespace(ctx, ns) + ctx = logtest.WithT(ctx, t) + + image, err := client.Pull(ctx, testImage, WithPullUnpack) + if err != nil { + t.Fatal(err) + } + defer client.ImageService().Delete(ctx, testImage, images.SynchronousDelete()) + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withTrue()), + WithRuntime(client.Runtime(), nil), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + eventStream, errC := client.EventService().Subscribe(ctx, "namespace=="+ns+",topic~=|^/tasks/exit|") + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + var timeout = 3 * time.Second + + select { + case et := <-statusC: + if got := et.ExitCode(); got != 0 { + t.Fatal(errors.Errorf("expect zero exit status, but got %v", got)) + } + case <-time.After(timeout): + t.Fatal(fmt.Errorf("failed to get exit event in time")) + } + + // start to check events + select { + case et := <-eventStream: + if et.Event == nil { + t.Fatal(errors.Errorf("unexpected empty event: %+v", et)) + } + + v, err := typeurl.UnmarshalAny(et.Event) + if err != nil { + t.Fatal(errors.Wrap(err, "failed to unmarshal event")) + } + + if e, ok := v.(*apievents.TaskExit); !ok { + t.Fatal(errors.Errorf("unexpected event type: %+v", v)) + } else if e.ExitStatus != 0 { + t.Fatal(errors.Errorf("expect zero exit status, but got %v", e.ExitStatus)) + } + case err := <-errC: + t.Fatal(errors.Wrap(err, "unexpected error from event service")) + + case <-time.After(timeout): + t.Fatal(fmt.Errorf("failed to get exit event in time")) + } + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + + // check duplicate event should not show up + select { + case event := <-eventStream: + t.Fatal(errors.Errorf("unexpected exit event: %+v", event)) + case err := <-errC: + t.Fatal(errors.Wrap(err, "unexpected error from event service")) + case <-time.After(timeout): + } +} + +func TestTaskUpdate(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + limit := int64(32 * 1024 * 1024) + memory := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Linux.Resources.Memory = &specs.LinuxMemory{ + Limit: &limit, + } + return nil + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"), memory)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + var ( + cgroup cgroups.Cgroup + cgroup2 *cgroupsv2.Manager + ) + // check that the task has a limit of 32mb + if cgroups.Mode() == cgroups.Unified { + groupPath, err := cgroupsv2.PidGroupPath(int(task.Pid())) + if err != nil { + t.Fatal(err) + } + cgroup2, err = cgroupsv2.LoadManager("/sys/fs/cgroup", groupPath) + if err != nil { + t.Fatal(err) + } + stat, err := cgroup2.Stat() + if err != nil { + t.Fatal(err) + } + if int64(stat.Memory.UsageLimit) != limit { + t.Fatalf("expected memory limit to be set to %d but received %d", limit, stat.Memory.UsageLimit) + } + } else { + cgroup, err = cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid()))) + if err != nil { + t.Fatal(err) + } + stat, err := cgroup.Stat(cgroups.IgnoreNotExist) + if err != nil { + t.Fatal(err) + } + if int64(stat.Memory.Usage.Limit) != limit { + t.Fatalf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) + } + } + limit = 64 * 1024 * 1024 + if err := task.Update(ctx, WithResources(&specs.LinuxResources{ + Memory: &specs.LinuxMemory{ + Limit: &limit, + }, + })); err != nil { + t.Error(err) + } + // check that the task has a limit of 64mb + if cgroups.Mode() == cgroups.Unified { + stat, err := cgroup2.Stat() + if err != nil { + t.Fatal(err) + } + if int64(stat.Memory.UsageLimit) != limit { + t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.UsageLimit) + } + } else { + stat, err := cgroup.Stat(cgroups.IgnoreNotExist) + if err != nil { + t.Fatal(err) + } + if int64(stat.Memory.Usage.Limit) != limit { + t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit) + } + } + if err := task.Kill(ctx, unix.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestShimInCgroup(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "30"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + // create a cgroup for the shim to use + path := "/containerd/shim" + var ( + cg cgroups.Cgroup + cg2 *cgroupsv2.Manager + ) + if cgroups.Mode() == cgroups.Unified { + cg2, err = cgroupsv2.NewManager("/sys/fs/cgroup", path, &cgroupsv2.Resources{}) + if err != nil { + t.Fatal(err) + } + defer cg2.Delete() + } else { + cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{}) + if err != nil { + t.Fatal(err) + } + defer cg.Delete() + } + + task, err := container.NewTask(ctx, empty(), WithShimCgroup(path)) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + // check to see if the shim is inside the cgroup + if cgroups.Mode() == cgroups.Unified { + processes, err := cg2.Procs(false) + if err != nil { + t.Fatal(err) + } + if len(processes) == 0 { + t.Errorf("created cgroup should have at least one process inside: %d", len(processes)) + } + } else { + processes, err := cg.Processes(cgroups.Devices, false) + if err != nil { + t.Fatal(err) + } + if len(processes) == 0 { + t.Errorf("created cgroup should have at least one process inside: %d", len(processes)) + } + } + if err := task.Kill(ctx, unix.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestDaemonRestart(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + var exitStatus ExitStatus + if err := ctrd.Restart(func() { + exitStatus = <-statusC + }); err != nil { + t.Fatal(err) + } + + if exitStatus.Error() == nil { + t.Errorf(`first task.Wait() should have failed with "transport is closing"`) + } + + waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) + serving, err := client.IsServing(waitCtx) + waitCancel() + if !serving { + t.Fatalf("containerd did not start within 2s: %v", err) + } + + statusC, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestShimDoesNotLeakPipes(t *testing.T) { + containerdPid := ctrd.cmd.Process.Pid + initialPipes, err := numPipes(containerdPid) + if err != nil { + t.Fatal(err) + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + if err != nil { + t.Fatal(err) + } + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + + exitChannel, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-exitChannel + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + + if err := container.Delete(ctx, WithSnapshotCleanup); err != nil { + t.Fatal(err) + } + + currentPipes, err := numPipes(containerdPid) + if err != nil { + t.Fatal(err) + } + + if initialPipes != currentPipes { + t.Errorf("Pipes have leaked after container has been deleted. Initially there were %d pipes, after container deletion there were %d pipes", initialPipes, currentPipes) + } +} + +func numPipes(pid int) (int, error) { + cmd := exec.Command("sh", "-c", fmt.Sprintf("lsof -p %d | grep FIFO", pid)) + + var stdout bytes.Buffer + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return 0, err + } + return strings.Count(stdout.String(), "\n"), nil +} + +func TestDaemonReconnectsToShimIOPipesOnRestart(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + _, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := ctrd.Restart(nil); err != nil { + t.Fatal(err) + } + + waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second) + serving, err := client.IsServing(waitCtx) + waitCancel() + if !serving { + t.Fatalf("containerd did not start within 2s: %v", err) + } + + // After we restared containerd we write some messages to the log pipes, simulating shim writing stuff there. + // Then we make sure that these messages are available on the containerd log thus proving that the server reconnected to the log pipes + runtimeVersion := getRuntimeVersion() + logDirPath := getLogDirPath(runtimeVersion, id) + + switch runtimeVersion { + case "v1": + writeToFile(t, filepath.Join(logDirPath, "shim.stdout.log"), fmt.Sprintf("%s writing to stdout\n", id)) + writeToFile(t, filepath.Join(logDirPath, "shim.stderr.log"), fmt.Sprintf("%s writing to stderr\n", id)) + case "v2": + writeToFile(t, filepath.Join(logDirPath, "log"), fmt.Sprintf("%s writing to log\n", id)) + } + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC + + stdioContents, err := ioutil.ReadFile(ctrdStdioFilePath) + if err != nil { + t.Fatal(err) + } + + switch runtimeVersion { + case "v1": + if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stdout", id)) { + t.Fatal("containerd did not connect to the shim stdout pipe") + } + if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stderr", id)) { + t.Fatal("containerd did not connect to the shim stderr pipe") + } + case "v2": + if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to log", id)) { + t.Fatal("containerd did not connect to the shim log pipe") + } + } +} + +func writeToFile(t *testing.T, filePath, message string) { + writer, err := os.OpenFile(filePath, os.O_WRONLY, 0600) + if err != nil { + t.Fatal(err) + } + if _, err := writer.WriteString(message); err != nil { + t.Fatal(err) + } + if err := writer.Close(); err != nil { + t.Fatal(err) + } +} + +func getLogDirPath(runtimeVersion, id string) string { + switch runtimeVersion { + case "v1": + return filepath.Join(defaultRoot, plugin.RuntimeLinuxV1, testNamespace, id) + case "v2": + return filepath.Join(defaultState, "io.containerd.runtime.v2.task", testNamespace, id) + default: + panic(fmt.Errorf("Unsupported runtime version %s", runtimeVersion)) + } +} + +func getRuntimeVersion() string { + switch rt := os.Getenv("TEST_RUNTIME"); rt { + case plugin.RuntimeLinuxV1: + return "v1" + default: + return "v2" + } +} + +func TestContainerPTY(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithTTY, withProcessArgs("echo", "hello"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + direct, err := newDirectIO(ctx, true) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + status, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + <-status + wg.Wait() + + if err := direct.Close(); err != nil { + t.Error(err) + } + + out := buf.String() + if !strings.ContainsAny(fmt.Sprintf("%#q", out), `\x00`) { + t.Fatal(`expected \x00 in output`) + } +} + +func TestContainerAttach(t *testing.T) { + t.Parallel() + + if runtime.GOOS == "windows" { + // On windows, closing the write side of the pipe closes the read + // side, sending an EOF to it and preventing reopening it. + // Hence this test will always fails on windows + t.Skip("invalid logic on windows") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat())) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + expected := "hello" + newLine + + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + status, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { + t.Error(err) + } + + // load the container and re-load the task + if container, err = client.LoadContainer(ctx, id); err != nil { + t.Fatal(err) + } + + if task, err = container.Task(ctx, direct.IOAttach); err != nil { + t.Fatal(err) + } + + if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { + t.Error(err) + } + + direct.Stdin.Close() + + if err := task.CloseIO(ctx, WithStdinCloser); err != nil { + t.Error(err) + } + + <-status + + wg.Wait() + if _, err := task.Delete(ctx); err != nil { + t.Error(err) + } + + output := buf.String() + + // we wrote the same thing after attach + expected = expected + expected + if output != expected { + t.Errorf("expected output %q but received %q", expected, output) + } +} + +func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) { + fifos, err := cio.NewFIFOSetInDir("", "", terminal) + if err != nil { + return nil, err + } + dio, err := cio.NewDirectIO(ctx, fifos) + if err != nil { + return nil, err + } + return &directIO{DirectIO: *dio}, nil +} + +type directIO struct { + cio.DirectIO +} + +// ioCreate returns IO available for use with task creation +func (f *directIO) IOCreate(id string) (cio.IO, error) { + return f, nil +} + +// ioAttach returns IO available for use with task attachment +func (f *directIO) IOAttach(set *cio.FIFOSet) (cio.IO, error) { + return f, nil +} + +func (f *directIO) Cancel() { + // nothing to cancel as all operations are handled externally +} + +// Close closes all open fds +func (f *directIO) Close() error { + err := f.Stdin.Close() + if f.Stdout != nil { + if err2 := f.Stdout.Close(); err == nil { + err = err2 + } + } + if f.Stderr != nil { + if err2 := f.Stderr.Close(); err == nil { + err = err2 + } + } + return err +} + +// Delete removes the underlying directory containing fifos +func (f *directIO) Delete() error { + return f.DirectIO.Close() +} + +func TestContainerUsername(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + // the www-data user in the busybox image has a uid of 33 + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), oci.WithUsername("www-data"), oci.WithProcessArgs("id", "-u")), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + <-statusC + + wg.Wait() + + output := strings.TrimSuffix(buf.String(), "\n") + if output != "33" { + t.Errorf("expected www-data uid to be 33 but received %q", output) + } +} + +func TestContainerUser(t *testing.T) { + t.Parallel() + t.Run("UserNameAndGroupName", func(t *testing.T) { testContainerUser(t, "www-data:www-data", "33:33") }) + t.Run("UserIDAndGroupName", func(t *testing.T) { testContainerUser(t, "1001:www-data", "1001:33") }) + t.Run("UserNameAndGroupID", func(t *testing.T) { testContainerUser(t, "www-data:1002", "33:1002") }) + t.Run("UserIDAndGroupID", func(t *testing.T) { testContainerUser(t, "1001:1002", "1001:1002") }) +} + +func testContainerUser(t *testing.T, userstr, expectedOutput string) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = strings.Replace(t.Name(), "/", "_", -1) + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), oci.WithUser(userstr), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + <-statusC + + wg.Wait() + + output := strings.TrimSuffix(buf.String(), "\n") + if output != expectedOutput { + t.Errorf("expected uid:gid to be %q, but received %q", expectedOutput, output) + } +} + +func TestContainerAttachProcess(t *testing.T) { + t.Parallel() + + if runtime.GOOS == "windows" { + // On windows, closing the write side of the pipe closes the read + // side, sending an EOF to it and preventing reopening it. + // Hence this test will always fails on windows + t.Skip("invalid logic on windows") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + expected := "hello" + newLine + + // creating IO early for easy resource cleanup + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + status, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + processSpec := spec.Process + processSpec.Args = []string{"cat"} + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + processStatusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + + if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { + t.Error(err) + } + + if process, err = task.LoadProcess(ctx, execID, direct.IOAttach); err != nil { + t.Fatal(err) + } + + if _, err := fmt.Fprint(direct.Stdin, expected); err != nil { + t.Error(err) + } + + direct.Stdin.Close() + + if err := process.CloseIO(ctx, WithStdinCloser); err != nil { + t.Error(err) + } + + <-processStatusC + + wg.Wait() + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + + output := buf.String() + + // we wrote the same thing after attach + expected = expected + expected + if output != expected { + t.Errorf("expected output %q but received %q", expected, output) + } + <-status +} + +func TestContainerLoadUnexistingProcess(t *testing.T) { + t.Parallel() + + if runtime.GOOS == "windows" { + // On windows, closing the write side of the pipe closes the read + // side, sending an EOF to it and preventing reopening it. + // Hence this test will always fails on windows + t.Skip("invalid logic on windows") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "100"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + // creating IO early for easy resource cleanup + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + status, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if _, err = task.LoadProcess(ctx, "this-process-does-not-exist", direct.IOAttach); err == nil { + t.Fatal("an error should have occurred when loading a process that does not exist") + } + + if !errdefs.IsNotFound(err) { + t.Fatalf("an error of type NotFound should have been returned when loading a process that does not exist, got %#v instead ", err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + + <-status +} + +func TestContainerUserID(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + var ( + wg sync.WaitGroup + buf = bytes.NewBuffer(nil) + ) + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(buf, direct.Stdout) + }() + + // sys user in the busybox image has a uid and gid of 3. + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), oci.WithUserID(3), oci.WithProcessArgs("sh", "-c", "echo $(id -u):$(id -g)")), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, direct.IOCreate) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + <-statusC + + wg.Wait() + + output := strings.TrimSuffix(buf.String(), "\n") + if output != "3:3" { + t.Errorf("expected uid:gid to be 3:3, but received %q", output) + } +} + +func TestContainerKillAll(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), + withProcessArgs("sh", "-c", "top"), + oci.WithHostNamespace(specs.PIDNamespace), + ), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL, WithKillAll); err != nil { + t.Error(err) + } + + <-statusC + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestDaemonRestartWithRunningShim(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("sleep", "100"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + pid := task.Pid() + if pid < 1 { + t.Fatalf("invalid task pid %d", pid) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + var exitStatus ExitStatus + if err := ctrd.Restart(func() { + exitStatus = <-statusC + }); err != nil { + t.Fatal(err) + } + + if exitStatus.Error() == nil { + t.Errorf(`first task.Wait() should have failed with "transport is closing"`) + } + + waitCtx, cancel := context.WithTimeout(ctx, 1*time.Second) + c, err := ctrd.waitForStart(waitCtx) + cancel() + if err != nil { + t.Fatal(err) + } + c.Close() + + statusC, err = task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC + + if err := unix.Kill(int(pid), 0); err != unix.ESRCH { + t.Errorf("pid %d still exists", pid) + } +} + +func TestContainerRuntimeOptionsv1(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer( + ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), + WithRuntime(plugin.RuntimeLinuxV1, &runctypes.RuncOptions{Runtime: "no-runc"}), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err == nil { + t.Errorf("task creation should have failed") + task.Delete(ctx) + return + } + if !strings.Contains(err.Error(), `"no-runc"`) { + t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) + } +} + +func TestContainerRuntimeOptionsv2(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer( + ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), + WithRuntime(plugin.RuntimeRuncV1, &options.Options{BinaryName: "no-runc"}), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err == nil { + t.Errorf("task creation should have failed") + task.Delete(ctx) + return + } + if !strings.Contains(err.Error(), `"no-runc"`) { + t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) + } +} + +func initContainerAndCheckChildrenDieOnKill(t *testing.T, opts ...oci.SpecOpts) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + opts = append(opts, oci.WithImageConfig(image)) + opts = append(opts, withProcessArgs("sh", "-c", "sleep 42; echo hi")) + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(opts...), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + + // Give the shim time to reap the init process and kill the orphans + select { + case <-statusC: + case <-time.After(100 * time.Millisecond): + } + + b, err := exec.Command("ps", "ax").CombinedOutput() + if err != nil { + t.Fatal(err) + } + + if strings.Contains(string(b), "sleep 42") { + t.Fatalf("killing init didn't kill all its children:\n%v", string(b)) + } + + if _, err := task.Delete(ctx, WithProcessKill); err != nil { + t.Error(err) + } +} + +func TestContainerKillInitPidHost(t *testing.T) { + initContainerAndCheckChildrenDieOnKill(t, oci.WithHostNamespace(specs.PIDNamespace)) +} + +func TestContainerKillInitKillsChildWhenNotHostPid(t *testing.T) { + initContainerAndCheckChildrenDieOnKill(t) +} + +func TestUserNamespaces(t *testing.T) { + t.Parallel() + t.Run("WritableRootFS", func(t *testing.T) { testUserNamespaces(t, false) }) + // see #1373 and runc#1572 + t.Run("ReadonlyRootFS", func(t *testing.T) { testUserNamespaces(t, true) }) +} + +func checkUserNS(t *testing.T) { + cmd := exec.Command("true") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUSER, + } + + if err := cmd.Run(); err != nil { + t.Skip("User namespaces are unavailable") + } +} + +func testUserNamespaces(t *testing.T, readonlyRootFS bool) { + checkUserNS(t) + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = strings.Replace(t.Name(), "/", "-", -1) + ) + defer cancel() + + image, err = client.Pull(ctx, testUserNSImage, WithPullUnpack) + if err != nil { + t.Fatal(err) + } + + opts := []NewContainerOpts{WithNewSpec(oci.WithImageConfig(image), + withExitStatus(7), + oci.WithUserNamespace([]specs.LinuxIDMapping{ + { + ContainerID: 0, + HostID: 1000, + Size: 10000, + }, + }, []specs.LinuxIDMapping{ + { + ContainerID: 0, + HostID: 2000, + Size: 10000, + }, + }), + )} + if readonlyRootFS { + opts = append([]NewContainerOpts{WithRemappedSnapshotView(id, image, 1000, 2000)}, opts...) + } else { + opts = append([]NewContainerOpts{WithRemappedSnapshot(id, image, 1000, 2000)}, opts...) + } + + container, err := client.NewContainer(ctx, id, opts...) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + var copts interface{} + if CheckRuntime(client.Runtime(), "io.containerd.runc") { + copts = &options.Options{ + IoUid: 1000, + IoGid: 2000, + } + } else { + copts = &runctypes.CreateOptions{ + IoUid: 1000, + IoGid: 2000, + } + } + + task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio), func(_ context.Context, client *Client, r *TaskInfo) error { + r.Options = copts + return nil + }) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } + if err := task.Start(ctx); err != nil { + t.Error(err) + task.Delete(ctx) + return + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 7 { + t.Errorf("expected status 7 from wait but received %d", code) + } + deleteStatus, err := task.Delete(ctx) + if err != nil { + t.Fatal(err) + } + if ec := deleteStatus.ExitCode(); ec != 7 { + t.Errorf("expected status 7 from delete but received %d", ec) + } +} + +func TestTaskResize(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + if err := task.Resize(ctx, 32, 32); err != nil { + t.Fatal(err) + } + task.Kill(ctx, syscall.SIGKILL) + <-statusC +} + +func TestContainerImage(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSpec(), WithImage(image)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + i, err := container.Image(ctx) + if err != nil { + t.Fatal(err) + } + if i.Name() != image.Name() { + t.Fatalf("expected container image name %s but received %s", image.Name(), i.Name()) + } +} + +func TestContainerNoImage(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + container, err := client.NewContainer(ctx, id, WithNewSpec()) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + _, err = container.Image(ctx) + if err == nil { + t.Fatal("error should not be nil when container is created without an image") + } + if !errdefs.IsNotFound(err) { + t.Fatalf("expected error to be %s but received %s", errdefs.ErrNotFound, err) + } +} + +func TestUIDNoGID(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + image, err := client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithUserID(1000))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + if uid := spec.Process.User.UID; uid != 1000 { + t.Fatalf("expected uid 1000 but received %d", uid) + } + if gid := spec.Process.User.GID; gid != 0 { + t.Fatalf("expected gid 0 but received %d", gid) + } +} + +func TestBindLowPortNonRoot(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000)), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 1 { + t.Errorf("expected status 1 from wait but received %d", code) + } + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestBindLowPortNonOpt(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withProcessArgs("nc", "-l", "-p", "80"), oci.WithUIDGID(1000, 1000), oci.WithAmbientCapabilities([]string{"CAP_NET_BIND_SERVICE"})), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + go func() { + time.Sleep(2 * time.Second) + task.Kill(ctx, unix.SIGTERM) + }() + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + // 128 + sigterm + if code != 143 { + t.Errorf("expected status 143 from wait but received %d", code) + } + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestContainerNoSTDIN(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(0))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(nil, ioutil.Discard, ioutil.Discard))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 0 { + t.Errorf("expected status 0 from wait but received %d", code) + } +} + +func TestShimOOMScore(t *testing.T) { + containerdPid := ctrd.cmd.Process.Pid + containerdScore, err := sys.GetOOMScoreAdj(containerdPid) + if err != nil { + t.Fatal(err) + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + path := "/containerd/oomshim" + var ( + cg cgroups.Cgroup + cg2 *cgroupsv2.Manager + ) + if cgroups.Mode() == cgroups.Unified { + cg2, err = cgroupsv2.NewManager("/sys/fs/cgroup", path, &cgroupsv2.Resources{}) + if err != nil { + t.Fatal(err) + } + defer cg2.Delete() + } else { + cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{}) + if err != nil { + t.Fatal(err) + } + defer cg.Delete() + } + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty(), WithShimCgroup(path)) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + expectedScore := containerdScore + 1 + if expectedScore > sys.OOMScoreAdjMax { + expectedScore = sys.OOMScoreAdjMax + } + + // find the shim's pid + if cgroups.Mode() == cgroups.Unified { + processes, err := cg2.Procs(false) + if err != nil { + t.Fatal(err) + } + for _, pid := range processes { + score, err := sys.GetOOMScoreAdj(int(pid)) + if err != nil { + t.Fatal(err) + } + if score != expectedScore { + t.Errorf("expected score %d but got %d for shim process", expectedScore, score) + } + } + } else { + processes, err := cg.Processes(cgroups.Devices, false) + if err != nil { + t.Fatal(err) + } + for _, p := range processes { + score, err := sys.GetOOMScoreAdj(p.Pid) + if err != nil { + t.Fatal(err) + } + if score != expectedScore { + t.Errorf("expected score %d but got %d for shim process", expectedScore, score) + } + } + } + + if err := task.Kill(ctx, unix.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestTaskSpec(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + spec, err := task.Spec(ctx) + if err != nil { + t.Fatal(err) + } + if spec == nil { + t.Fatal("spec from task is nil") + } + direct, err := newDirectIO(ctx, false) + if err != nil { + t.Fatal(err) + } + defer direct.Delete() + + lt, err := container.Task(ctx, direct.IOAttach) + if err != nil { + t.Fatal(err) + } + + spec, err = lt.Spec(ctx) + if err != nil { + t.Fatal(err) + } + if spec == nil { + t.Fatal("spec from loaded task is nil") + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC +} diff -Nru containerd-1.2.6/integration/client/container_test.go containerd-1.5.9/integration/client/container_test.go --- containerd-1.2.6/integration/client/container_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/container_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,1836 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "runtime" + "strings" + "syscall" + "testing" + "time" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + _ "github.com/containerd/containerd/runtime" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/typeurl" + specs "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/go-runc" + gogotypes "github.com/gogo/protobuf/types" +) + +func empty() cio.Creator { + // TODO (@mlaventure) windows searches for pipes + // when none are provided + if runtime.GOOS == "windows" { + return cio.NewCreator(cio.WithStdio) + } + return cio.NullIO +} + +func TestContainerList(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + + containers, err := client.Containers(ctx) + if err != nil { + t.Fatalf("container list returned error %v", err) + } + if len(containers) != 0 { + t.Errorf("expected 0 containers but received %d", len(containers)) + } +} + +func TestNewContainer(t *testing.T) { + t.Parallel() + + id := t.Name() + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ctx, cancel := testContext(t) + defer cancel() + + container, err := client.NewContainer(ctx, id, WithNewSpec()) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + if container.ID() != id { + t.Errorf("expected container id %q but received %q", id, container.ID()) + } + if _, err = container.Spec(ctx); err != nil { + t.Fatal(err) + } + if err := container.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestContainerStart(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if runtime.GOOS != "windows" { + // task.Pid not implemented on Windows + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } + } + + if err := task.Start(ctx); err != nil { + t.Error(err) + task.Delete(ctx) + return + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 7 { + t.Errorf("expected status 7 from wait but received %d", code) + } + + deleteStatus, err := task.Delete(ctx) + if err != nil { + t.Fatal(err) + } + if ec := deleteStatus.ExitCode(); ec != 7 { + t.Errorf("expected status 7 from delete but received %d", ec) + } +} + +func TestContainerOutput(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + expected = "kingkoye" + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("echo", expected))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + status := <-statusC + code, _, err := status.Result() + if code != 0 { + t.Errorf("expected status 0 but received %d: %v", code, err) + } + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + + actual := stdout.String() + // echo adds a new line + expected = expected + newLine + if actual != expected { + t.Errorf("expected output %q but received %q", expected, actual) + } +} + +func withByteBuffers(stdout io.Writer) cio.Opt { + // TODO: could this use ioutil.Discard? + return func(streams *cio.Streams) { + streams.Stdin = new(bytes.Buffer) + streams.Stdout = stdout + streams.Stderr = new(bytes.Buffer) + } +} + +func TestContainerExec(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + // start an exec process without running the original container process info + processSpec := spec.Process + withExecExitStatus(processSpec, 6) + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + processStatusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + + // wait for the exec to return + status := <-processStatusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + + if code != 6 { + t.Errorf("expected exec exit code 6 but received %d", code) + } + deleteStatus, err := process.Delete(ctx) + if err != nil { + t.Fatal(err) + } + if ec := deleteStatus.ExitCode(); ec != 6 { + t.Errorf("expected delete exit code 6 but received %d", ec) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finishedC +} +func TestContainerLargeExecArgs(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + processSpec := spec.Process + withExecArgs(processSpec, "echo", strings.Repeat("a", 20000)) + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + processStatusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + + // wait for the exec to return + status := <-processStatusC + if _, _, err := status.Result(); err != nil { + t.Fatal(err) + } + if _, err := process.Delete(ctx); err != nil { + t.Fatal(err) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finishedC +} + +func TestContainerPids(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + pid := task.Pid() + if pid < 1 { + t.Errorf("invalid task pid %d", pid) + } + processes, err := task.Pids(ctx) + switch runtime.GOOS { + case "windows": + // TODO: This is currently not implemented on windows + default: + if err != nil { + t.Fatal(err) + } + // 2 processes, 1 for sh and one for sleep + if l := len(processes); l != 2 { + t.Errorf("expected 2 process but received %d", l) + } + if len(processes) > 0 { + actual := processes[0].Pid + if pid != actual { + t.Errorf("expected pid %d but received %d", pid, actual) + } + } + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + select { + case s := <-statusC: + t.Log(s.Result()) + default: + } + t.Error(err) + } + <-statusC +} + +func TestContainerCloseIO(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat())) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + + task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(r, stdout, ioutil.Discard))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + w.Close() + if err := task.CloseIO(ctx, WithStdinCloser); err != nil { + t.Error(err) + } + + <-statusC +} + +func TestDeleteRunningContainer(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + err = container.Delete(ctx, WithSnapshotCleanup) + if err == nil { + t.Error("delete did not error with running task") + } + if !errdefs.IsFailedPrecondition(err) { + t.Errorf("expected error %q but received %q", errdefs.ErrFailedPrecondition, err) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC +} + +func TestContainerKill(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC + + err = task.Kill(ctx, syscall.SIGTERM) + if err == nil { + t.Fatal("second call to kill should return an error") + } + if !errdefs.IsNotFound(err) { + t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err) + } +} + +func TestKillContainerDeletedByRunc(t *testing.T) { + t.Parallel() + + if runtime.GOOS == "windows" { + t.Skip("Test relies on runc and is not supported on Windows") + } + + // We skip this case when runtime is crun. + // More information in https://github.com/containerd/containerd/pull/4214#discussion_r422769497 + if os.Getenv("RUNC_FLAVOR") == "crun" { + t.Skip("skip it when using crun") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + if client.Runtime() == plugin.RuntimeLinuxV1 { + t.Skip("test relies on runtime v2") + } + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + runcRoot = "/tmp/runc-test" + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), longCommand), + WithRuntime(client.Runtime(), &options.Options{Root: runcRoot})) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + rcmd := &runc.Runc{ + Root: path.Join(runcRoot, testNamespace), + } + + if err := rcmd.Delete(ctx, id, &runc.DeleteOpts{Force: true}); err != nil { + t.Fatal(err) + } + err = task.Kill(ctx, syscall.SIGKILL) + if err == nil { + t.Fatal("kill should return NotFound error") + } else if !errdefs.IsNotFound(err) { + t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err) + } + + select { + case <-statusC: + case <-time.After(2 * time.Second): + t.Errorf("unexpected timeout when try to get exited container's status") + } +} + +func TestContainerNoBinaryExists(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("nothing"))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + switch runtime.GOOS { + case "windows": + if err != nil { + t.Fatalf("failed to create task %v", err) + } + defer task.Delete(ctx, WithProcessKill) + if err := task.Start(ctx); err == nil { + t.Error("task.Start() should return an error when binary does not exist") + } + default: + if err == nil { + t.Error("NewTask should return an error when binary does not exist") + task.Delete(ctx) + } + } +} + +func TestContainerExecNoBinaryExists(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + // start an exec process without running the original container process + processSpec := spec.Process + processSpec.Args = []string{ + "none", + } + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + defer process.Delete(ctx) + if err := process.Start(ctx); err == nil { + t.Error("Process.Start should fail when process does not exist") + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finishedC +} + +func TestWaitStoppedTask(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if runtime.GOOS != "windows" { + // Getting the pid is not currently implemented on windows + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } + } + if err := task.Start(ctx); err != nil { + t.Error(err) + task.Delete(ctx) + return + } + + // wait for the task to stop then call wait again + <-statusC + statusC, err = task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 7 { + t.Errorf("exit status from stopped task should be 7 but received %d", code) + } +} + +func TestWaitStoppedProcess(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + // start an exec process without running the original container process info + processSpec := spec.Process + withExecExitStatus(processSpec, 6) + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + defer process.Delete(ctx) + + statusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + + // wait for the exec to return + <-statusC + + // try to wait on the process after it has stopped + statusC, err = process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 6 { + t.Errorf("exit status from stopped process should be 6 but received %d", code) + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finishedC +} + +func TestTaskForceDelete(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + if _, err := task.Delete(ctx); err == nil { + t.Error("task.Delete of a running task should create an error") + } + if _, err := task.Delete(ctx, WithProcessKill); err != nil { + t.Fatal(err) + } +} + +func TestProcessForceDelete(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + // task must be started on windows + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + processSpec := spec.Process + if runtime.GOOS == "windows" { + withExecArgs(processSpec, "cmd", "/c", "ping -t localhost") + } else { + withExecArgs(processSpec, "/bin/sh", "-c", "while true; do sleep 1; done") + } + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + if _, err := process.Delete(ctx); err == nil { + t.Error("process.Delete should return an error when process is running") + } + if _, err := process.Delete(ctx, WithProcessKill); err != nil { + t.Error(err) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + <-statusC +} + +func TestContainerHostname(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + expected = "myhostname" + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), + withProcessArgs("hostname"), + oci.WithHostname(expected), + )) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout))) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 0 { + t.Errorf("expected status 0 but received %d", code) + } + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + cutset := "\n" + if runtime.GOOS == "windows" { + cutset = "\r\n" + } + + actual := strings.TrimSuffix(stdout.String(), cutset) + if actual != expected { + t.Errorf("expected output %q but received %q", expected, actual) + } +} + +func TestContainerExitedAtSet(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withTrue())) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + startTime := time.Now() + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + status := <-statusC + code, _, err := status.Result() + if code != 0 { + t.Errorf("expected status 0 but received %d (err: %v)", code, err) + } + + if s, err := task.Status(ctx); err != nil { + t.Errorf("failed to retrieve status: %v", err) + } else if s.ExitTime.After(startTime) == false { + t.Errorf("exit time is not after start time: %v <= %v", startTime, s.ExitTime) + } + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestDeleteContainerExecCreated(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finished, err := task.Wait(ctx) + if err != nil { + t.Error(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + // start an exec process without running the original container process info + processSpec := spec.Process + withExecExitStatus(processSpec, 6) + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, empty()) + if err != nil { + t.Fatal(err) + } + deleteStatus, err := process.Delete(ctx) + if err != nil { + t.Fatal(err) + } + if ec := deleteStatus.ExitCode(); ec != 0 { + t.Errorf("expected delete exit code 0 but received %d", ec) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finished +} + +func TestContainerMetrics(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("metrics are currently not supported on windows") + } + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx, WithProcessKill) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + metric, err := task.Metrics(ctx) + if err != nil { + t.Error(err) + return + } + if metric.ID != id { + t.Errorf("expected metric id %q but received %q", id, metric.ID) + } + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestDeletedContainerMetrics(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("metrics are currently not supported on windows") + } + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withExitStatus(0))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + <-statusC + + if _, err := task.Delete(ctx); err != nil { + t.Fatal(err) + } + + if _, err := task.Metrics(ctx); err == nil { + t.Errorf("Getting metrics of deleted task should have failed") + } +} + +func TestContainerExtensions(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + ext := gogotypes.Any{TypeUrl: "test.ext.url", Value: []byte("hello")} + container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerExtension("hello", &ext)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + checkExt := func(container Container) { + cExts, err := container.Extensions(ctx) + if err != nil { + t.Fatal(err) + } + if len(cExts) != 1 { + t.Errorf("expected 1 container extension") + } + if cExts["hello"].TypeUrl != ext.TypeUrl { + t.Errorf("got unexpected type url for extension: %s", cExts["hello"].TypeUrl) + } + if !bytes.Equal(cExts["hello"].Value, ext.Value) { + t.Errorf("expected extension value %q, got: %q", ext.Value, cExts["hello"].Value) + } + } + + checkExt(container) + + container, err = client.LoadContainer(ctx, container.ID()) + if err != nil { + t.Fatal(err) + } + checkExt(container) +} + +func TestContainerUpdate(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + container, err := client.NewContainer(ctx, id, WithNewSpec()) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + const hostname = "updated-hostname" + spec.Hostname = hostname + + if err := container.Update(ctx, func(ctx context.Context, client *Client, c *containers.Container) error { + a, err := typeurl.MarshalAny(spec) + if err != nil { + return err + } + c.Spec = a + return nil + }); err != nil { + t.Fatal(err) + } + if spec, err = container.Spec(ctx); err != nil { + t.Fatal(err) + } + if spec.Hostname != hostname { + t.Errorf("hostname %q != %q", spec.Hostname, hostname) + } +} + +func TestContainerInfo(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + container, err := client.NewContainer(ctx, id, WithNewSpec()) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + info, err := container.Info(ctx) + if err != nil { + t.Fatal(err) + } + if info.ID != container.ID() { + t.Fatalf("info.ID=%s != container.ID()=%s", info.ID, container.ID()) + } +} + +func TestContainerLabels(t *testing.T) { + t.Parallel() + + ctx, cancel := testContext(t) + defer cancel() + id := t.Name() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerLabels(map[string]string{ + "test": "yes", + })) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + labels, err := container.Labels(ctx) + if err != nil { + t.Fatal(err) + } + if labels["test"] != "yes" { + t.Fatalf("expected label \"test\" to be \"yes\"") + } + labels["test"] = "no" + if labels, err = container.SetLabels(ctx, labels); err != nil { + t.Fatal(err) + } + if labels["test"] != "no" { + t.Fatalf("expected label \"test\" to be \"no\"") + } +} + +func TestContainerHook(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + hook := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + if s.Hooks == nil { + s.Hooks = &specs.Hooks{} + } + path, err := exec.LookPath("containerd") + if err != nil { + return err + } + psPath, err := exec.LookPath("ps") + if err != nil { + return err + } + s.Hooks.Prestart = []specs.Hook{ + { + Path: path, + Args: []string{ + "containerd", + "oci-hook", "--", + psPath, "--pid", "{{pid}}", + }, + Env: os.Environ(), + }, + } + return nil + } + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), hook)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx, WithProcessKill) +} + +func TestShimSockLength(t *testing.T) { + t.Parallel() + + // Max length of namespace should be 76 + namespace := strings.Repeat("n", 76) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + ctx = namespaces.WithNamespace(ctx, namespace) + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + image, err := client.Pull(ctx, testImage, + WithPlatformMatcher(platforms.Default()), + WithPullUnpack, + ) + if err != nil { + t.Fatal(err) + } + + id := strings.Repeat("c", 64) + + // We don't have limitation with length of container name, + // but 64 bytes of sha256 is the common case + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withExitStatus(0)), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + <-statusC +} + +func TestContainerExecLargeOutputWithTTY(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Test does not run on Windows") + } + + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + for i := 0; i < 100; i++ { + spec, err := container.Spec(ctx) + if err != nil { + t.Fatal(err) + } + + // start an exec process without running the original container process info + processSpec := spec.Process + withExecArgs(processSpec, "sh", "-c", `seq -s " " 1000000`) + + stdout := bytes.NewBuffer(nil) + + execID := t.Name() + "_exec" + process, err := task.Exec(ctx, execID, processSpec, cio.NewCreator(withByteBuffers(stdout), withProcessTTY())) + if err != nil { + t.Fatal(err) + } + processStatusC, err := process.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := process.Start(ctx); err != nil { + t.Fatal(err) + } + + // wait for the exec to return + status := <-processStatusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + + if code != 0 { + t.Errorf("expected exec exit code 0 but received %d", code) + } + if _, err := process.Delete(ctx); err != nil { + t.Fatal(err) + } + + const expectedSuffix = "999999 1000000" + stdoutString := stdout.String() + if !strings.Contains(stdoutString, expectedSuffix) { + t.Fatalf("process output does not end with %q at iteration %d, here are the last 20 characters of the output:\n\n %q", expectedSuffix, i, stdoutString[len(stdoutString)-20:]) + } + + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-finishedC +} + +func TestShortRunningTaskPid(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), shortCommand)) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + finishedC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + int32PID := int32(task.Pid()) + if int32PID <= 0 { + t.Errorf("Unexpected task pid %d", int32PID) + } + <-finishedC +} + +func withProcessTTY() cio.Opt { + return func(opt *cio.Streams) { + cio.WithTerminal(opt) + } +} diff -Nru containerd-1.2.6/integration/client/content_test.go containerd-1.5.9/integration/client/content_test.go --- containerd-1.2.6/integration/client/content_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/content_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "sync/atomic" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/content/testsuite" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/namespaces" + "github.com/pkg/errors" +) + +func newContentStore(ctx context.Context, root string) (context.Context, content.Store, func() error, error) { + client, err := New(address) + if err != nil { + return nil, nil, nil, err + } + + var ( + count uint64 + cs = client.ContentStore() + name = testsuite.Name(ctx) + ) + + wrap := func(ctx context.Context) (context.Context, func(context.Context) error, error) { + n := atomic.AddUint64(&count, 1) + ctx = namespaces.WithNamespace(ctx, fmt.Sprintf("%s-n%d", name, n)) + return client.WithLease(ctx) + } + + ctx = testsuite.SetContextWrapper(ctx, wrap) + + return ctx, cs, func() error { + for i := uint64(1); i <= count; i++ { + ctx = namespaces.WithNamespace(ctx, fmt.Sprintf("%s-n%d", name, i)) + statuses, err := cs.ListStatuses(ctx) + if err != nil { + return err + } + for _, st := range statuses { + if err := cs.Abort(ctx, st.Ref); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to abort %s", st.Ref) + } + } + err = cs.Walk(ctx, func(info content.Info) error { + if err := cs.Delete(ctx, info.Digest); err != nil { + if errdefs.IsNotFound(err) { + return nil + } + + return err + } + return nil + }) + if err != nil { + return err + } + } + return nil + + }, nil +} + +func TestContentClient(t *testing.T) { + if testing.Short() { + t.Skip() + } + testsuite.ContentSuite(t, "ContentClient", newContentStore) +} diff -Nru containerd-1.2.6/integration/client/convert_test.go containerd-1.5.9/integration/client/convert_test.go --- containerd-1.2.6/integration/client/convert_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/convert_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/images/converter" + "github.com/containerd/containerd/images/converter/uncompress" + "github.com/containerd/containerd/platforms" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "gotest.tools/v3/assert" +) + +// TestConvert creates an image from testImage, with the following conversion: +// - Media type: Docker -> OCI +// - Layer type: tar.gz -> tar +// - Arch: Multi -> Single +func TestConvert(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx, cancel := testContext(t) + defer cancel() + + client, err := New(address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + _, err = client.Fetch(ctx, testImage) + if err != nil { + t.Fatal(err) + } + dstRef := testImage + "-testconvert" + defPlat := platforms.DefaultStrict() + opts := []converter.Opt{ + converter.WithDockerToOCI(true), + converter.WithLayerConvertFunc(uncompress.LayerConvertFunc), + converter.WithPlatform(defPlat), + } + dstImg, err := converter.Convert(ctx, client, dstRef, testImage, opts...) + if err != nil { + t.Fatal(err) + } + defer func() { + if deleteErr := client.ImageService().Delete(ctx, dstRef); deleteErr != nil { + t.Fatal(deleteErr) + } + }() + cs := client.ContentStore() + plats, err := images.Platforms(ctx, cs, dstImg.Target) + if err != nil { + t.Fatal(err) + } + // Assert that the image does not have any extra arch. + assert.Equal(t, 1, len(plats)) + assert.Check(t, defPlat.Match(plats[0])) + + // Assert that the media type is converted to OCI and also uncompressed + mani, err := images.Manifest(ctx, cs, dstImg.Target, defPlat) + if err != nil { + t.Fatal(err) + } + for _, l := range mani.Layers { + if plats[0].OS == "windows" { + assert.Equal(t, ocispec.MediaTypeImageLayerNonDistributable, l.MediaType) + } else { + assert.Equal(t, ocispec.MediaTypeImageLayer, l.MediaType) + } + } +} diff -Nru containerd-1.2.6/integration/client/daemon_config_linux_test.go containerd-1.5.9/integration/client/daemon_config_linux_test.go --- containerd-1.2.6/integration/client/daemon_config_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/daemon_config_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,268 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" + "testing" + "time" + + "github.com/containerd/cgroups" + . "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/runtime/v2/runc/options" + srvconfig "github.com/containerd/containerd/services/server/config" +) + +// the following nolint is for shutting up gometalinter on non-linux. +// nolint: unused +func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) { + if testing.Short() { + t.Skip() + } + testutil.RequiresRoot(t) + var ( + ctrd = daemon{} + configTOMLDecoded srvconfig.Config + buf = bytes.NewBuffer(nil) + ) + + tempDir, err := ioutil.TempDir("", "containerd-test-new-daemon-with-config") + if err != nil { + t.Fatal(err) + } + defer func() { + if err != nil { + os.RemoveAll(tempDir) + } + }() + + configTOMLFile := filepath.Join(tempDir, "config.toml") + if err = ioutil.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil { + t.Fatal(err) + } + + if err = srvconfig.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil { + t.Fatal(err) + } + + address := configTOMLDecoded.GRPC.Address + if address == "" { + address = filepath.Join(tempDir, "containerd.sock") + } + args := []string{"-c", configTOMLFile} + if configTOMLDecoded.Root == "" { + args = append(args, "--root", filepath.Join(tempDir, "root")) + } + if configTOMLDecoded.State == "" { + args = append(args, "--state", filepath.Join(tempDir, "state")) + } + if err = ctrd.start("containerd", address, args, buf, buf); err != nil { + t.Fatalf("%v: %s", err, buf.String()) + } + + waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second) + client, err := ctrd.waitForStart(waitCtx) + waitCancel() + if err != nil { + ctrd.Kill() + ctrd.Wait() + t.Fatalf("%v: %s", err, buf.String()) + } + + cleanup := func() { + if err := client.Close(); err != nil { + t.Fatalf("failed to close client: %v", err) + } + if err := ctrd.Stop(); err != nil { + if err := ctrd.Kill(); err != nil { + t.Fatalf("failed to signal containerd: %v", err) + } + } + if err := ctrd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); !ok { + t.Fatalf("failed to wait for: %v", err) + } + } + if err := os.RemoveAll(tempDir); err != nil { + t.Fatalf("failed to remove %s: %v", tempDir, err) + } + // cleaning config-specific resources is up to the caller + } + return client, &ctrd, cleanup +} + +// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored +func TestDaemonRuntimeRoot(t *testing.T) { + runtimeRoot, err := ioutil.TempDir("", "containerd-test-runtime-root") + if err != nil { + t.Fatal(err) + } + defer func() { + if err != nil { + os.RemoveAll(runtimeRoot) + } + }() + configTOML := ` +version = 2 +[plugins] + [plugins."io.containerd.grpc.v1.cri"] + stream_server_port = "0" +` + + client, _, cleanup := newDaemonWithConfig(t, configTOML) + defer cleanup() + + ctx, cancel := testContext(t) + defer cancel() + // FIXME(AkihiroSuda): import locally frozen image? + image, err := client.Pull(ctx, testImage, WithPullUnpack) + if err != nil { + t.Fatal(err) + } + + id := t.Name() + container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithRuntime(plugin.RuntimeRuncV1, &options.Options{ + Root: runtimeRoot, + })) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + status, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + containerPath := filepath.Join(runtimeRoot, testNamespace, id) + if _, err = os.Stat(containerPath); err != nil { + t.Errorf("error while getting stat for %s: %v", containerPath, err) + } + + if err = task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + <-status +} + +// code most copy from https://github.com/opencontainers/runc +func getCgroupPath() (map[string]string, error) { + cgroupPath := make(map[string]string) + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return nil, err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + text := scanner.Text() + fields := strings.Split(text, " ") + // Safe as mountinfo encodes mountpoints with spaces as \040. + index := strings.Index(text, " - ") + postSeparatorFields := strings.Fields(text[index+3:]) + numPostFields := len(postSeparatorFields) + + // This is an error as we can't detect if the mount is for "cgroup" + if numPostFields == 0 { + continue + } + + if postSeparatorFields[0] == "cgroup" { + // Check that the mount is properly formatted. + if numPostFields < 3 { + continue + } + cgroupPath[filepath.Base(fields[4])] = fields[4] + } + } + + return cgroupPath, nil +} + +// TestDaemonCustomCgroup ensures plugin.cgroup.path is not ignored +func TestDaemonCustomCgroup(t *testing.T) { + if cgroups.Mode() == cgroups.Unified { + t.Skip("test requires cgroup1") + } + cgroupPath, err := getCgroupPath() + if err != nil { + t.Fatal(err) + } + if len(cgroupPath) == 0 { + t.Skip("skip TestDaemonCustomCgroup since no cgroup path available") + } + + customCgroup := fmt.Sprintf("%d", time.Now().Nanosecond()) + configTOML := ` +version = 2 +[cgroup] + path = "` + customCgroup + `"` + + _, _, cleanup := newDaemonWithConfig(t, configTOML) + + defer func() { + // do cgroup path clean + for _, v := range cgroupPath { + if _, err := os.Stat(filepath.Join(v, customCgroup)); err == nil { + if err := os.RemoveAll(filepath.Join(v, customCgroup)); err != nil { + t.Logf("failed to remove cgroup path %s", filepath.Join(v, customCgroup)) + } + } + } + }() + + defer cleanup() + + paths := []string{ + "devices", + "memory", + "cpu", + "blkio", + } + + for _, p := range paths { + v := cgroupPath[p] + if v == "" { + continue + } + path := filepath.Join(v, customCgroup) + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + t.Fatalf("custom cgroup path %s should exist, actually not", path) + } + } + } +} diff -Nru containerd-1.2.6/integration/client/daemon_test.go containerd-1.5.9/integration/client/daemon_test.go --- containerd-1.2.6/integration/client/daemon_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/daemon_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "io" + "os/exec" + "sync" + "syscall" + + . "github.com/containerd/containerd" + "github.com/pkg/errors" +) + +type daemon struct { + sync.Mutex + addr string + cmd *exec.Cmd +} + +func (d *daemon) start(name, address string, args []string, stdout, stderr io.Writer) error { + d.Lock() + defer d.Unlock() + if d.cmd != nil { + return errors.New("daemon is already running") + } + args = append(args, []string{"--address", address}...) + cmd := exec.Command(name, args...) + cmd.Stdout = stdout + cmd.Stderr = stderr + if err := cmd.Start(); err != nil { + cmd.Wait() + return errors.Wrap(err, "failed to start daemon") + } + d.addr = address + d.cmd = cmd + return nil +} + +func (d *daemon) waitForStart(ctx context.Context) (*Client, error) { + var ( + client *Client + serving bool + err error + ) + + client, err = New(d.addr) + if err != nil { + return nil, err + } + serving, err = client.IsServing(ctx) + if !serving { + client.Close() + if err == nil { + err = errors.New("connection was successful but service is not available") + } + return nil, err + } + return client, err +} + +func (d *daemon) Stop() error { + d.Lock() + defer d.Unlock() + if d.cmd == nil { + return errors.New("daemon is not running") + } + return d.cmd.Process.Signal(syscall.SIGTERM) +} + +func (d *daemon) Kill() error { + d.Lock() + defer d.Unlock() + if d.cmd == nil { + return errors.New("daemon is not running") + } + return d.cmd.Process.Kill() +} + +func (d *daemon) Wait() error { + d.Lock() + defer d.Unlock() + if d.cmd == nil { + return errors.New("daemon is not running") + } + err := d.cmd.Wait() + d.cmd = nil + return err +} + +func (d *daemon) Restart(stopCb func()) error { + d.Lock() + defer d.Unlock() + if d.cmd == nil { + return errors.New("daemon is not running") + } + + var err error + if err = d.cmd.Process.Signal(syscall.SIGTERM); err != nil { + return errors.Wrap(err, "failed to signal daemon") + } + + d.cmd.Wait() + + if stopCb != nil { + stopCb() + } + + cmd := exec.Command(d.cmd.Path, d.cmd.Args[1:]...) + cmd.Stdout = d.cmd.Stdout + cmd.Stderr = d.cmd.Stderr + if err := cmd.Start(); err != nil { + cmd.Wait() + return errors.Wrap(err, "failed to start new daemon instance") + } + d.cmd = cmd + + return nil +} diff -Nru containerd-1.2.6/integration/client/export_test.go containerd-1.5.9/integration/client/export_test.go --- containerd-1.2.6/integration/client/export_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/export_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "archive/tar" + "bytes" + "io" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/images/archive" + "github.com/containerd/containerd/platforms" +) + +// TestExport exports testImage as a tar stream +func TestExport(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx, cancel := testContext(t) + defer cancel() + + client, err := New(address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + _, err = client.Fetch(ctx, testImage) + if err != nil { + t.Fatal(err) + } + wb := bytes.NewBuffer(nil) + err = client.Export(ctx, wb, archive.WithPlatform(platforms.Default()), archive.WithImage(client.ImageService(), testImage)) + if err != nil { + t.Fatal(err) + } + assertOCITar(t, bytes.NewReader(wb.Bytes())) +} + +func assertOCITar(t *testing.T, r io.Reader) { + // TODO: add more assertion + tr := tar.NewReader(r) + foundOCILayout := false + foundIndexJSON := false + for { + h, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + t.Error(err) + continue + } + if h.Name == "oci-layout" { + foundOCILayout = true + } + if h.Name == "index.json" { + foundIndexJSON = true + } + } + if !foundOCILayout { + t.Error("oci-layout not found") + } + if !foundIndexJSON { + t.Error("index.json not found") + } +} diff -Nru containerd-1.2.6/integration/client/go.mod containerd-1.5.9/integration/client/go.mod --- containerd-1.2.6/integration/client/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,41 @@ +module github.com/containerd/containerd/integration/client + +go 1.15 + +require ( + github.com/Microsoft/hcsshim v0.8.23 + github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 + github.com/containerd/cgroups v1.0.1 + // the actual version of containerd is replaced with the code at the root of this repository + github.com/containerd/containerd v1.5.1 + github.com/containerd/go-runc v1.0.0 + github.com/containerd/ttrpc v1.1.0 + github.com/containerd/typeurl v1.0.2 + github.com/gogo/protobuf v1.3.2 + github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/image-spec v1.0.2 + github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.8.1 + golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 + gotest.tools/v3 v3.0.3 +) + +replace ( + // use the containerd module from this repository instead of downloading + // + // IMPORTANT: this replace rule ONLY replaces containerd itself; dependencies + // in the "require" section above are still taken into account for version + // resolution if newer. + github.com/containerd/containerd => ../../ + + // Replace rules below must be kept in sync with the main go.mod file at the + // root, because that's the actual version expected by the "containerd/containerd" + // dependency above. + github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2 + github.com/golang/protobuf => github.com/golang/protobuf v1.3.5 + // urfave/cli must be <= v1.22.1 due to a regression: https://github.com/urfave/cli/issues/1092 + github.com/urfave/cli => github.com/urfave/cli v1.22.1 + google.golang.org/genproto => google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 + google.golang.org/grpc => google.golang.org/grpc v1.27.1 +) diff -Nru containerd-1.2.6/integration/client/go.sum containerd-1.5.9/integration/client/go.sum --- containerd-1.2.6/integration/client/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,702 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 h1:pVKfKyPkXna29XlGjxSr9J0A7vNucOUHZ/2ClcTWalw= +github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1/go.mod h1:Cmvnhlie15Ha2UYrJs9EhgSx76Bq9RV2FgfEiT78GhI= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0 h1:oU+lLv1ULm5taqgV/CJivypVODI4SUz1znWjv3nNYS0= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0 h1:GbtyLRxb0gOLR0TYQWt3O6B0NvT8tMdorEHqIQo/lWI= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c= +github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 h1:YzfoEYWbODU5Fbt37+h7X16BWQbad7Q4S6gclTKFXM8= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/integration/client/helpers_unix_test.go containerd-1.5.9/integration/client/helpers_unix_test.go --- containerd-1.2.6/integration/client/helpers_unix_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/helpers_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +const newLine = "\n" + +func withExitStatus(es int) oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Process.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)} + return nil + } +} + +func withProcessArgs(args ...string) oci.SpecOpts { + return oci.WithProcessArgs(args...) +} + +func withCat() oci.SpecOpts { + return oci.WithProcessArgs("cat") +} + +func withTrue() oci.SpecOpts { + return oci.WithProcessArgs("true") +} + +func withExecExitStatus(s *specs.Process, es int) { + s.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)} +} + +func withExecArgs(s *specs.Process, args ...string) { + s.Args = args +} diff -Nru containerd-1.2.6/integration/client/helpers_windows_test.go containerd-1.5.9/integration/client/helpers_windows_test.go --- containerd-1.2.6/integration/client/helpers_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/helpers_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "strconv" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +const newLine = "\r\n" + +func withExitStatus(es int) oci.SpecOpts { + return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error { + s.Process.Args = []string{"cmd", "/c", "exit", strconv.Itoa(es)} + return nil + } +} + +func withProcessArgs(args ...string) oci.SpecOpts { + return oci.WithProcessArgs(append([]string{"cmd", "/c"}, args...)...) +} + +func withCat() oci.SpecOpts { + return oci.WithProcessArgs("cmd", "/c", "more") +} + +func withTrue() oci.SpecOpts { + return oci.WithProcessArgs("cmd", "/c") +} + +func withExecExitStatus(s *specs.Process, es int) { + s.Args = []string{"cmd", "/c", "exit", strconv.Itoa(es)} +} + +func withExecArgs(s *specs.Process, args ...string) { + s.Args = append([]string{"cmd", "/c"}, args...) +} diff -Nru containerd-1.2.6/integration/client/image_test.go containerd-1.5.9/integration/client/image_test.go --- containerd-1.2.6/integration/client/image_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/image_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,265 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "runtime" + "strings" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +func TestImageIsUnpacked(t *testing.T) { + const imageName = "k8s.gcr.io/pause:3.5" + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + // Cleanup + opts := []images.DeleteOpt{images.SynchronousDelete()} + err = client.ImageService().Delete(ctx, imageName, opts...) + if err != nil && !errdefs.IsNotFound(err) { + t.Fatal(err) + } + + // By default pull does not unpack an image + image, err := client.Pull(ctx, imageName, WithPlatformMatcher(platforms.Default())) + if err != nil { + t.Fatal(err) + } + + // Check that image is not unpacked + unpacked, err := image.IsUnpacked(ctx, DefaultSnapshotter) + if err != nil { + t.Fatal(err) + } + if unpacked { + t.Fatalf("image should not be unpacked") + } + + // Check that image is unpacked + err = image.Unpack(ctx, DefaultSnapshotter) + if err != nil { + t.Fatal(err) + } + unpacked, err = image.IsUnpacked(ctx, DefaultSnapshotter) + if err != nil { + t.Fatal(err) + } + if !unpacked { + t.Fatalf("image should be unpacked") + } +} + +func TestImagePullWithDistSourceLabel(t *testing.T) { + var ( + source = "k8s.gcr.io" + repoName = "pause" + tag = "3.5" + ) + + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + imageName := fmt.Sprintf("%s/%s:%s", source, repoName, tag) + pMatcher := platforms.Default() + + // pull content without unpack and add distribution source label + image, err := client.Pull(ctx, imageName, WithPlatformMatcher(pMatcher)) + if err != nil { + t.Fatal(err) + } + defer client.ImageService().Delete(ctx, imageName) + + cs := client.ContentStore() + key := fmt.Sprintf("containerd.io/distribution.source.%s", source) + + // only check the target platform + childrenHandler := images.LimitManifests(images.ChildrenHandler(cs), pMatcher, 1) + + checkLabelHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + children, err := childrenHandler(ctx, desc) + if err != nil { + return nil, err + } + + info, err := cs.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + + // check the label + if got := info.Labels[key]; !strings.Contains(got, repoName) { + return nil, fmt.Errorf("expected to have %s repo name in label, but got %s", repoName, got) + } + return children, nil + } + + if err := images.Dispatch(ctx, images.HandlerFunc(checkLabelHandler), nil, image.Target()); err != nil { + t.Fatal(err) + } +} + +func TestImageUsage(t *testing.T) { + if testing.Short() { + t.Skip() + } + + imageName := "k8s.gcr.io/pause:3.5" + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + // Cleanup + err = client.ImageService().Delete(ctx, imageName, images.SynchronousDelete()) + if err != nil && !errdefs.IsNotFound(err) { + t.Fatal(err) + } + + pMatcher := platforms.Default() + + // Pull single platform, do not unpack + image, err := client.Pull(ctx, imageName, WithPlatformMatcher(pMatcher)) + if err != nil { + t.Fatal(err) + } + + s1, err := image.Usage(ctx, WithUsageManifestLimit(1)) + if err != nil { + t.Fatal(err) + } + + if _, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage()); err == nil { + t.Fatal("expected NotFound with missing manifests") + } else if !errdefs.IsNotFound(err) { + t.Fatalf("unexpected error: %+v", err) + } + + // Pin image name to specific version for future fetches + imageName = imageName + "@" + image.Target().Digest.String() + defer client.ImageService().Delete(ctx, imageName, images.SynchronousDelete()) + + // Fetch single platforms, but all manifests pulled + if _, err := client.Fetch(ctx, imageName, WithPlatformMatcher(pMatcher), WithAllMetadata()); err != nil { + t.Fatal(err) + } + + if s, err := image.Usage(ctx, WithUsageManifestLimit(1)); err != nil { + t.Fatal(err) + } else if s != s1 { + t.Fatalf("unexpected usage %d, expected %d", s, s1) + } + + s2, err := image.Usage(ctx, WithUsageManifestLimit(0)) + if err != nil { + t.Fatal(err) + } + + if s2 <= s1 { + t.Fatalf("Expected larger usage counting all manifests: %d <= %d", s2, s1) + } + + s3, err := image.Usage(ctx, WithUsageManifestLimit(0), WithManifestUsage()) + if err != nil { + t.Fatal(err) + } + + if s3 <= s2 { + t.Fatalf("Expected larger usage counting all manifest reported sizes: %d <= %d", s3, s2) + } + + // Fetch everything + if _, err = client.Fetch(ctx, imageName); err != nil { + t.Fatal(err) + } + + if s, err := image.Usage(ctx); err != nil { + t.Fatal(err) + } else if s != s3 { + t.Fatalf("Expected actual usage to equal manifest reported usage of %d: got %d", s3, s) + } + + err = image.Unpack(ctx, DefaultSnapshotter) + if err != nil { + t.Fatal(err) + } + + if s, err := image.Usage(ctx, WithSnapshotUsage()); err != nil { + t.Fatal(err) + } else if s <= s3 { + t.Fatalf("Expected actual usage with snapshots to be greater: %d <= %d", s, s3) + } +} + +func TestImageSupportedBySnapshotter_Error(t *testing.T) { + var unsupportedImage string + if runtime.GOOS == "windows" { + unsupportedImage = "k8s.gcr.io/pause-amd64:3.2" + } else { + unsupportedImage = "mcr.microsoft.com/windows/nanoserver:1809" + } + + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + // Cleanup + err = client.ImageService().Delete(ctx, unsupportedImage) + if err != nil && !errdefs.IsNotFound(err) { + t.Fatal(err) + } + + _, err = client.Pull(ctx, unsupportedImage, + WithSchema1Conversion, + WithPlatform(platforms.DefaultString()), + WithPullSnapshotter(DefaultSnapshotter), + WithPullUnpack, + WithUnpackOpts([]UnpackOpt{WithSnapshotterPlatformCheck()}), + ) + + if err == nil { + t.Fatalf("expected unpacking %s for snapshotter %s to fail", unsupportedImage, DefaultSnapshotter) + } +} diff -Nru containerd-1.2.6/integration/client/import_test.go containerd-1.5.9/integration/client/import_test.go --- containerd-1.2.6/integration/client/import_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/import_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,373 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "bytes" + "context" + "encoding/json" + "io" + + "io/ioutil" + "math/rand" + "reflect" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/archive/compression" + "github.com/containerd/containerd/archive/tartest" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/images/archive" + digest "github.com/opencontainers/go-digest" + specs "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// TestExportAndImport exports testImage as a tar stream, +// and import the tar stream as a new image. +func TestExportAndImport(t *testing.T) { + if testing.Short() { + t.Skip() + } + ctx, cancel := testContext(t) + defer cancel() + + client, err := New(address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + _, err = client.Fetch(ctx, testImage) + if err != nil { + t.Fatal(err) + } + + wb := bytes.NewBuffer(nil) + err = client.Export(ctx, wb, archive.WithAllPlatforms(), archive.WithImage(client.ImageService(), testImage)) + if err != nil { + t.Fatal(err) + } + + opts := []ImportOpt{ + WithImageRefTranslator(archive.AddRefPrefix("foo/bar")), + } + imgrecs, err := client.Import(ctx, bytes.NewReader(wb.Bytes()), opts...) + if err != nil { + t.Fatalf("Import failed: %+v", err) + } + + for _, imgrec := range imgrecs { + if imgrec.Name == testImage { + continue + } + err = client.ImageService().Delete(ctx, imgrec.Name) + if err != nil { + t.Fatal(err) + } + } +} + +func TestImport(t *testing.T) { + ctx, cancel := testContext(t) + defer cancel() + + client, err := New(address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + tc := tartest.TarContext{} + + b1, d1 := createContent(256, 1) + empty := []byte("{}") + version := []byte("1.0") + + c1, d2 := createConfig() + + m1, d3, expManifest := createManifest(c1, [][]byte{b1}) + + provider := client.ContentStore() + + checkManifest := func(ctx context.Context, t *testing.T, d ocispec.Descriptor, expManifest *ocispec.Manifest) { + m, err := images.Manifest(ctx, provider, d, nil) + if err != nil { + t.Fatalf("unable to read target blob: %+v", err) + } + + if m.Config.Digest != d2 { + t.Fatalf("unexpected digest hash %s, expected %s", m.Config.Digest, d2) + } + + if len(m.Layers) != 1 { + t.Fatalf("expected 1 layer, has %d", len(m.Layers)) + } + + if m.Layers[0].Digest != d1 { + t.Fatalf("unexpected layer hash %s, expected %s", m.Layers[0].Digest, d1) + } + + if expManifest != nil { + if !reflect.DeepEqual(m.Layers, expManifest.Layers) { + t.Fatalf("DeepEqual on Layers failed: %v vs. %v", m.Layers, expManifest.Layers) + } + if !reflect.DeepEqual(m.Config, expManifest.Config) { + t.Fatalf("DeepEqual on Config failed: %v vs. %v", m.Config, expManifest.Config) + } + } + } + + for _, tc := range []struct { + Name string + Writer tartest.WriterToTar + Check func(*testing.T, []images.Image) + Opts []ImportOpt + }{ + { + Name: "DockerV2.0", + Writer: tartest.TarAll( + tc.Dir("bd765cd43e95212f7aa2cab51d0a", 0755), + tc.File("bd765cd43e95212f7aa2cab51d0a/json", empty, 0644), + tc.File("bd765cd43e95212f7aa2cab51d0a/layer.tar", b1, 0644), + tc.File("bd765cd43e95212f7aa2cab51d0a/VERSION", version, 0644), + tc.File("repositories", []byte(`{"any":{"1":"bd765cd43e95212f7aa2cab51d0a"}}`), 0644), + ), + }, + { + Name: "DockerV2.1", + Writer: tartest.TarAll( + tc.Dir("bd765cd43e95212f7aa2cab51d0a", 0755), + tc.File("bd765cd43e95212f7aa2cab51d0a/json", empty, 0644), + tc.File("bd765cd43e95212f7aa2cab51d0a/layer.tar", b1, 0644), + tc.File("bd765cd43e95212f7aa2cab51d0a/VERSION", version, 0644), + tc.File("e95212f7aa2cab51d0abd765cd43.json", c1, 0644), + tc.File("manifest.json", []byte(`[{"Config":"e95212f7aa2cab51d0abd765cd43.json","RepoTags":["test-import:notlatest", "another/repo:tag"],"Layers":["bd765cd43e95212f7aa2cab51d0a/layer.tar"]}]`), 0644), + ), + Check: func(t *testing.T, imgs []images.Image) { + if len(imgs) == 0 { + t.Fatalf("no images") + } + + names := []string{ + "docker.io/library/test-import:notlatest", + "docker.io/another/repo:tag", + } + + checkImages(t, imgs[0].Target.Digest, imgs, names...) + checkManifest(ctx, t, imgs[0].Target, nil) + }, + }, + { + Name: "OCI-BadFormat", + Writer: tartest.TarAll( + tc.File("oci-layout", []byte(`{"imageLayoutVersion":"2.0.0"}`), 0644), + ), + }, + { + Name: "OCI", + Writer: tartest.TarAll( + tc.Dir("blobs", 0755), + tc.Dir("blobs/sha256", 0755), + tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), + tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), + tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), + tc.File("index.json", createIndex(m1, "latest", "docker.io/lib/img:ok"), 0644), + tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), + ), + Check: func(t *testing.T, imgs []images.Image) { + names := []string{ + "latest", + "docker.io/lib/img:ok", + } + + checkImages(t, d3, imgs, names...) + checkManifest(ctx, t, imgs[0].Target, expManifest) + }, + }, + { + Name: "OCIPrefixName", + Writer: tartest.TarAll( + tc.Dir("blobs", 0755), + tc.Dir("blobs/sha256", 0755), + tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), + tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), + tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), + tc.File("index.json", createIndex(m1, "latest", "docker.io/lib/img:ok"), 0644), + tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), + ), + Check: func(t *testing.T, imgs []images.Image) { + names := []string{ + "localhost:5000/myimage:latest", + "docker.io/lib/img:ok", + } + + checkImages(t, d3, imgs, names...) + checkManifest(ctx, t, imgs[0].Target, expManifest) + }, + Opts: []ImportOpt{ + WithImageRefTranslator(archive.AddRefPrefix("localhost:5000/myimage")), + }, + }, + { + Name: "OCIPrefixName2", + Writer: tartest.TarAll( + tc.Dir("blobs", 0755), + tc.Dir("blobs/sha256", 0755), + tc.File("blobs/sha256/"+d1.Encoded(), b1, 0644), + tc.File("blobs/sha256/"+d2.Encoded(), c1, 0644), + tc.File("blobs/sha256/"+d3.Encoded(), m1, 0644), + tc.File("index.json", createIndex(m1, "latest", "localhost:5000/myimage:old", "docker.io/lib/img:ok"), 0644), + tc.File("oci-layout", []byte(`{"imageLayoutVersion":"1.0.0"}`), 0644), + ), + Check: func(t *testing.T, imgs []images.Image) { + names := []string{ + "localhost:5000/myimage:latest", + "localhost:5000/myimage:old", + } + + checkImages(t, d3, imgs, names...) + checkManifest(ctx, t, imgs[0].Target, expManifest) + }, + Opts: []ImportOpt{ + WithImageRefTranslator(archive.FilterRefPrefix("localhost:5000/myimage")), + }, + }, + } { + t.Run(tc.Name, func(t *testing.T) { + images, err := client.Import(ctx, tartest.TarFromWriterTo(tc.Writer), tc.Opts...) + if err != nil { + if tc.Check != nil { + t.Errorf("unexpected import error: %+v", err) + } + return + } else if tc.Check == nil { + t.Fatalf("expected error on import") + } + + tc.Check(t, images) + }) + } +} + +func checkImages(t *testing.T, target digest.Digest, actual []images.Image, names ...string) { + if len(names) != len(actual) { + t.Fatalf("expected %d images, got %d", len(names), len(actual)) + } + + for i, n := range names { + if actual[i].Target.Digest != target { + t.Fatalf("image(%d) unexpected target %s, expected %s", i, actual[i].Target.Digest, target) + } + if actual[i].Name != n { + t.Fatalf("image(%d) unexpected name %q, expected %q", i, actual[i].Name, n) + } + + if actual[i].Target.MediaType != ocispec.MediaTypeImageManifest && + actual[i].Target.MediaType != images.MediaTypeDockerSchema2Manifest { + t.Fatalf("image(%d) unexpected media type: %s", i, actual[i].Target.MediaType) + } + } +} + +func createContent(size int64, seed int64) ([]byte, digest.Digest) { + b, err := ioutil.ReadAll(io.LimitReader(rand.New(rand.NewSource(seed)), size)) + if err != nil { + panic(err) + } + wb := bytes.NewBuffer(nil) + cw, err := compression.CompressStream(wb, compression.Gzip) + if err != nil { + panic(err) + } + + if _, err := cw.Write(b); err != nil { + panic(err) + } + b = wb.Bytes() + return b, digest.FromBytes(b) +} + +func createConfig() ([]byte, digest.Digest) { + image := ocispec.Image{ + OS: "any", + Architecture: "any", + Author: "test", + } + b, _ := json.Marshal(image) + + return b, digest.FromBytes(b) +} + +func createManifest(config []byte, layers [][]byte) ([]byte, digest.Digest, *ocispec.Manifest) { + manifest := ocispec.Manifest{ + Versioned: specs.Versioned{ + SchemaVersion: 2, + }, + Config: ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageConfig, + Digest: digest.FromBytes(config), + Size: int64(len(config)), + Annotations: map[string]string{ + "ocispec": "manifest.config.descriptor", + }, + }, + } + for _, l := range layers { + manifest.Layers = append(manifest.Layers, ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageLayer, + Digest: digest.FromBytes(l), + Size: int64(len(l)), + Annotations: map[string]string{ + "ocispec": "manifest.layers.descriptor", + }, + }) + } + + b, _ := json.Marshal(manifest) + + return b, digest.FromBytes(b), &manifest +} + +func createIndex(manifest []byte, tags ...string) []byte { + idx := ocispec.Index{ + Versioned: specs.Versioned{ + SchemaVersion: 2, + }, + } + d := ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageManifest, + Digest: digest.FromBytes(manifest), + Size: int64(len(manifest)), + } + + if len(tags) == 0 { + idx.Manifests = append(idx.Manifests, d) + } else { + for _, t := range tags { + dt := d + dt.Annotations = map[string]string{ + ocispec.AnnotationRefName: t, + } + idx.Manifests = append(idx.Manifests, dt) + } + } + + b, _ := json.Marshal(idx) + + return b +} diff -Nru containerd-1.2.6/integration/client/lease_test.go containerd-1.5.9/integration/client/lease_test.go --- containerd-1.2.6/integration/client/lease_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/lease_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,141 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "runtime" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/leases" + "github.com/opencontainers/image-spec/identity" +) + +func TestLeaseResources(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() + } + + ctx, cancel := testContext(t) + defer cancel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + ls = client.LeasesService() + cs = client.ContentStore() + imgSrv = client.ImageService() + sn = client.SnapshotService("native") + ) + + l, err := ls.Create(ctx, leases.WithRandomID()) + if err != nil { + t.Fatal(err) + } + defer ls.Delete(ctx, l, leases.SynchronousDelete) + + // step 1: download image + imageName := "k8s.gcr.io/pause:3.5" + + image, err := client.Pull(ctx, imageName, WithPullUnpack, WithPullSnapshotter("native")) + if err != nil { + t.Fatal(err) + } + defer imgSrv.Delete(ctx, imageName) + + // both the config and snapshotter should exist + cfgDesc, err := image.Config(ctx) + if err != nil { + t.Fatal(err) + } + + if _, err := cs.Info(ctx, cfgDesc.Digest); err != nil { + t.Fatal(err) + } + + dgsts, err := image.RootFS(ctx) + if err != nil { + t.Fatal(err) + } + chainID := identity.ChainID(dgsts) + + if _, err := sn.Stat(ctx, chainID.String()); err != nil { + t.Fatal(err) + } + + // step 2: reference snapshotter with lease + r := leases.Resource{ + ID: chainID.String(), + Type: "snapshots/native", + } + + if err := ls.AddResource(ctx, l, r); err != nil { + t.Fatal(err) + } + + list, err := ls.ListResources(ctx, l) + if err != nil { + t.Fatal(err) + } + + if len(list) != 1 || list[0] != r { + t.Fatalf("expected (%v), but got (%v)", []leases.Resource{r}, list) + } + + // step 3: remove image and check the status of snapshotter and content + if err := imgSrv.Delete(ctx, imageName, images.SynchronousDelete()); err != nil { + t.Fatal(err) + } + + // config should be removed but the snapshotter should exist + if _, err := cs.Info(ctx, cfgDesc.Digest); !errdefs.IsNotFound(err) { + t.Fatalf("expected error(%v), but got(%v)", errdefs.ErrNotFound, err) + } + + if _, err := sn.Stat(ctx, chainID.String()); err != nil { + t.Fatal(err) + } + + // step 4: remove resource from the lease and check the list API + if err := ls.DeleteResource(ctx, l, r); err != nil { + t.Fatal(err) + } + + list, err = ls.ListResources(ctx, l) + if err != nil { + t.Fatal(err) + } + + if len(list) != 0 { + t.Fatalf("expected nothing, but got (%v)", list) + } + + // step 5: remove the lease to check the status of snapshotter + if err := ls.Delete(ctx, l, leases.SynchronousDelete); err != nil { + t.Fatal(err) + } + + if _, err := sn.Stat(ctx, chainID.String()); !errdefs.IsNotFound(err) { + t.Fatalf("expected error(%v), but got(%v)", errdefs.ErrNotFound, err) + } +} diff -Nru containerd-1.2.6/integration/client/restart_monitor_linux_test.go containerd-1.5.9/integration/client/restart_monitor_linux_test.go --- containerd-1.2.6/integration/client/restart_monitor_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/restart_monitor_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,116 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "fmt" + "syscall" + "testing" + "time" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" +) + +// TestRestartMonitor tests restarting containers +// with the restart monitor service plugin +func TestRestartMonitor(t *testing.T) { + const ( + interval = 10 * time.Second + epsilon = 1 * time.Second + ) + configTOML := fmt.Sprintf(` +version = 2 +[plugins] + [plugins."io.containerd.internal.v1.restart"] + interval = "%s" +`, interval.String()) + client, _, cleanup := newDaemonWithConfig(t, configTOML) + defer cleanup() + + var ( + ctx, cancel = testContext(t) + id = t.Name() + ) + defer cancel() + + image, err := client.Pull(ctx, testImage, WithPullUnpack) + if err != nil { + t.Fatal(err) + } + + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec( + oci.WithImageConfig(image), + withProcessArgs("sleep", "infinity"), + ), + withRestartStatus(Running), + ) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx, WithProcessKill) + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + task.Kill(ctx, syscall.SIGKILL) + begin := time.Now() + deadline := begin.Add(interval).Add(epsilon) + for time.Now().Before(deadline) { + status, err := task.Status(ctx) + now := time.Now() + if err != nil { + // ErrNotFound is expected here, because the restart monitor + // temporarily removes the task before restarting. + t.Logf("%v: err=%v", now, err) + } else { + t.Logf("%v: status=%q", now, status) + + if status.Status == Running { + elapsed := time.Since(begin) + t.Logf("the task was restarted within %s", elapsed.String()) + return + } + } + time.Sleep(epsilon) + } + t.Fatalf("the task was not restarted in %s + %s", + interval.String(), epsilon.String()) +} + +// withRestartStatus is a copy of "github.com/containerd/containerd/runtime/restart".WithStatus. +// This copy is needed because `go test` refuses circular imports. +func withRestartStatus(status ProcessStatus) func(context.Context, *Client, *containers.Container) error { + return func(_ context.Context, _ *Client, c *containers.Container) error { + if c.Labels == nil { + c.Labels = make(map[string]string) + } + c.Labels["containerd.io/restart.status"] = string(status) + return nil + } +} diff -Nru containerd-1.2.6/integration/client/signals_test.go containerd-1.5.9/integration/client/signals_test.go --- containerd-1.2.6/integration/client/signals_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/signals_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "fmt" + "syscall" + "testing" + + . "github.com/containerd/containerd" +) + +func TestParseSignal(t *testing.T) { + testSignals := []struct { + raw string + want syscall.Signal + err bool + }{ + {"1", syscall.Signal(1), false}, + {"SIGKILL", syscall.SIGKILL, false}, + {"NONEXIST", 0, true}, + } + for _, ts := range testSignals { + t.Run(fmt.Sprintf("%s/%d/%t", ts.raw, ts.want, ts.err), func(t *testing.T) { + got, err := ParseSignal(ts.raw) + if ts.err && err == nil { + t.Errorf("ParseSignal(%s) should return error", ts.raw) + } + if !ts.err && got != ts.want { + t.Errorf("ParseSignal(%s) return %d, want %d", ts.raw, got, ts.want) + } + }) + } +} diff -Nru containerd-1.2.6/integration/client/snapshot_test.go containerd-1.5.9/integration/client/snapshot_test.go --- containerd-1.2.6/integration/client/snapshot_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/snapshot_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "runtime" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/snapshots/testsuite" +) + +func newSnapshotter(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { + client, err := New(address) + if err != nil { + return nil, nil, err + } + + sn := client.SnapshotService(DefaultSnapshotter) + + return sn, func() error { + // no need to close remote snapshotter + return client.Close() + }, nil +} + +func TestSnapshotterClient(t *testing.T) { + if testing.Short() { + t.Skip() + } + if runtime.GOOS == "windows" { + t.Skip("snapshots not yet supported on Windows") + } + testsuite.SnapshotterSuite(t, "SnapshotterClient", newSnapshotter) +} diff -Nru containerd-1.2.6/integration/client/task_opts_unix_test.go containerd-1.5.9/integration/client/task_opts_unix_test.go --- containerd-1.2.6/integration/client/task_opts_unix_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/client/task_opts_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,64 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package client + +import ( + "context" + "testing" + + . "github.com/containerd/containerd" + "github.com/containerd/containerd/runtime/linux/runctypes" +) + +func TestWithNoNewKeyringAddsNoNewKeyringToOptions(t *testing.T) { + var taskInfo TaskInfo + var ctx context.Context + var client Client + + err := WithNoNewKeyring(ctx, &client, &taskInfo) + if err != nil { + t.Fatal(err) + } + + opts := taskInfo.Options.(*runctypes.CreateOptions) + + if !opts.NoNewKeyring { + t.Fatal("NoNewKeyring set on WithNoNewKeyring") + } + +} + +func TestWithNoNewKeyringDoesNotOverwriteOtherOptions(t *testing.T) { + var taskInfo TaskInfo + var ctx context.Context + var client Client + + taskInfo.Options = &runctypes.CreateOptions{NoPivotRoot: true} + + err := WithNoNewKeyring(ctx, &client, &taskInfo) + if err != nil { + t.Fatal(err) + } + + opts := taskInfo.Options.(*runctypes.CreateOptions) + + if !opts.NoPivotRoot { + t.Fatal("WithNoNewKeyring overwrote other options") + } +} diff -Nru containerd-1.2.6/integration/common.go containerd-1.5.9/integration/common.go --- containerd-1.2.6/integration/common.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/common.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,106 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "fmt" + "io/ioutil" + + "github.com/pelletier/go-toml" + "github.com/sirupsen/logrus" + cri "k8s.io/cri-api/pkg/apis" +) + +// ImageList holds public image references +type ImageList struct { + Alpine string + BusyBox string + Pause string + ResourceConsumer string + VolumeCopyUp string + VolumeOwnership string +} + +var ( + imageService cri.ImageManagerService + imageMap map[int]string + imageList ImageList + pauseImage string // This is the same with default sandbox image +) + +func initImages(imageListFile string) { + imageList = ImageList{ + Alpine: "docker.io/library/alpine:latest", + BusyBox: "docker.io/library/busybox:latest", + Pause: "k8s.gcr.io/pause:3.5", + ResourceConsumer: "k8s.gcr.io/e2e-test-images/resource-consumer:1.9", + VolumeCopyUp: "gcr.io/k8s-cri-containerd/volume-copy-up:2.0", + VolumeOwnership: "gcr.io/k8s-cri-containerd/volume-ownership:2.0", + } + + if imageListFile != "" { + fileContent, err := ioutil.ReadFile(imageListFile) + if err != nil { + panic(fmt.Errorf("Error reading '%v' file contents: %v", imageList, err)) + } + + err = toml.Unmarshal(fileContent, &imageList) + if err != nil { + panic(fmt.Errorf("Error unmarshalling '%v' TOML file: %v", imageList, err)) + } + } + + logrus.Infof("Using the following image list: %+v", imageList) + + imageMap = initImageMap(imageList) + pauseImage = GetImage(Pause) +} + +const ( + // None is to be used for unset/default images + None = iota + // Alpine image + Alpine + // BusyBox image + BusyBox + // Pause image + Pause + // ResourceConsumer image + ResourceConsumer + // VolumeCopyUp image + VolumeCopyUp + // VolumeOwnership image + VolumeOwnership +) + +func initImageMap(imageList ImageList) map[int]string { + images := map[int]string{} + images[Alpine] = imageList.Alpine + images[BusyBox] = imageList.BusyBox + images[Pause] = imageList.Pause + images[ResourceConsumer] = imageList.ResourceConsumer + images[VolumeCopyUp] = imageList.VolumeCopyUp + images[VolumeOwnership] = imageList.VolumeOwnership + return images +} + +// GetImage returns the fully qualified URI to an image (including version) +func GetImage(image int) string { + return imageMap[image] +} diff -Nru containerd-1.2.6/integration/containerd_image_test.go containerd-1.5.9/integration/containerd_image_test.go --- containerd-1.2.6/integration/containerd_image_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/containerd_image_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,213 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + "time" + + "golang.org/x/net/context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/namespaces" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Test to test the CRI plugin should see image pulled into containerd directly. +func TestContainerdImage(t *testing.T) { + var testImage = GetImage(BusyBox) + ctx := context.Background() + + t.Logf("make sure the test image doesn't exist in the cri plugin") + i, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + require.NoError(t, err) + if i != nil { + require.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage})) + } + + t.Logf("pull the image into containerd") + _, err = containerdClient.Pull(ctx, testImage, containerd.WithPullUnpack) + assert.NoError(t, err) + defer func() { + // Make sure the image is cleaned up in any case. + if err := containerdClient.ImageService().Delete(ctx, testImage); err != nil { + assert.True(t, errdefs.IsNotFound(err), err) + } + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage})) + }() + + t.Logf("the image should be seen by the cri plugin") + var id string + checkImage := func() (bool, error) { + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + if err != nil { + return false, err + } + if img == nil { + t.Logf("Image %q not show up in the cri plugin yet", testImage) + return false, nil + } + id = img.Id + img, err = imageService.ImageStatus(&runtime.ImageSpec{Image: id}) + if err != nil { + return false, err + } + if img == nil { + // We always generate image id as a reference first, it must + // be ready here. + return false, errors.New("can't reference image by id") + } + if len(img.RepoTags) != 1 { + // RepoTags must have been populated correctly. + return false, errors.Errorf("unexpected repotags: %+v", img.RepoTags) + } + if img.RepoTags[0] != testImage { + return false, errors.Errorf("unexpected repotag %q", img.RepoTags[0]) + } + return true, nil + } + require.NoError(t, Eventually(checkImage, 100*time.Millisecond, 10*time.Second)) + require.NoError(t, Consistently(checkImage, 100*time.Millisecond, time.Second)) + defer func() { + t.Logf("image should still be seen by id if only tag get deleted") + if err := containerdClient.ImageService().Delete(ctx, testImage); err != nil { + assert.True(t, errdefs.IsNotFound(err), err) + } + assert.NoError(t, Consistently(func() (bool, error) { + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: id}) + if err != nil { + return false, err + } + return img != nil, nil + }, 100*time.Millisecond, time.Second)) + t.Logf("image should be removed from the cri plugin if all references get deleted") + if err := containerdClient.ImageService().Delete(ctx, id); err != nil { + assert.True(t, errdefs.IsNotFound(err), err) + } + assert.NoError(t, Eventually(func() (bool, error) { + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: id}) + if err != nil { + return false, err + } + return img == nil, nil + }, 100*time.Millisecond, 10*time.Second)) + }() + + t.Logf("the image should be marked as managed") + imgByRef, err := containerdClient.GetImage(ctx, testImage) + assert.NoError(t, err) + assert.Equal(t, imgByRef.Labels()["io.cri-containerd.image"], "managed") + + t.Logf("the image id should be created and managed") + imgByID, err := containerdClient.GetImage(ctx, id) + assert.NoError(t, err) + assert.Equal(t, imgByID.Labels()["io.cri-containerd.image"], "managed") + + t.Logf("should be able to start container with the image") + sbConfig := PodSandboxConfig("sandbox", "containerd-image") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + cnConfig := ContainerConfig( + "test-container", + id, + WithCommand("top"), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + require.NoError(t, runtimeService.StartContainer(cn)) + checkContainer := func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + return s.GetState() == runtime.ContainerState_CONTAINER_RUNNING, nil + } + require.NoError(t, Eventually(checkContainer, 100*time.Millisecond, 10*time.Second)) + require.NoError(t, Consistently(checkContainer, 100*time.Millisecond, time.Second)) +} + +// Test image managed by CRI plugin shouldn't be affected by images in other namespaces. +func TestContainerdImageInOtherNamespaces(t *testing.T) { + var testImage = GetImage(BusyBox) + ctx := context.Background() + + t.Logf("make sure the test image doesn't exist in the cri plugin") + i, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + require.NoError(t, err) + if i != nil { + require.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage})) + } + + t.Logf("pull the image into test namespace") + namespacedCtx := namespaces.WithNamespace(ctx, "test") + _, err = containerdClient.Pull(namespacedCtx, testImage, containerd.WithPullUnpack) + assert.NoError(t, err) + defer func() { + // Make sure the image is cleaned up in any case. + if err := containerdClient.ImageService().Delete(namespacedCtx, testImage); err != nil { + assert.True(t, errdefs.IsNotFound(err), err) + } + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage})) + }() + + t.Logf("cri plugin should not see the image") + checkImage := func() (bool, error) { + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + if err != nil { + return false, err + } + return img == nil, nil + } + require.NoError(t, Consistently(checkImage, 100*time.Millisecond, time.Second)) + + sbConfig := PodSandboxConfig("sandbox", "test") + t.Logf("pull the image into cri plugin") + id, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: id})) + }() + + t.Logf("cri plugin should see the image now") + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + require.NoError(t, err) + assert.NotNil(t, img) + + t.Logf("remove the image from test namespace") + require.NoError(t, containerdClient.ImageService().Delete(namespacedCtx, testImage)) + + t.Logf("cri plugin should still see the image") + checkImage = func() (bool, error) { + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + if err != nil { + return false, err + } + return img != nil, nil + } + assert.NoError(t, Consistently(checkImage, 100*time.Millisecond, time.Second)) +} diff -Nru containerd-1.2.6/integration/container_log_test.go containerd-1.5.9/integration/container_log_test.go --- containerd-1.2.6/integration/container_log_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_log_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,175 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestContainerLogWithoutTailingNewLine(t *testing.T) { + testPodLogDir, err := ioutil.TempDir("/tmp", "container-log-without-tailing-newline") + require.NoError(t, err) + defer os.RemoveAll(testPodLogDir) + + t.Log("Create a sandbox with log directory") + sbConfig := PodSandboxConfig("sandbox", "container-log-without-tailing-newline", + WithPodLogDirectory(testPodLogDir), + ) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container with log path") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sh", "-c", "printf abcd"), + WithLogPath(containerName), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Wait for container to finish running") + require.NoError(t, Eventually(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + if s.GetState() == runtime.ContainerState_CONTAINER_EXITED { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Log("Check container log") + content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName)) + assert.NoError(t, err) + checkContainerLog(t, string(content), []string{ + fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagPartial, "abcd"), + }) +} + +func TestLongContainerLog(t *testing.T) { + testPodLogDir, err := ioutil.TempDir("/tmp", "long-container-log") + require.NoError(t, err) + defer os.RemoveAll(testPodLogDir) + + t.Log("Create a sandbox with log directory") + sbConfig := PodSandboxConfig("sandbox", "long-container-log", + WithPodLogDirectory(testPodLogDir), + ) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container with log path") + config, err := CRIConfig() + require.NoError(t, err) + maxSize := config.MaxContainerLogLineSize + shortLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize-1, "a") + maxLenLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize, "b") + longLineCmd := fmt.Sprintf("i=0; while [ $i -lt %d ]; do printf %s; i=$((i+1)); done", maxSize+1, "c") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sh", "-c", + fmt.Sprintf("%s; echo; %s; echo; %s; echo", shortLineCmd, maxLenLineCmd, longLineCmd)), + WithLogPath(containerName), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Wait for container to finish running") + require.NoError(t, Eventually(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + if s.GetState() == runtime.ContainerState_CONTAINER_EXITED { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Log("Check container log") + content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName)) + assert.NoError(t, err) + checkContainerLog(t, string(content), []string{ + fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, strings.Repeat("a", maxSize-1)), + fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, strings.Repeat("b", maxSize)), + fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagPartial, strings.Repeat("c", maxSize)), + fmt.Sprintf("%s %s %s", runtime.Stdout, runtime.LogTagFull, "c"), + }) +} + +func checkContainerLog(t *testing.T, log string, messages []string) { + lines := strings.Split(strings.TrimSpace(log), "\n") + require.Len(t, lines, len(messages), "log line number should match") + for i, line := range lines { + parts := strings.SplitN(line, " ", 2) + require.Len(t, parts, 2) + _, err := time.Parse(time.RFC3339Nano, parts[0]) + assert.NoError(t, err, "timestamp should be in RFC3339Nano format") + assert.Equal(t, messages[i], parts[1], "log content should match") + } +} diff -Nru containerd-1.2.6/integration/container_restart_test.go containerd-1.5.9/integration/container_restart_test.go --- containerd-1.2.6/integration/container_restart_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_restart_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Test to verify container can be restarted +func TestContainerRestart(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("sandbox1", "restart") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create a container config and run container in a pod") + containerConfig := ContainerConfig( + "container1", + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + + t.Logf("Restart the container with same config") + require.NoError(t, runtimeService.StopContainer(cn, 10)) + require.NoError(t, runtimeService.RemoveContainer(cn)) + + cn, err = runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + require.NoError(t, runtimeService.StartContainer(cn)) +} diff -Nru containerd-1.2.6/integration/container_stats_test.go containerd-1.5.9/integration/container_stats_test.go --- containerd-1.2.6/integration/container_stats_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_stats_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,425 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "fmt" + goruntime "runtime" + "testing" + "time" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Test to verify for a container ID +func TestContainerStats(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("sandbox1", "stats") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create a container config and run container in a pod") + containerConfig := ContainerConfig( + "container1", + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + + t.Logf("Fetch stats for container") + var s *runtime.ContainerStats + require.NoError(t, Eventually(func() (bool, error) { + s, err = runtimeService.ContainerStats(cn) + if err != nil { + return false, err + } + if s.GetWritableLayer().GetUsedBytes().GetValue() != 0 && + s.GetWritableLayer().GetInodesUsed().GetValue() != 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Logf("Verify stats received for container %q", cn) + testStats(t, s, containerConfig) +} + +// Test to verify if the consumed stats are correct. +func TestContainerConsumedStats(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("sandbox1", "stats") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + testImage := GetImage(ResourceConsumer) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Logf("Create a container config and run container in a pod") + containerConfig := ContainerConfig( + "container1", + testImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + + t.Logf("Fetch initial stats for container") + var s *runtime.ContainerStats + require.NoError(t, Eventually(func() (bool, error) { + s, err = runtimeService.ContainerStats(cn) + if err != nil { + return false, err + } + if s.GetMemory().GetWorkingSetBytes().GetValue() > 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + initialMemory := s.GetMemory().GetWorkingSetBytes().GetValue() + t.Logf("Initial container memory consumption is %f MB. Consume 100 MB and expect the reported stats to increase accordingly", float64(initialMemory)/(1024*1024)) + + // consume 100 MB memory for 30 seconds. + var command []string + if goruntime.GOOS == "windows" { + // -d: Leak and touch memory in specified MBs + // -c: Count of number of objects to allocate + command = []string{"testlimit.exe", "-accepteula", "-d", "25", "-c", "4"} + } else { + command = []string{"stress", "-m", "1", "--vm-bytes", "100M", "--vm-hang", "0", "-t", "30"} + } + + go func() { + _, _, err = runtimeService.ExecSync(cn, command, 30*time.Second) + }() + + require.NoError(t, Eventually(func() (bool, error) { + s, err = runtimeService.ContainerStats(cn) + if err != nil { + return false, err + } + if s.GetMemory().GetWorkingSetBytes().GetValue() > initialMemory+100*1024*1024 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) +} + +// Test to verify filtering without any filter +func TestContainerListStats(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("running-pod", "statsls") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create a container config and run containers in a pod") + containerConfigMap := make(map[string]*runtime.ContainerConfig) + for i := 0; i < 3; i++ { + cName := fmt.Sprintf("container%d", i) + containerConfig := ContainerConfig( + cName, + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + containerConfigMap[cn] = containerConfig + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + } + + t.Logf("Fetch all container stats") + var stats []*runtime.ContainerStats + require.NoError(t, Eventually(func() (bool, error) { + stats, err = runtimeService.ListContainerStats(&runtime.ContainerStatsFilter{}) + if err != nil { + return false, err + } + for _, s := range stats { + if s.GetWritableLayer().GetUsedBytes().GetValue() == 0 && + s.GetWritableLayer().GetInodesUsed().GetValue() == 0 { + return false, nil + } + } + return true, nil + }, time.Second, 30*time.Second)) + + t.Logf("Verify all container stats") + for _, s := range stats { + testStats(t, s, containerConfigMap[s.GetAttributes().GetId()]) + } +} + +// Test to verify filtering given a specific container ID +// TODO Convert the filter tests into table driven tests and unit tests +func TestContainerListStatsWithIdFilter(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("running-pod", "statsls") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create a container config and run containers in a pod") + containerConfigMap := make(map[string]*runtime.ContainerConfig) + for i := 0; i < 3; i++ { + cName := fmt.Sprintf("container%d", i) + containerConfig := ContainerConfig( + cName, + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + containerConfigMap[cn] = containerConfig + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + } + + t.Logf("Fetch container stats for each container with Filter") + var stats []*runtime.ContainerStats + for id := range containerConfigMap { + require.NoError(t, Eventually(func() (bool, error) { + stats, err = runtimeService.ListContainerStats( + &runtime.ContainerStatsFilter{Id: id}) + if err != nil { + return false, err + } + if len(stats) != 1 { + return false, errors.New("unexpected stats length") + } + if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 && + stats[0].GetWritableLayer().GetInodesUsed().GetValue() != 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Logf("Verify container stats for %s", id) + for _, s := range stats { + require.Equal(t, s.GetAttributes().GetId(), id) + testStats(t, s, containerConfigMap[id]) + } + } +} + +// Test to verify filtering given a specific Sandbox ID. Stats for +// all the containers in a pod should be returned +func TestContainerListStatsWithSandboxIdFilter(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("running-pod", "statsls") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create a container config and run containers in a pod") + containerConfigMap := make(map[string]*runtime.ContainerConfig) + for i := 0; i < 3; i++ { + cName := fmt.Sprintf("container%d", i) + containerConfig := ContainerConfig( + cName, + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + containerConfigMap[cn] = containerConfig + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + } + + t.Logf("Fetch container stats for each container with Filter") + var stats []*runtime.ContainerStats + require.NoError(t, Eventually(func() (bool, error) { + stats, err = runtimeService.ListContainerStats( + &runtime.ContainerStatsFilter{PodSandboxId: sb}) + if err != nil { + return false, err + } + if len(stats) != 3 { + return false, errors.New("unexpected stats length") + } + if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 && + stats[0].GetWritableLayer().GetInodesUsed().GetValue() != 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + t.Logf("Verify container stats for sandbox %q", sb) + for _, s := range stats { + testStats(t, s, containerConfigMap[s.GetAttributes().GetId()]) + } +} + +// Test to verify filtering given a specific container ID and +// sandbox ID +func TestContainerListStatsWithIdSandboxIdFilter(t *testing.T) { + t.Logf("Create a pod config and run sandbox container") + sbConfig := PodSandboxConfig("running-pod", "statsls") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + t.Logf("Create container config and run containers in a pod") + containerConfigMap := make(map[string]*runtime.ContainerConfig) + for i := 0; i < 3; i++ { + cName := fmt.Sprintf("container%d", i) + containerConfig := ContainerConfig( + cName, + pauseImage, + WithTestLabels(), + WithTestAnnotations(), + ) + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + containerConfigMap[cn] = containerConfig + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.RemoveContainer(cn)) + }() + require.NoError(t, runtimeService.StartContainer(cn)) + defer func() { + assert.NoError(t, runtimeService.StopContainer(cn, 10)) + }() + } + t.Logf("Fetch container stats for sandbox ID and container ID filter") + var stats []*runtime.ContainerStats + for id, config := range containerConfigMap { + require.NoError(t, Eventually(func() (bool, error) { + stats, err = runtimeService.ListContainerStats( + &runtime.ContainerStatsFilter{Id: id, PodSandboxId: sb}) + if err != nil { + return false, err + } + if len(stats) != 1 { + return false, errors.New("unexpected stats length") + } + if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 && + stats[0].GetWritableLayer().GetInodesUsed().GetValue() != 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + t.Logf("Verify container stats for sandbox %q and container %q filter", sb, id) + for _, s := range stats { + testStats(t, s, config) + } + } + + t.Logf("Fetch container stats for sandbox truncID and container truncID filter ") + for id, config := range containerConfigMap { + require.NoError(t, Eventually(func() (bool, error) { + stats, err = runtimeService.ListContainerStats( + &runtime.ContainerStatsFilter{Id: id[:3], PodSandboxId: sb[:3]}) + if err != nil { + return false, err + } + if len(stats) != 1 { + return false, errors.New("unexpected stats length") + } + if stats[0].GetWritableLayer().GetUsedBytes().GetValue() != 0 && + stats[0].GetWritableLayer().GetInodesUsed().GetValue() != 0 { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + t.Logf("Verify container stats for sandbox %q and container %q filter", sb, id) + for _, s := range stats { + testStats(t, s, config) + } + } +} + +// TODO make this as options to use for dead container tests +func testStats(t *testing.T, + s *runtime.ContainerStats, + config *runtime.ContainerConfig, +) { + require.NotEmpty(t, s.GetAttributes().GetId()) + require.NotEmpty(t, s.GetAttributes().GetMetadata()) + require.NotEmpty(t, s.GetAttributes().GetAnnotations()) + require.Equal(t, s.GetAttributes().GetLabels(), config.Labels) + require.Equal(t, s.GetAttributes().GetAnnotations(), config.Annotations) + require.Equal(t, s.GetAttributes().GetMetadata().Name, config.Metadata.Name) + require.NotEmpty(t, s.GetAttributes().GetLabels()) + require.NotEmpty(t, s.GetCpu().GetTimestamp()) + require.NotEmpty(t, s.GetCpu().GetUsageCoreNanoSeconds().GetValue()) + require.NotEmpty(t, s.GetMemory().GetTimestamp()) + require.NotEmpty(t, s.GetMemory().GetWorkingSetBytes().GetValue()) + require.NotEmpty(t, s.GetWritableLayer().GetTimestamp()) + require.NotEmpty(t, s.GetWritableLayer().GetFsId().GetMountpoint()) + require.NotEmpty(t, s.GetWritableLayer().GetUsedBytes().GetValue()) + require.NotEmpty(t, s.GetWritableLayer().GetInodesUsed().GetValue()) +} diff -Nru containerd-1.2.6/integration/container_stop_test.go containerd-1.5.9/integration/container_stop_test.go --- containerd-1.2.6/integration/container_stop_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_stop_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,141 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestSharedPidMultiProcessContainerStop(t *testing.T) { + for name, sbConfig := range map[string]*runtime.PodSandboxConfig{ + "hostpid": PodSandboxConfig("sandbox", "host-pid-container-stop", WithHostPid), + "podpid": PodSandboxConfig("sandbox", "pod-pid-container-stop", WithPodPid), + } { + t.Run(name, func(t *testing.T) { + t.Log("Create a shared pid sandbox") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a multi-process container") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sh", "-c", "sleep 10000 & sleep 10000"), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Stop the container") + require.NoError(t, runtimeService.StopContainer(cn, 0)) + + t.Log("The container state should be exited") + s, err := runtimeService.ContainerStatus(cn) + require.NoError(t, err) + assert.Equal(t, s.GetState(), runtime.ContainerState_CONTAINER_EXITED) + }) + } +} + +func TestContainerStopCancellation(t *testing.T) { + t.Log("Create a pod sandbox") + sbConfig := PodSandboxConfig("sandbox", "cancel-container-stop") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container which traps sigterm") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sh", "-c", `trap "echo ignore sigterm" TERM; sleep 1000`), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Stop the container with 3s timeout, but 1s context timeout") + // Note that with container pid namespace, the sleep process + // is pid 1, and SIGTERM sent by `StopContainer` will be ignored. + rawClient, err := RawRuntimeClient() + require.NoError(t, err) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + _, err = rawClient.StopContainer(ctx, &runtime.StopContainerRequest{ + ContainerId: cn, + Timeout: 3, + }) + assert.Error(t, err) + + t.Log("The container should still be running even after 5 seconds") + assert.NoError(t, Consistently(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + return s.GetState() == runtime.ContainerState_CONTAINER_RUNNING, nil + }, 100*time.Millisecond, 5*time.Second)) + + t.Log("Stop the container with 1s timeout, without shorter context timeout") + assert.NoError(t, runtimeService.StopContainer(cn, 1)) + + t.Log("The container state should be exited") + s, err := runtimeService.ContainerStatus(cn) + require.NoError(t, err) + assert.Equal(t, s.GetState(), runtime.ContainerState_CONTAINER_EXITED) +} diff -Nru containerd-1.2.6/integration/container_update_resources_test.go containerd-1.5.9/integration/container_update_resources_test.go --- containerd-1.2.6/integration/container_update_resources_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_update_resources_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/containerd/cgroups" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func checkMemoryLimit(t *testing.T, spec *runtimespec.Spec, memLimit int64) { + require.NotNil(t, spec) + require.NotNil(t, spec.Linux) + require.NotNil(t, spec.Linux.Resources) + require.NotNil(t, spec.Linux.Resources.Memory) + require.NotNil(t, spec.Linux.Resources.Memory.Limit) + assert.Equal(t, memLimit, *spec.Linux.Resources.Memory.Limit) +} + +func TestUpdateContainerResources(t *testing.T) { + t.Log("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "update-container-resources") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + t.Log("Create a container with memory limit") + cnConfig := ContainerConfig( + "container", + pauseImage, + WithResources(&runtime.LinuxContainerResources{ + MemoryLimitInBytes: 200 * 1024 * 1024, + }), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Check memory limit in container OCI spec") + container, err := containerdClient.LoadContainer(context.Background(), cn) + require.NoError(t, err) + spec, err := container.Spec(context.Background()) + require.NoError(t, err) + checkMemoryLimit(t, spec, 200*1024*1024) + + t.Log("Update container memory limit after created") + err = runtimeService.UpdateContainerResources(cn, &runtime.LinuxContainerResources{ + MemoryLimitInBytes: 400 * 1024 * 1024, + }) + require.NoError(t, err) + + t.Log("Check memory limit in container OCI spec") + spec, err = container.Spec(context.Background()) + require.NoError(t, err) + checkMemoryLimit(t, spec, 400*1024*1024) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + task, err := container.Task(context.Background(), nil) + require.NoError(t, err) + + t.Log("Check memory limit in cgroup") + cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid()))) + require.NoError(t, err) + stat, err := cgroup.Stat(cgroups.IgnoreNotExist) + require.NoError(t, err) + assert.Equal(t, uint64(400*1024*1024), stat.Memory.Usage.Limit) + + t.Log("Update container memory limit after started") + err = runtimeService.UpdateContainerResources(cn, &runtime.LinuxContainerResources{ + MemoryLimitInBytes: 800 * 1024 * 1024, + }) + require.NoError(t, err) + + t.Log("Check memory limit in container OCI spec") + spec, err = container.Spec(context.Background()) + require.NoError(t, err) + checkMemoryLimit(t, spec, 800*1024*1024) + + t.Log("Check memory limit in cgroup") + stat, err = cgroup.Stat(cgroups.IgnoreNotExist) + require.NoError(t, err) + assert.Equal(t, uint64(800*1024*1024), stat.Memory.Usage.Limit) +} diff -Nru containerd-1.2.6/integration/container_without_image_ref_test.go containerd-1.5.9/integration/container_without_image_ref_test.go --- containerd-1.2.6/integration/container_without_image_ref_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/container_without_image_ref_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,77 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Test container lifecycle can work without image references. +func TestContainerLifecycleWithoutImageRef(t *testing.T) { + t.Log("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "container-lifecycle-without-image-ref") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Log("Pull test image") + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create test container") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sleep", "1000"), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Remove test image") + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + + t.Log("Container status should be running") + status, err := runtimeService.ContainerStatus(cn) + require.NoError(t, err) + assert.Equal(t, status.GetState(), runtime.ContainerState_CONTAINER_RUNNING) + + t.Logf("Stop container") + err = runtimeService.StopContainer(cn, 1) + assert.NoError(t, err) + + t.Log("Container status should be exited") + status, err = runtimeService.ContainerStatus(cn) + require.NoError(t, err) + assert.Equal(t, status.GetState(), runtime.ContainerState_CONTAINER_EXITED) +} diff -Nru containerd-1.2.6/integration/duplicate_name_test.go containerd-1.5.9/integration/duplicate_name_test.go --- containerd-1.2.6/integration/duplicate_name_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/duplicate_name_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,53 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDuplicateName(t *testing.T) { + t.Logf("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "duplicate-name") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + t.Logf("Create the sandbox again should fail") + _, err = runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.Error(t, err) + + t.Logf("Create a container") + cnConfig := ContainerConfig( + "container", + pauseImage, + ) + _, err = runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Logf("Create the container again should fail") + _, err = runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.Error(t, err) +} diff -Nru containerd-1.2.6/integration/imagefs_info_test.go containerd-1.5.9/integration/imagefs_info_test.go --- containerd-1.2.6/integration/imagefs_info_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/imagefs_info_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,78 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "os" + "testing" + "time" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestImageFSInfo(t *testing.T) { + config := PodSandboxConfig("running-pod", "imagefs") + + t.Logf("Pull an image to make sure image fs is not empty") + img, err := imageService.PullImage(&runtime.ImageSpec{Image: GetImage(BusyBox)}, nil, config) + require.NoError(t, err) + defer func() { + err := imageService.RemoveImage(&runtime.ImageSpec{Image: img}) + assert.NoError(t, err) + }() + t.Logf("Create a sandbox to make sure there is an active snapshot") + sb, err := runtimeService.RunPodSandbox(config, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + // It takes time to populate imagefs stats. Use eventually + // to check for a period of time. + t.Logf("Check imagefs info") + var info *runtime.FilesystemUsage + require.NoError(t, Eventually(func() (bool, error) { + stats, err := imageService.ImageFsInfo() + if err != nil { + return false, err + } + if len(stats) == 0 { + return false, nil + } + if len(stats) >= 2 { + return false, errors.Errorf("unexpected stats length: %d", len(stats)) + } + info = stats[0] + if info.GetTimestamp() != 0 && + info.GetUsedBytes().GetValue() != 0 && + info.GetInodesUsed().GetValue() != 0 && + info.GetFsId().GetMountpoint() != "" { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + t.Logf("Image filesystem mountpath should exist") + _, err = os.Stat(info.GetFsId().GetMountpoint()) + assert.NoError(t, err) +} diff -Nru containerd-1.2.6/integration/image_list.sample.toml containerd-1.5.9/integration/image_list.sample.toml --- containerd-1.2.6/integration/image_list.sample.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/image_list.sample.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +alpine = "docker.io/library/alpine:latest" +busybox = "docker.io/library/busybox:latest" +pause = "k8s.gcr.io/pause:3.5" +VolumeCopyUp = "gcr.io/k8s-cri-containerd/volume-copy-up:2.0" +VolumeOwnership = "gcr.io/k8s-cri-containerd/volume-ownership:2.0" diff -Nru containerd-1.2.6/integration/image_load_test.go containerd-1.5.9/integration/image_load_test.go --- containerd-1.2.6/integration/image_load_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/image_load_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,101 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "io/ioutil" + "os" + "os/exec" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Test to load an image from tarball. +func TestImageLoad(t *testing.T) { + testImage := GetImage(BusyBox) + loadedImage := testImage + _, err := exec.LookPath("docker") + if err != nil { + t.Skipf("Docker is not available: %v", err) + } + t.Logf("docker save image into tarball") + output, err := exec.Command("docker", "pull", testImage).CombinedOutput() + require.NoError(t, err, "output: %q", output) + tarF, err := ioutil.TempFile("", "image-load") + tar := tarF.Name() + require.NoError(t, err) + defer func() { + assert.NoError(t, os.RemoveAll(tar)) + }() + output, err = exec.Command("docker", "save", testImage, "-o", tar).CombinedOutput() + require.NoError(t, err, "output: %q", output) + + t.Logf("make sure no such image in cri") + img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + require.NoError(t, err) + if img != nil { + require.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage})) + } + + t.Logf("load image in cri") + ctr, err := exec.LookPath("ctr") + require.NoError(t, err, "ctr should be installed, make sure you've run `make install.deps`") + output, err = exec.Command(ctr, "-address="+containerdEndpoint, + "-n=k8s.io", "images", "import", tar).CombinedOutput() + require.NoError(t, err, "output: %q", output) + + t.Logf("make sure image is loaded") + // Use Eventually because the cri plugin needs a short period of time + // to pick up images imported into containerd directly. + require.NoError(t, Eventually(func() (bool, error) { + img, err = imageService.ImageStatus(&runtime.ImageSpec{Image: testImage}) + if err != nil { + return false, err + } + return img != nil, nil + }, 100*time.Millisecond, 10*time.Second)) + require.Equal(t, []string{loadedImage}, img.RepoTags) + + t.Logf("create a container with the loaded image") + sbConfig := PodSandboxConfig("sandbox", Randomize("image-load")) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + containerConfig := ContainerConfig( + "container", + testImage, + WithCommand("tail", "-f", "/dev/null"), + ) + // Rely on sandbox clean to do container cleanup. + cn, err := runtimeService.CreateContainer(sb, containerConfig, sbConfig) + require.NoError(t, err) + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Logf("make sure container is running") + status, err := runtimeService.ContainerStatus(cn) + require.NoError(t, err) + require.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, status.State) +} diff -Nru containerd-1.2.6/integration/images/volume-copy-up/Dockerfile containerd-1.5.9/integration/images/volume-copy-up/Dockerfile --- containerd-1.2.6/integration/images/volume-copy-up/Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/images/volume-copy-up/Dockerfile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM busybox +RUN sh -c "mkdir /test_dir; echo test_content > /test_dir/test_file" +VOLUME "/test_dir" diff -Nru containerd-1.2.6/integration/images/volume-copy-up/Makefile containerd-1.5.9/integration/images/volume-copy-up/Makefile --- containerd-1.2.6/integration/images/volume-copy-up/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/images/volume-copy-up/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: build + +PROJ=gcr.io/k8s-cri-containerd +VERSION=2.0 +IMAGE=$(PROJ)/volume-copy-up:$(VERSION) +PLATFORMS?=linux/amd64,linux/arm64 + +configure-docker: + gcloud auth configure-docker + +build: + docker buildx build \ + $(OUTPUT) \ + --platform=${PLATFORMS} \ + --tag $(IMAGE) . + +push: OUTPUT=--push +push: configure-docker build + +.PHONY: configure-docker build push diff -Nru containerd-1.2.6/integration/images/volume-ownership/Dockerfile containerd-1.5.9/integration/images/volume-ownership/Dockerfile --- containerd-1.2.6/integration/images/volume-ownership/Dockerfile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/images/volume-ownership/Dockerfile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM ubuntu +RUN mkdir -p /test_dir && \ + chown -R nobody:nogroup /test_dir +VOLUME /test_dir diff -Nru containerd-1.2.6/integration/images/volume-ownership/Makefile containerd-1.5.9/integration/images/volume-ownership/Makefile --- containerd-1.2.6/integration/images/volume-ownership/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/images/volume-ownership/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: build + +PROJ=gcr.io/k8s-cri-containerd +VERSION=2.0 +IMAGE=$(PROJ)/volume-ownership:$(VERSION) +PLATFORMS?=linux/amd64,linux/arm64 + +configure-docker: + gcloud auth configure-docker + +build: + docker buildx build \ + $(OUTPUT) \ + --platform=${PLATFORMS} \ + --tag $(IMAGE) . + +push: OUTPUT=--push +push: configure-docker build + +.PHONY: configure-docker build push diff -Nru containerd-1.2.6/integration/main_test.go containerd-1.5.9/integration/main_test.go --- containerd-1.2.6/integration/main_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/main_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,418 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "os/exec" + "strconv" + "strings" + "testing" + "time" + + "github.com/containerd/containerd" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + cri "k8s.io/cri-api/pkg/apis" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/integration/remote" + dialer "github.com/containerd/containerd/integration/util" + criconfig "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/constants" + "github.com/containerd/containerd/pkg/cri/server" + "github.com/containerd/containerd/pkg/cri/util" +) + +const ( + timeout = 1 * time.Minute + k8sNamespace = constants.K8sContainerdNamespace +) + +var ( + runtimeService cri.RuntimeService + containerdClient *containerd.Client + containerdEndpoint string +) + +var criEndpoint = flag.String("cri-endpoint", "unix:///run/containerd/containerd.sock", "The endpoint of cri plugin.") +var criRoot = flag.String("cri-root", "/var/lib/containerd/io.containerd.grpc.v1.cri", "The root directory of cri plugin.") +var runtimeHandler = flag.String("runtime-handler", "", "The runtime handler to use in the test.") +var containerdBin = flag.String("containerd-bin", "containerd", "The containerd binary name. The name is used to restart containerd during test.") +var imageListFile = flag.String("image-list", "", "The TOML file containing the non-default images to be used in tests.") + +func TestMain(m *testing.M) { + flag.Parse() + initImages(*imageListFile) + if err := ConnectDaemons(); err != nil { + logrus.WithError(err).Fatalf("Failed to connect daemons") + } + os.Exit(m.Run()) +} + +// ConnectDaemons connect cri plugin and containerd, and initialize the clients. +func ConnectDaemons() error { + var err error + runtimeService, err = remote.NewRuntimeService(*criEndpoint, timeout) + if err != nil { + return errors.Wrap(err, "failed to create runtime service") + } + imageService, err = remote.NewImageService(*criEndpoint, timeout) + if err != nil { + return errors.Wrap(err, "failed to create image service") + } + // Since CRI grpc client doesn't have `WithBlock` specified, we + // need to check whether it is actually connected. + // TODO(random-liu): Extend cri remote client to accept extra grpc options. + _, err = runtimeService.ListContainers(&runtime.ContainerFilter{}) + if err != nil { + return errors.Wrap(err, "failed to list containers") + } + _, err = imageService.ListImages(&runtime.ImageFilter{}) + if err != nil { + return errors.Wrap(err, "failed to list images") + } + // containerdEndpoint is the same with criEndpoint now + containerdEndpoint = strings.TrimPrefix(*criEndpoint, "unix://") + containerdClient, err = containerd.New(containerdEndpoint, containerd.WithDefaultNamespace(k8sNamespace)) + if err != nil { + return errors.Wrap(err, "failed to connect containerd") + } + return nil +} + +// Opts sets specific information in pod sandbox config. +type PodSandboxOpts func(*runtime.PodSandboxConfig) + +// Set host network. +func WithHostNetwork(p *runtime.PodSandboxConfig) { + if p.Linux == nil { + p.Linux = &runtime.LinuxPodSandboxConfig{} + } + if p.Linux.SecurityContext == nil { + p.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{} + } + if p.Linux.SecurityContext.NamespaceOptions == nil { + p.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{} + } + p.Linux.SecurityContext.NamespaceOptions.Network = runtime.NamespaceMode_NODE +} + +// Set host pid. +func WithHostPid(p *runtime.PodSandboxConfig) { + if p.Linux == nil { + p.Linux = &runtime.LinuxPodSandboxConfig{} + } + if p.Linux.SecurityContext == nil { + p.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{} + } + if p.Linux.SecurityContext.NamespaceOptions == nil { + p.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{} + } + p.Linux.SecurityContext.NamespaceOptions.Pid = runtime.NamespaceMode_NODE +} + +// Set pod pid. +func WithPodPid(p *runtime.PodSandboxConfig) { + if p.Linux == nil { + p.Linux = &runtime.LinuxPodSandboxConfig{} + } + if p.Linux.SecurityContext == nil { + p.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{} + } + if p.Linux.SecurityContext.NamespaceOptions == nil { + p.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{} + } + p.Linux.SecurityContext.NamespaceOptions.Pid = runtime.NamespaceMode_POD +} + +// Add pod log directory. +func WithPodLogDirectory(dir string) PodSandboxOpts { + return func(p *runtime.PodSandboxConfig) { + p.LogDirectory = dir + } +} + +// Add pod hostname. +func WithPodHostname(hostname string) PodSandboxOpts { + return func(p *runtime.PodSandboxConfig) { + p.Hostname = hostname + } +} + +// PodSandboxConfig generates a pod sandbox config for test. +func PodSandboxConfig(name, ns string, opts ...PodSandboxOpts) *runtime.PodSandboxConfig { + config := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: name, + // Using random id as uuid is good enough for local + // integration test. + Uid: util.GenerateID(), + Namespace: Randomize(ns), + }, + Linux: &runtime.LinuxPodSandboxConfig{}, + } + for _, opt := range opts { + opt(config) + } + return config +} + +// ContainerOpts to set any specific attribute like labels, +// annotations, metadata etc +type ContainerOpts func(*runtime.ContainerConfig) + +func WithTestLabels() ContainerOpts { + return func(c *runtime.ContainerConfig) { + c.Labels = map[string]string{"key": "value"} + } +} + +func WithTestAnnotations() ContainerOpts { + return func(c *runtime.ContainerConfig) { + c.Annotations = map[string]string{"a.b.c": "test"} + } +} + +// Add container resource limits. +func WithResources(r *runtime.LinuxContainerResources) ContainerOpts { + return func(c *runtime.ContainerConfig) { + if c.Linux == nil { + c.Linux = &runtime.LinuxContainerConfig{} + } + c.Linux.Resources = r + } +} + +// Add container command. +func WithCommand(cmd string, args ...string) ContainerOpts { + return func(c *runtime.ContainerConfig) { + c.Command = []string{cmd} + c.Args = args + } +} + +// Add pid namespace mode. +func WithPidNamespace(mode runtime.NamespaceMode) ContainerOpts { + return func(c *runtime.ContainerConfig) { + if c.Linux == nil { + c.Linux = &runtime.LinuxContainerConfig{} + } + if c.Linux.SecurityContext == nil { + c.Linux.SecurityContext = &runtime.LinuxContainerSecurityContext{} + } + if c.Linux.SecurityContext.NamespaceOptions == nil { + c.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{} + } + c.Linux.SecurityContext.NamespaceOptions.Pid = mode + } + +} + +// Add container log path. +func WithLogPath(path string) ContainerOpts { + return func(c *runtime.ContainerConfig) { + c.LogPath = path + } +} + +// WithSupplementalGroups adds supplemental groups. +func WithSupplementalGroups(gids []int64) ContainerOpts { + return func(c *runtime.ContainerConfig) { + if c.Linux == nil { + c.Linux = &runtime.LinuxContainerConfig{} + } + if c.Linux.SecurityContext == nil { + c.Linux.SecurityContext = &runtime.LinuxContainerSecurityContext{} + } + c.Linux.SecurityContext.SupplementalGroups = gids + } +} + +// ContainerConfig creates a container config given a name and image name +// and additional container config options +func ContainerConfig(name, image string, opts ...ContainerOpts) *runtime.ContainerConfig { + cConfig := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: name, + }, + Image: &runtime.ImageSpec{Image: image}, + } + for _, opt := range opts { + opt(cConfig) + } + return cConfig +} + +// CheckFunc is the function used to check a condition is true/false. +type CheckFunc func() (bool, error) + +// Eventually waits for f to return true, it checks every period, and +// returns error if timeout exceeds. If f returns error, Eventually +// will return the same error immediately. +func Eventually(f CheckFunc, period, timeout time.Duration) error { + start := time.Now() + for { + done, err := f() + if done { + return nil + } + if err != nil { + return err + } + if time.Since(start) >= timeout { + return errors.New("timeout exceeded") + } + time.Sleep(period) + } +} + +// Consistently makes sure that f consistently returns true without +// error before timeout exceeds. If f returns error, Consistently +// will return the same error immediately. +func Consistently(f CheckFunc, period, timeout time.Duration) error { + start := time.Now() + for { + ok, err := f() + if !ok { + return errors.New("get false") + } + if err != nil { + return err + } + if time.Since(start) >= timeout { + return nil + } + time.Sleep(period) + } +} + +// Randomize adds uuid after a string. +func Randomize(str string) string { + return str + "-" + util.GenerateID() +} + +// KillProcess kills the process by name. pkill is used. +func KillProcess(name string) error { + output, err := exec.Command("pkill", "-x", fmt.Sprintf("^%s$", name)).CombinedOutput() + if err != nil { + return errors.Errorf("failed to kill %q - error: %v, output: %q", name, err, output) + } + return nil +} + +// KillPid kills the process by pid. kill is used. +func KillPid(pid int) error { + output, err := exec.Command("kill", strconv.Itoa(pid)).CombinedOutput() + if err != nil { + return errors.Errorf("failed to kill %d - error: %v, output: %q", pid, err, output) + } + return nil +} + +// PidOf returns pid of a process by name. +func PidOf(name string) (int, error) { + b, err := exec.Command("pidof", "-s", name).CombinedOutput() + output := strings.TrimSpace(string(b)) + if err != nil { + if len(output) != 0 { + return 0, errors.Errorf("failed to run pidof %q - error: %v, output: %q", name, err, output) + } + return 0, nil + } + return strconv.Atoi(output) +} + +// RawRuntimeClient returns a raw grpc runtime service client. +func RawRuntimeClient() (runtime.RuntimeServiceClient, error) { + addr, dialer, err := dialer.GetAddressAndDialer(*criEndpoint) + if err != nil { + return nil, errors.Wrap(err, "failed to get dialer") + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithContextDialer(dialer)) + if err != nil { + return nil, errors.Wrap(err, "failed to connect cri endpoint") + } + return runtime.NewRuntimeServiceClient(conn), nil +} + +// CRIConfig gets current cri config from containerd. +func CRIConfig() (*criconfig.Config, error) { + client, err := RawRuntimeClient() + if err != nil { + return nil, errors.Wrap(err, "failed to get raw runtime client") + } + resp, err := client.Status(context.Background(), &runtime.StatusRequest{Verbose: true}) + if err != nil { + return nil, errors.Wrap(err, "failed to get status") + } + config := &criconfig.Config{} + if err := json.Unmarshal([]byte(resp.Info["config"]), config); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal config") + } + return config, nil +} + +// SandboxInfo gets sandbox info. +func SandboxInfo(id string) (*runtime.PodSandboxStatus, *server.SandboxInfo, error) { + client, err := RawRuntimeClient() + if err != nil { + return nil, nil, errors.Wrap(err, "failed to get raw runtime client") + } + resp, err := client.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{ + PodSandboxId: id, + Verbose: true, + }) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to get sandbox status") + } + status := resp.GetStatus() + var info server.SandboxInfo + if err := json.Unmarshal([]byte(resp.GetInfo()["info"]), &info); err != nil { + return nil, nil, errors.Wrap(err, "failed to unmarshal sandbox info") + } + return status, &info, nil +} + +func RestartContainerd(t *testing.T) { + require.NoError(t, KillProcess(*containerdBin)) + + // Use assert so that the 3rd wait always runs, this makes sure + // containerd is running before this function returns. + assert.NoError(t, Eventually(func() (bool, error) { + pid, err := PidOf(*containerdBin) + if err != nil { + return false, err + } + return pid == 0, nil + }, time.Second, 30*time.Second), "wait for containerd to be killed") + + require.NoError(t, Eventually(func() (bool, error) { + return ConnectDaemons() == nil, nil + }, time.Second, 30*time.Second), "wait for containerd to be restarted") +} diff -Nru containerd-1.2.6/integration/no_metadata_test.go containerd-1.5.9/integration/no_metadata_test.go --- containerd-1.2.6/integration/no_metadata_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/no_metadata_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,50 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestRunPodSandboxWithoutMetadata(t *testing.T) { + sbConfig := &runtime.PodSandboxConfig{} + _, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.Error(t, err) + _, err = runtimeService.Status() + require.NoError(t, err) +} + +func TestCreateContainerWithoutMetadata(t *testing.T) { + sbConfig := PodSandboxConfig("sandbox", "container-create") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + // Make sure the sandbox is cleaned up in any case. + runtimeService.StopPodSandbox(sb) + runtimeService.RemovePodSandbox(sb) + }() + config := &runtime.ContainerConfig{} + _, err = runtimeService.CreateContainer(sb, config, sbConfig) + require.Error(t, err) + _, err = runtimeService.Status() + require.NoError(t, err) +} diff -Nru containerd-1.2.6/integration/pod_dualstack_test.go containerd-1.5.9/integration/pod_dualstack_test.go --- containerd-1.2.6/integration/pod_dualstack_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/pod_dualstack_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "io/ioutil" + "net" + "os" + "path/filepath" + "regexp" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestPodDualStack(t *testing.T) { + testPodLogDir, err := ioutil.TempDir("/tmp", "dualstack") + require.NoError(t, err) + defer os.RemoveAll(testPodLogDir) + + t.Log("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "dualstack", WithPodLogDirectory(testPodLogDir)) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container to print env") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("ip", "address", "show", "dev", "eth0"), + WithLogPath(containerName), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Wait for container to finish running") + require.NoError(t, Eventually(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + if s.GetState() == runtime.ContainerState_CONTAINER_EXITED { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName)) + assert.NoError(t, err) + status, err := runtimeService.PodSandboxStatus(sb) + require.NoError(t, err) + ip := status.GetNetwork().GetIp() + additionalIps := status.GetNetwork().GetAdditionalIps() + + ipv4Enabled, err := regexp.MatchString("inet .* scope global", string(content)) + assert.NoError(t, err) + ipv6Enabled, err := regexp.MatchString("inet6 .* scope global", string(content)) + assert.NoError(t, err) + + if ipv4Enabled && ipv6Enabled { + t.Log("Dualstack should be enabled") + require.Len(t, additionalIps, 1) + assert.NotNil(t, net.ParseIP(ip).To4()) + assert.Nil(t, net.ParseIP(additionalIps[0].GetIp()).To4()) + } else { + t.Log("Dualstack should not be enabled") + assert.Len(t, additionalIps, 0) + assert.NotEmpty(t, ip) + } +} diff -Nru containerd-1.2.6/integration/pod_hostname_test.go containerd-1.5.9/integration/pod_hostname_test.go --- containerd-1.2.6/integration/pod_hostname_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/pod_hostname_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,132 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestPodHostname(t *testing.T) { + hostname, err := os.Hostname() + require.NoError(t, err) + for name, test := range map[string]struct { + opts []PodSandboxOpts + expectedHostname string + expectErr bool + }{ + "regular pod with custom hostname": { + opts: []PodSandboxOpts{ + WithPodHostname("test-hostname"), + }, + expectedHostname: "test-hostname", + }, + "host network pod without custom hostname": { + opts: []PodSandboxOpts{ + WithHostNetwork, + }, + expectedHostname: hostname, + }, + "host network pod with custom hostname should fail": { + opts: []PodSandboxOpts{ + WithHostNetwork, + WithPodHostname("test-hostname"), + }, + expectErr: true, + }, + } { + t.Run(name, func(t *testing.T) { + testPodLogDir, err := ioutil.TempDir("/tmp", "hostname") + require.NoError(t, err) + defer os.RemoveAll(testPodLogDir) + + opts := append(test.opts, WithPodLogDirectory(testPodLogDir)) + t.Log("Create a sandbox with hostname") + sbConfig := PodSandboxConfig("sandbox", "hostname", opts...) + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + if err != nil { + if !test.expectErr { + t.Fatalf("Unexpected RunPodSandbox error: %v", err) + } + return + } + // Make sure the sandbox is cleaned up. + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + if test.expectErr { + t.Fatalf("Expected RunPodSandbox to return error") + } + + var ( + testImage = GetImage(BusyBox) + containerName = "test-container" + ) + t.Logf("Pull test image %q", testImage) + img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + + t.Log("Create a container to print env") + cnConfig := ContainerConfig( + containerName, + testImage, + WithCommand("sh", "-c", + "echo -n /etc/hostname= && cat /etc/hostname && env"), + WithLogPath(containerName), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Log("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + t.Log("Wait for container to finish running") + require.NoError(t, Eventually(func() (bool, error) { + s, err := runtimeService.ContainerStatus(cn) + if err != nil { + return false, err + } + if s.GetState() == runtime.ContainerState_CONTAINER_EXITED { + return true, nil + } + return false, nil + }, time.Second, 30*time.Second)) + + content, err := ioutil.ReadFile(filepath.Join(testPodLogDir, containerName)) + assert.NoError(t, err) + + t.Log("Search hostname env in container log") + assert.Contains(t, string(content), "HOSTNAME="+test.expectedHostname) + + t.Log("Search /etc/hostname content in container log") + assert.Contains(t, string(content), "/etc/hostname="+test.expectedHostname) + }) + } +} diff -Nru containerd-1.2.6/integration/remote/doc.go containerd-1.5.9/integration/remote/doc.go --- containerd-1.2.6/integration/remote/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package remote contains gRPC implementation of internalapi.RuntimeService +// and internalapi.ImageManagerService. +package remote diff -Nru containerd-1.2.6/integration/remote/remote_image.go containerd-1.5.9/integration/remote/remote_image.go --- containerd-1.2.6/integration/remote/remote_image.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/remote_image.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,172 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remote + +import ( + "context" + "errors" + "fmt" + "time" + + "google.golang.org/grpc" + "k8s.io/klog/v2" + + internalapi "k8s.io/cri-api/pkg/apis" + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/integration/remote/util" +) + +// ImageService is a gRPC implementation of internalapi.ImageManagerService. +type ImageService struct { + timeout time.Duration + imageClient runtimeapi.ImageServiceClient +} + +// NewImageService creates a new internalapi.ImageManagerService. +func NewImageService(endpoint string, connectionTimeout time.Duration) (internalapi.ImageManagerService, error) { + klog.V(3).Infof("Connecting to image service %s", endpoint) + addr, dialer, err := util.GetAddressAndDialer(endpoint) + if err != nil { + return nil, err + } + + ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithContextDialer(dialer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize))) + if err != nil { + klog.Errorf("Connect remote image service %s failed: %v", addr, err) + return nil, err + } + + return &ImageService{ + timeout: connectionTimeout, + imageClient: runtimeapi.NewImageServiceClient(conn), + }, nil +} + +// ListImages lists available images. +func (r *ImageService) ListImages(filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error) { + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.imageClient.ListImages(ctx, &runtimeapi.ListImagesRequest{ + Filter: filter, + }) + if err != nil { + klog.Errorf("ListImages with filter %+v from image service failed: %v", filter, err) + return nil, err + } + + return resp.Images, nil +} + +// ImageStatus returns the status of the image. +func (r *ImageService) ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) { + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.imageClient.ImageStatus(ctx, &runtimeapi.ImageStatusRequest{ + Image: image, + }) + if err != nil { + klog.Errorf("ImageStatus %q from image service failed: %v", image.Image, err) + return nil, err + } + + if resp.Image != nil { + if resp.Image.Id == "" || resp.Image.Size_ == 0 { + errorMessage := fmt.Sprintf("Id or size of image %q is not set", image.Image) + klog.Errorf("ImageStatus failed: %s", errorMessage) + return nil, errors.New(errorMessage) + } + } + + return resp.Image, nil +} + +// PullImage pulls an image with authentication config. +func (r *ImageService) PullImage(image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error) { + ctx, cancel := getContextWithCancel() + defer cancel() + + resp, err := r.imageClient.PullImage(ctx, &runtimeapi.PullImageRequest{ + Image: image, + Auth: auth, + SandboxConfig: podSandboxConfig, + }) + if err != nil { + klog.Errorf("PullImage %q from image service failed: %v", image.Image, err) + return "", err + } + + if resp.ImageRef == "" { + errorMessage := fmt.Sprintf("imageRef of image %q is not set", image.Image) + klog.Errorf("PullImage failed: %s", errorMessage) + return "", errors.New(errorMessage) + } + + return resp.ImageRef, nil +} + +// RemoveImage removes the image. +func (r *ImageService) RemoveImage(image *runtimeapi.ImageSpec) error { + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.imageClient.RemoveImage(ctx, &runtimeapi.RemoveImageRequest{ + Image: image, + }) + if err != nil { + klog.Errorf("RemoveImage %q from image service failed: %v", image.Image, err) + return err + } + + return nil +} + +// ImageFsInfo returns information of the filesystem that is used to store images. +func (r *ImageService) ImageFsInfo() ([]*runtimeapi.FilesystemUsage, error) { + // Do not set timeout, because `ImageFsInfo` takes time. + // TODO(random-liu): Should we assume runtime should cache the result, and set timeout here? + ctx, cancel := getContextWithCancel() + defer cancel() + + resp, err := r.imageClient.ImageFsInfo(ctx, &runtimeapi.ImageFsInfoRequest{}) + if err != nil { + klog.Errorf("ImageFsInfo from image service failed: %v", err) + return nil, err + } + return resp.GetImageFilesystems(), nil +} diff -Nru containerd-1.2.6/integration/remote/remote_runtime.go containerd-1.5.9/integration/remote/remote_runtime.go --- containerd-1.2.6/integration/remote/remote_runtime.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/remote_runtime.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,588 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remote + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "google.golang.org/grpc" + "k8s.io/klog/v2" + + "k8s.io/component-base/logs/logreduction" + internalapi "k8s.io/cri-api/pkg/apis" + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + utilexec "k8s.io/utils/exec" + + "github.com/containerd/containerd/integration/remote/util" +) + +// RuntimeService is a gRPC implementation of internalapi.RuntimeService. +type RuntimeService struct { + timeout time.Duration + runtimeClient runtimeapi.RuntimeServiceClient + // Cache last per-container error message to reduce log spam + logReduction *logreduction.LogReduction +} + +const ( + // How frequently to report identical errors + identicalErrorDelay = 1 * time.Minute +) + +// NewRuntimeService creates a new internalapi.RuntimeService. +func NewRuntimeService(endpoint string, connectionTimeout time.Duration) (internalapi.RuntimeService, error) { + klog.V(3).Infof("Connecting to runtime service %s", endpoint) + addr, dialer, err := util.GetAddressAndDialer(endpoint) + if err != nil { + return nil, err + } + ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) + defer cancel() + + conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithContextDialer(dialer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize))) + if err != nil { + klog.Errorf("Connect remote runtime %s failed: %v", addr, err) + return nil, err + } + + return &RuntimeService{ + timeout: connectionTimeout, + runtimeClient: runtimeapi.NewRuntimeServiceClient(conn), + logReduction: logreduction.NewLogReduction(identicalErrorDelay), + }, nil +} + +// Version returns the runtime name, runtime version and runtime API version. +func (r *RuntimeService) Version(apiVersion string) (*runtimeapi.VersionResponse, error) { + klog.V(10).Infof("[RuntimeService] Version (apiVersion=%v, timeout=%v)", apiVersion, r.timeout) + + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + typedVersion, err := r.runtimeClient.Version(ctx, &runtimeapi.VersionRequest{ + Version: apiVersion, + }) + if err != nil { + klog.Errorf("Version from runtime service failed: %v", err) + return nil, err + } + + klog.V(10).Infof("[RuntimeService] Version Response (typedVersion=%v)", typedVersion) + + if typedVersion.Version == "" || typedVersion.RuntimeName == "" || typedVersion.RuntimeApiVersion == "" || typedVersion.RuntimeVersion == "" { + return nil, fmt.Errorf("not all fields are set in VersionResponse (%q)", *typedVersion) + } + + return typedVersion, err +} + +// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure +// the sandbox is in ready state. +func (r *RuntimeService) RunPodSandbox(config *runtimeapi.PodSandboxConfig, runtimeHandler string) (string, error) { + // Use 2 times longer timeout for sandbox operation (4 mins by default) + // TODO: Make the pod sandbox timeout configurable. + timeout := r.timeout * 2 + + klog.V(10).Infof("[RuntimeService] RunPodSandbox (config=%v, runtimeHandler=%v, timeout=%v)", config, runtimeHandler, timeout) + + ctx, cancel := getContextWithTimeout(timeout) + defer cancel() + + resp, err := r.runtimeClient.RunPodSandbox(ctx, &runtimeapi.RunPodSandboxRequest{ + Config: config, + RuntimeHandler: runtimeHandler, + }) + if err != nil { + klog.Errorf("RunPodSandbox from runtime service failed: %v", err) + return "", err + } + + if resp.PodSandboxId == "" { + errorMessage := fmt.Sprintf("PodSandboxId is not set for sandbox %q", config.GetMetadata()) + klog.Errorf("RunPodSandbox failed: %s", errorMessage) + return "", errors.New(errorMessage) + } + + klog.V(10).Infof("[RuntimeService] RunPodSandbox Response (PodSandboxId=%v)", resp.PodSandboxId) + + return resp.PodSandboxId, nil +} + +// StopPodSandbox stops the sandbox. If there are any running containers in the +// sandbox, they should be forced to termination. +func (r *RuntimeService) StopPodSandbox(podSandBoxID string) error { + klog.V(10).Infof("[RuntimeService] StopPodSandbox (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) + + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.runtimeClient.StopPodSandbox(ctx, &runtimeapi.StopPodSandboxRequest{ + PodSandboxId: podSandBoxID, + }) + if err != nil { + klog.Errorf("StopPodSandbox %q from runtime service failed: %v", podSandBoxID, err) + return err + } + + klog.V(10).Infof("[RuntimeService] StopPodSandbox Response (podSandboxID=%v)", podSandBoxID) + + return nil +} + +// RemovePodSandbox removes the sandbox. If there are any containers in the +// sandbox, they should be forcibly removed. +func (r *RuntimeService) RemovePodSandbox(podSandBoxID string) error { + klog.V(10).Infof("[RuntimeService] RemovePodSandbox (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.runtimeClient.RemovePodSandbox(ctx, &runtimeapi.RemovePodSandboxRequest{ + PodSandboxId: podSandBoxID, + }) + if err != nil { + klog.Errorf("RemovePodSandbox %q from runtime service failed: %v", podSandBoxID, err) + return err + } + + klog.V(10).Infof("[RuntimeService] RemovePodSandbox Response (podSandboxID=%v)", podSandBoxID) + + return nil +} + +// PodSandboxStatus returns the status of the PodSandbox. +func (r *RuntimeService) PodSandboxStatus(podSandBoxID string) (*runtimeapi.PodSandboxStatus, error) { + klog.V(10).Infof("[RuntimeService] PodSandboxStatus (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.PodSandboxStatus(ctx, &runtimeapi.PodSandboxStatusRequest{ + PodSandboxId: podSandBoxID, + }) + if err != nil { + return nil, err + } + + klog.V(10).Infof("[RuntimeService] PodSandboxStatus Response (podSandboxID=%v, status=%v)", podSandBoxID, resp.Status) + + if resp.Status != nil { + if err := verifySandboxStatus(resp.Status); err != nil { + return nil, err + } + } + + return resp.Status, nil +} + +// ListPodSandbox returns a list of PodSandboxes. +func (r *RuntimeService) ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error) { + klog.V(10).Infof("[RuntimeService] ListPodSandbox (filter=%v, timeout=%v)", filter, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.ListPodSandbox(ctx, &runtimeapi.ListPodSandboxRequest{ + Filter: filter, + }) + if err != nil { + klog.Errorf("ListPodSandbox with filter %+v from runtime service failed: %v", filter, err) + return nil, err + } + + klog.V(10).Infof("[RuntimeService] ListPodSandbox Response (filter=%v, items=%v)", filter, resp.Items) + + return resp.Items, nil +} + +// CreateContainer creates a new container in the specified PodSandbox. +func (r *RuntimeService) CreateContainer(podSandBoxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) { + klog.V(10).Infof("[RuntimeService] CreateContainer (podSandBoxID=%v, timeout=%v)", podSandBoxID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.CreateContainer(ctx, &runtimeapi.CreateContainerRequest{ + PodSandboxId: podSandBoxID, + Config: config, + SandboxConfig: sandboxConfig, + }) + if err != nil { + klog.Errorf("CreateContainer in sandbox %q from runtime service failed: %v", podSandBoxID, err) + return "", err + } + + klog.V(10).Infof("[RuntimeService] CreateContainer (podSandBoxID=%v, ContainerId=%v)", podSandBoxID, resp.ContainerId) + if resp.ContainerId == "" { + errorMessage := fmt.Sprintf("ContainerId is not set for container %q", config.GetMetadata()) + klog.Errorf("CreateContainer failed: %s", errorMessage) + return "", errors.New(errorMessage) + } + + return resp.ContainerId, nil +} + +// StartContainer starts the container. +func (r *RuntimeService) StartContainer(containerID string) error { + klog.V(10).Infof("[RuntimeService] StartContainer (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.runtimeClient.StartContainer(ctx, &runtimeapi.StartContainerRequest{ + ContainerId: containerID, + }) + if err != nil { + klog.Errorf("StartContainer %q from runtime service failed: %v", containerID, err) + return err + } + klog.V(10).Infof("[RuntimeService] StartContainer Response (containerID=%v)", containerID) + + return nil +} + +// StopContainer stops a running container with a grace period (i.e., timeout). +func (r *RuntimeService) StopContainer(containerID string, timeout int64) error { + klog.V(10).Infof("[RuntimeService] StopContainer (containerID=%v, timeout=%v)", containerID, timeout) + // Use timeout + default timeout (2 minutes) as timeout to leave extra time + // for SIGKILL container and request latency. + t := r.timeout + time.Duration(timeout)*time.Second + ctx, cancel := getContextWithTimeout(t) + defer cancel() + + r.logReduction.ClearID(containerID) + _, err := r.runtimeClient.StopContainer(ctx, &runtimeapi.StopContainerRequest{ + ContainerId: containerID, + Timeout: timeout, + }) + if err != nil { + klog.Errorf("StopContainer %q from runtime service failed: %v", containerID, err) + return err + } + klog.V(10).Infof("[RuntimeService] StopContainer Response (containerID=%v)", containerID) + + return nil +} + +// RemoveContainer removes the container. If the container is running, the container +// should be forced to removal. +func (r *RuntimeService) RemoveContainer(containerID string) error { + klog.V(10).Infof("[RuntimeService] RemoveContainer (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + r.logReduction.ClearID(containerID) + _, err := r.runtimeClient.RemoveContainer(ctx, &runtimeapi.RemoveContainerRequest{ + ContainerId: containerID, + }) + if err != nil { + klog.Errorf("RemoveContainer %q from runtime service failed: %v", containerID, err) + return err + } + klog.V(10).Infof("[RuntimeService] RemoveContainer Response (containerID=%v)", containerID) + + return nil +} + +// ListContainers lists containers by filters. +func (r *RuntimeService) ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error) { + klog.V(10).Infof("[RuntimeService] ListContainers (filter=%v, timeout=%v)", filter, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.ListContainers(ctx, &runtimeapi.ListContainersRequest{ + Filter: filter, + }) + if err != nil { + klog.Errorf("ListContainers with filter %+v from runtime service failed: %v", filter, err) + return nil, err + } + klog.V(10).Infof("[RuntimeService] ListContainers Response (filter=%v, containers=%v)", filter, resp.Containers) + + return resp.Containers, nil +} + +// ContainerStatus returns the container status. +func (r *RuntimeService) ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error) { + klog.V(10).Infof("[RuntimeService] ContainerStatus (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.ContainerStatus(ctx, &runtimeapi.ContainerStatusRequest{ + ContainerId: containerID, + }) + if err != nil { + // Don't spam the log with endless messages about the same failure. + if r.logReduction.ShouldMessageBePrinted(err.Error(), containerID) { + klog.Errorf("ContainerStatus %q from runtime service failed: %v", containerID, err) + } + return nil, err + } + r.logReduction.ClearID(containerID) + klog.V(10).Infof("[RuntimeService] ContainerStatus Response (containerID=%v, status=%v)", containerID, resp.Status) + + if resp.Status != nil { + if err := verifyContainerStatus(resp.Status); err != nil { + klog.Errorf("ContainerStatus of %q failed: %v", containerID, err) + return nil, err + } + } + + return resp.Status, nil +} + +// UpdateContainerResources updates a containers resource config +func (r *RuntimeService) UpdateContainerResources(containerID string, resources *runtimeapi.LinuxContainerResources) error { + klog.V(10).Infof("[RuntimeService] UpdateContainerResources (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.runtimeClient.UpdateContainerResources(ctx, &runtimeapi.UpdateContainerResourcesRequest{ + ContainerId: containerID, + Linux: resources, + }) + if err != nil { + klog.Errorf("UpdateContainerResources %q from runtime service failed: %v", containerID, err) + return err + } + klog.V(10).Infof("[RuntimeService] UpdateContainerResources Response (containerID=%v)", containerID) + + return nil +} + +// ExecSync executes a command in the container, and returns the stdout output. +// If command exits with a non-zero exit code, an error is returned. +func (r *RuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) { + klog.V(10).Infof("[RuntimeService] ExecSync (containerID=%v, timeout=%v)", containerID, timeout) + // Do not set timeout when timeout is 0. + var ctx context.Context + var cancel context.CancelFunc + if timeout != 0 { + // Use timeout + default timeout (2 minutes) as timeout to leave some time for + // the runtime to do cleanup. + ctx, cancel = getContextWithTimeout(r.timeout + timeout) + } else { + ctx, cancel = getContextWithCancel() + } + defer cancel() + + timeoutSeconds := int64(timeout.Seconds()) + req := &runtimeapi.ExecSyncRequest{ + ContainerId: containerID, + Cmd: cmd, + Timeout: timeoutSeconds, + } + resp, err := r.runtimeClient.ExecSync(ctx, req) + if err != nil { + klog.Errorf("ExecSync %s '%s' from runtime service failed: %v", containerID, strings.Join(cmd, " "), err) + return nil, nil, err + } + + klog.V(10).Infof("[RuntimeService] ExecSync Response (containerID=%v, ExitCode=%v)", containerID, resp.ExitCode) + err = nil + if resp.ExitCode != 0 { + err = utilexec.CodeExitError{ + Err: fmt.Errorf("command '%s' exited with %d: %s", strings.Join(cmd, " "), resp.ExitCode, resp.Stderr), + Code: int(resp.ExitCode), + } + } + + return resp.Stdout, resp.Stderr, err +} + +// Exec prepares a streaming endpoint to execute a command in the container, and returns the address. +func (r *RuntimeService) Exec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) { + klog.V(10).Infof("[RuntimeService] Exec (timeout=%v)", r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.Exec(ctx, req) + if err != nil { + klog.Errorf("Exec %s '%s' from runtime service failed: %v", req.ContainerId, strings.Join(req.Cmd, " "), err) + return nil, err + } + klog.V(10).Info("[RuntimeService] Exec Response") + + if resp.Url == "" { + errorMessage := "URL is not set" + klog.Errorf("Exec failed: %s", errorMessage) + return nil, errors.New(errorMessage) + } + + return resp, nil +} + +// Attach prepares a streaming endpoint to attach to a running container, and returns the address. +func (r *RuntimeService) Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) { + klog.V(10).Infof("[RuntimeService] Attach (containerId=%v, timeout=%v)", req.ContainerId, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.Attach(ctx, req) + if err != nil { + klog.Errorf("Attach %s from runtime service failed: %v", req.ContainerId, err) + return nil, err + } + klog.V(10).Infof("[RuntimeService] Attach Response (containerId=%v)", req.ContainerId) + + if resp.Url == "" { + errorMessage := "URL is not set" + klog.Errorf("Attach failed: %s", errorMessage) + return nil, errors.New(errorMessage) + } + return resp, nil +} + +// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address. +func (r *RuntimeService) PortForward(req *runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) { + klog.V(10).Infof("[RuntimeService] PortForward (podSandboxID=%v, port=%v, timeout=%v)", req.PodSandboxId, req.Port, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.PortForward(ctx, req) + if err != nil { + klog.Errorf("PortForward %s from runtime service failed: %v", req.PodSandboxId, err) + return nil, err + } + klog.V(10).Infof("[RuntimeService] PortForward Response (podSandboxID=%v)", req.PodSandboxId) + + if resp.Url == "" { + errorMessage := "URL is not set" + klog.Errorf("PortForward failed: %s", errorMessage) + return nil, errors.New(errorMessage) + } + + return resp, nil +} + +// UpdateRuntimeConfig updates the config of a runtime service. The only +// update payload currently supported is the pod CIDR assigned to a node, +// and the runtime service just proxies it down to the network plugin. +func (r *RuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeapi.RuntimeConfig) error { + klog.V(10).Infof("[RuntimeService] UpdateRuntimeConfig (runtimeConfig=%v, timeout=%v)", runtimeConfig, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + // Response doesn't contain anything of interest. This translates to an + // Event notification to the network plugin, which can't fail, so we're + // really looking to surface destination unreachable. + _, err := r.runtimeClient.UpdateRuntimeConfig(ctx, &runtimeapi.UpdateRuntimeConfigRequest{ + RuntimeConfig: runtimeConfig, + }) + + if err != nil { + return err + } + klog.V(10).Infof("[RuntimeService] UpdateRuntimeConfig Response (runtimeConfig=%v)", runtimeConfig) + + return nil +} + +// Status returns the status of the runtime. +func (r *RuntimeService) Status() (*runtimeapi.RuntimeStatus, error) { + klog.V(10).Infof("[RuntimeService] Status (timeout=%v)", r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.Status(ctx, &runtimeapi.StatusRequest{}) + if err != nil { + klog.Errorf("Status from runtime service failed: %v", err) + return nil, err + } + + klog.V(10).Infof("[RuntimeService] Status Response (status=%v)", resp.Status) + + if resp.Status == nil || len(resp.Status.Conditions) < 2 { + errorMessage := "RuntimeReady or NetworkReady condition are not set" + klog.Errorf("Status failed: %s", errorMessage) + return nil, errors.New(errorMessage) + } + + return resp.Status, nil +} + +// ContainerStats returns the stats of the container. +func (r *RuntimeService) ContainerStats(containerID string) (*runtimeapi.ContainerStats, error) { + klog.V(10).Infof("[RuntimeService] ContainerStats (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + resp, err := r.runtimeClient.ContainerStats(ctx, &runtimeapi.ContainerStatsRequest{ + ContainerId: containerID, + }) + if err != nil { + if r.logReduction.ShouldMessageBePrinted(err.Error(), containerID) { + klog.Errorf("ContainerStats %q from runtime service failed: %v", containerID, err) + } + return nil, err + } + r.logReduction.ClearID(containerID) + klog.V(10).Infof("[RuntimeService] ContainerStats Response (containerID=%v, stats=%v)", containerID, resp.GetStats()) + + return resp.GetStats(), nil +} + +// ListContainerStats lists all container stats given the provided filter +func (r *RuntimeService) ListContainerStats(filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error) { + klog.V(10).Infof("[RuntimeService] ListContainerStats (filter=%v)", filter) + // Do not set timeout, because writable layer stats collection takes time. + // TODO(random-liu): Should we assume runtime should cache the result, and set timeout here? + ctx, cancel := getContextWithCancel() + defer cancel() + + resp, err := r.runtimeClient.ListContainerStats(ctx, &runtimeapi.ListContainerStatsRequest{ + Filter: filter, + }) + if err != nil { + klog.Errorf("ListContainerStats with filter %+v from runtime service failed: %v", filter, err) + return nil, err + } + klog.V(10).Infof("[RuntimeService] ListContainerStats Response (filter=%v, stats=%v)", filter, resp.GetStats()) + + return resp.GetStats(), nil +} + +// ReopenContainerLog reopens the container log for the given container ID +func (r *RuntimeService) ReopenContainerLog(containerID string) error { + klog.V(10).Infof("[RuntimeService] ReopenContainerLog (containerID=%v, timeout=%v)", containerID, r.timeout) + ctx, cancel := getContextWithTimeout(r.timeout) + defer cancel() + + _, err := r.runtimeClient.ReopenContainerLog(ctx, &runtimeapi.ReopenContainerLogRequest{ContainerId: containerID}) + if err != nil { + klog.Errorf("ReopenContainerLog %q from runtime service failed: %v", containerID, err) + return err + } + + klog.V(10).Infof("[RuntimeService] ReopenContainerLog Response (containerID=%v)", containerID) + return nil +} diff -Nru containerd-1.2.6/integration/remote/util/util_unix.go containerd-1.5.9/integration/remote/util/util_unix.go --- containerd-1.2.6/integration/remote/util/util_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/util/util_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,157 @@ +// +build freebsd linux darwin + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "io/ioutil" + "net" + "net/url" + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +const ( + // unixProtocol is the network protocol of unix socket. + unixProtocol = "unix" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) + if err != nil { + return nil, err + } + if protocol != unixProtocol { + return nil, fmt.Errorf("only support unix socket endpoint") + } + + // Unlink to cleanup the previous socket file. + err = unix.Unlink(addr) + if err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("failed to unlink socket file %q: %v", addr, err) + } + + if err := os.MkdirAll(filepath.Dir(addr), 0750); err != nil { + return nil, fmt.Errorf("error creating socket directory %q: %v", filepath.Dir(addr), err) + } + + // Create the socket on a tempfile and move it to the destination socket to handle improprer cleanup + file, err := ioutil.TempFile(filepath.Dir(addr), "") + if err != nil { + return nil, fmt.Errorf("failed to create temporary file: %v", err) + } + + if err := os.Remove(file.Name()); err != nil { + return nil, fmt.Errorf("failed to remove temporary file: %v", err) + } + + l, err := net.Listen(protocol, file.Name()) + if err != nil { + return nil, err + } + + if err = os.Rename(file.Name(), addr); err != nil { + return nil, fmt.Errorf("failed to move temporary file to addr %q: %v", addr, err) + } + + return l, nil +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) + if err != nil { + return "", nil, err + } + if protocol != unixProtocol { + return "", nil, fmt.Errorf("only support unix socket endpoint") + } + + return addr, dial, nil +} + +func dial(ctx context.Context, addr string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, unixProtocol, addr) +} + +func parseEndpointWithFallbackProtocol(endpoint string, fallbackProtocol string) (protocol string, addr string, err error) { + if protocol, addr, err = parseEndpoint(endpoint); err != nil && protocol == "" { + fallbackEndpoint := fallbackProtocol + "://" + endpoint + protocol, addr, err = parseEndpoint(fallbackEndpoint) + } + return +} + +func parseEndpoint(endpoint string) (string, string, error) { + u, err := url.Parse(endpoint) + if err != nil { + return "", "", err + } + + switch u.Scheme { + case "tcp": + return "tcp", u.Host, nil + + case "unix": + return "unix", u.Path, nil + + case "": + return "", "", fmt.Errorf("using %q as endpoint is deprecated, please consider using full url format", endpoint) + + default: + return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme) + } +} + +// IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file +func IsUnixDomainSocket(filePath string) (bool, error) { + fi, err := os.Stat(filePath) + if err != nil { + return false, fmt.Errorf("stat file %s failed: %v", filePath, err) + } + if fi.Mode()&os.ModeSocket == 0 { + return false, nil + } + return true, nil +} + +// NormalizePath is a no-op for Linux for now +func NormalizePath(path string) string { + return path +} diff -Nru containerd-1.2.6/integration/remote/util/util_unsupported.go containerd-1.5.9/integration/remote/util/util_unsupported.go --- containerd-1.2.6/integration/remote/util/util_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/util/util_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,71 @@ +// +build !freebsd,!linux,!windows,!darwin + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "net" + "time" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + return nil, fmt.Errorf("CreateListener is unsupported in this build") +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + return "", nil, fmt.Errorf("GetAddressAndDialer is unsupported in this build") +} + +// LockAndCheckSubPath empty implementation +func LockAndCheckSubPath(volumePath, subPath string) ([]uintptr, error) { + return []uintptr{}, nil +} + +// UnlockPath empty implementation +func UnlockPath(fileHandles []uintptr) { +} + +// LocalEndpoint empty implementation +func LocalEndpoint(path, file string) (string, error) { + return "", fmt.Errorf("LocalEndpoints are unsupported in this build") +} + +// GetBootTime empty implementation +func GetBootTime() (time.Time, error) { + return time.Time{}, fmt.Errorf("GetBootTime is unsupported in this build") +} diff -Nru containerd-1.2.6/integration/remote/util/util_windows.go containerd-1.5.9/integration/remote/util/util_windows.go --- containerd-1.2.6/integration/remote/util/util_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/util/util_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,165 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "net" + "net/url" + "strings" + "syscall" + "time" + + "github.com/Microsoft/go-winio" +) + +const ( + tcpProtocol = "tcp" + npipeProtocol = "npipe" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + protocol, addr, err := parseEndpoint(endpoint) + if err != nil { + return nil, err + } + + switch protocol { + case tcpProtocol: + return net.Listen(tcpProtocol, addr) + + case npipeProtocol: + return winio.ListenPipe(addr, nil) + + default: + return nil, fmt.Errorf("only support tcp and npipe endpoint") + } +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + protocol, addr, err := parseEndpoint(endpoint) + if err != nil { + return "", nil, err + } + + if protocol == tcpProtocol { + return addr, tcpDial, nil + } + + if protocol == npipeProtocol { + return addr, npipeDial, nil + } + + return "", nil, fmt.Errorf("only support tcp and npipe endpoint") +} + +func tcpDial(ctx context.Context, addr string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, tcpProtocol, addr) +} + +func npipeDial(ctx context.Context, addr string) (net.Conn, error) { + return winio.DialPipeContext(ctx, addr) +} + +func parseEndpoint(endpoint string) (string, string, error) { + // url.Parse doesn't recognize \, so replace with / first. + endpoint = strings.Replace(endpoint, "\\", "/", -1) + u, err := url.Parse(endpoint) + if err != nil { + return "", "", err + } + + if u.Scheme == "tcp" { + return "tcp", u.Host, nil + } else if u.Scheme == "npipe" { + if strings.HasPrefix(u.Path, "//./pipe") { + return "npipe", u.Path, nil + } + + // fallback host if not provided. + host := u.Host + if host == "" { + host = "." + } + return "npipe", fmt.Sprintf("//%s%s", host, u.Path), nil + } else if u.Scheme == "" { + return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint) + } else { + return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme) + } +} + +var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64") + +// GetBootTime returns the time at which the machine was started, truncated to the nearest second +func GetBootTime() (time.Time, error) { + currentTime := time.Now() + output, _, err := tickCount.Call() + if errno, ok := err.(syscall.Errno); !ok || errno != 0 { + return time.Time{}, err + } + return currentTime.Add(-time.Duration(output) * time.Millisecond).Truncate(time.Second), nil +} + +// IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file +func IsUnixDomainSocket(filePath string) (bool, error) { + // Due to the absence of golang support for os.ModeSocket in Windows (https://github.com/golang/go/issues/33357) + // we need to dial the file and check if we receive an error to determine if a file is Unix Domain Socket file. + + // Note that querrying for the Reparse Points (https://docs.microsoft.com/en-us/windows/win32/fileio/reparse-points) + // for the file (using FSCTL_GET_REPARSE_POINT) and checking for reparse tag: reparseTagSocket + // does NOT work in 1809 if the socket file is created within a bind mounted directory by a container + // and the FSCTL is issued in the host by the kubelet. + + c, err := net.Dial("unix", filePath) + if err == nil { + c.Close() + return true, nil + } + return false, nil +} + +// NormalizePath converts FS paths returned by certain go frameworks (like fsnotify) +// to native Windows paths that can be passed to Windows specific code +func NormalizePath(path string) string { + path = strings.ReplaceAll(path, "/", "\\") + if strings.HasPrefix(path, "\\") { + path = "c:" + path + } + return path +} diff -Nru containerd-1.2.6/integration/remote/utils.go containerd-1.5.9/integration/remote/utils.go --- containerd-1.2.6/integration/remote/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/remote/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remote + +import ( + "context" + "fmt" + "time" + + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// maxMsgSize use 16MB as the default message size limit. +// grpc library default is 4MB +const maxMsgSize = 1024 * 1024 * 16 + +// getContextWithTimeout returns a context with timeout. +func getContextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), timeout) +} + +// getContextWithCancel returns a context with cancel. +func getContextWithCancel() (context.Context, context.CancelFunc) { + return context.WithCancel(context.Background()) +} + +// verifySandboxStatus verified whether all required fields are set in PodSandboxStatus. +func verifySandboxStatus(status *runtimeapi.PodSandboxStatus) error { + if status.Id == "" { + return fmt.Errorf("Id is not set") + } + + if status.Metadata == nil { + return fmt.Errorf("Metadata is not set") + } + + metadata := status.Metadata + if metadata.Name == "" || metadata.Namespace == "" || metadata.Uid == "" { + return fmt.Errorf("Name, Namespace or Uid is not in metadata %q", metadata) + } + + if status.CreatedAt == 0 { + return fmt.Errorf("CreatedAt is not set") + } + + return nil +} + +// verifyContainerStatus verified whether all required fields are set in ContainerStatus. +func verifyContainerStatus(status *runtimeapi.ContainerStatus) error { + if status.Id == "" { + return fmt.Errorf("Id is not set") + } + + if status.Metadata == nil { + return fmt.Errorf("Metadata is not set") + } + + metadata := status.Metadata + if metadata.Name == "" { + return fmt.Errorf("Name is not in metadata %q", metadata) + } + + if status.CreatedAt == 0 { + return fmt.Errorf("CreatedAt is not set") + } + + if status.Image == nil || status.Image.Image == "" { + return fmt.Errorf("Image is not set") + } + + if status.ImageRef == "" { + return fmt.Errorf("ImageRef is not set") + } + + return nil +} diff -Nru containerd-1.2.6/integration/restart_test.go containerd-1.5.9/integration/restart_test.go --- containerd-1.2.6/integration/restart_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/restart_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,201 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "sort" + "testing" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Restart test must run sequentially. + +func TestContainerdRestart(t *testing.T) { + type container struct { + name string + id string + state runtime.ContainerState + } + type sandbox struct { + name string + id string + state runtime.PodSandboxState + containers []container + } + ctx := context.Background() + sandboxNS := "restart-containerd" + sandboxes := []sandbox{ + { + name: "ready-sandbox", + state: runtime.PodSandboxState_SANDBOX_READY, + containers: []container{ + { + name: "created-container", + state: runtime.ContainerState_CONTAINER_CREATED, + }, + { + name: "running-container", + state: runtime.ContainerState_CONTAINER_RUNNING, + }, + { + name: "exited-container", + state: runtime.ContainerState_CONTAINER_EXITED, + }, + }, + }, + { + name: "notready-sandbox", + state: runtime.PodSandboxState_SANDBOX_NOTREADY, + containers: []container{ + { + name: "created-container", + state: runtime.ContainerState_CONTAINER_CREATED, + }, + { + name: "running-container", + state: runtime.ContainerState_CONTAINER_RUNNING, + }, + { + name: "exited-container", + state: runtime.ContainerState_CONTAINER_EXITED, + }, + }, + }, + } + t.Logf("Make sure no sandbox is running before test") + existingSandboxes, err := runtimeService.ListPodSandbox(&runtime.PodSandboxFilter{}) + require.NoError(t, err) + require.Empty(t, existingSandboxes) + + t.Logf("Start test sandboxes and containers") + for i := range sandboxes { + s := &sandboxes[i] + sbCfg := PodSandboxConfig(s.name, sandboxNS) + sid, err := runtimeService.RunPodSandbox(sbCfg, *runtimeHandler) + require.NoError(t, err) + defer func() { + // Make sure the sandbox is cleaned up in any case. + runtimeService.StopPodSandbox(sid) + runtimeService.RemovePodSandbox(sid) + }() + s.id = sid + for j := range s.containers { + c := &s.containers[j] + cfg := ContainerConfig(c.name, pauseImage, + // Set pid namespace as per container, so that container won't die + // when sandbox container is killed. + WithPidNamespace(runtime.NamespaceMode_CONTAINER), + ) + cid, err := runtimeService.CreateContainer(sid, cfg, sbCfg) + require.NoError(t, err) + // Reply on sandbox cleanup. + c.id = cid + switch c.state { + case runtime.ContainerState_CONTAINER_CREATED: + case runtime.ContainerState_CONTAINER_RUNNING: + require.NoError(t, runtimeService.StartContainer(cid)) + case runtime.ContainerState_CONTAINER_EXITED: + require.NoError(t, runtimeService.StartContainer(cid)) + require.NoError(t, runtimeService.StopContainer(cid, 10)) + } + } + if s.state == runtime.PodSandboxState_SANDBOX_NOTREADY { + cntr, err := containerdClient.LoadContainer(ctx, sid) + require.NoError(t, err) + task, err := cntr.Task(ctx, nil) + require.NoError(t, err) + _, err = task.Delete(ctx, containerd.WithProcessKill) + if err != nil { + require.True(t, errdefs.IsNotFound(err)) + } + } + } + + t.Logf("Pull test images") + for _, image := range []string{GetImage(BusyBox), GetImage(Alpine)} { + img, err := imageService.PullImage(&runtime.ImageSpec{Image: image}, nil, nil) + require.NoError(t, err) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) + }() + } + imagesBeforeRestart, err := imageService.ListImages(nil) + assert.NoError(t, err) + + t.Logf("Restart containerd") + RestartContainerd(t) + + t.Logf("Check sandbox and container state after restart") + loadedSandboxes, err := runtimeService.ListPodSandbox(&runtime.PodSandboxFilter{}) + require.NoError(t, err) + assert.Len(t, loadedSandboxes, len(sandboxes)) + loadedContainers, err := runtimeService.ListContainers(&runtime.ContainerFilter{}) + require.NoError(t, err) + assert.Len(t, loadedContainers, len(sandboxes)*3) + for _, s := range sandboxes { + for _, loaded := range loadedSandboxes { + if s.id == loaded.Id { + assert.Equal(t, s.state, loaded.State) + break + } + } + for _, c := range s.containers { + for _, loaded := range loadedContainers { + if c.id == loaded.Id { + assert.Equal(t, c.state, loaded.State) + break + } + } + } + } + + t.Logf("Should be able to stop and remove sandbox after restart") + for _, s := range sandboxes { + assert.NoError(t, runtimeService.StopPodSandbox(s.id)) + assert.NoError(t, runtimeService.RemovePodSandbox(s.id)) + } + + t.Logf("Should recover all images") + imagesAfterRestart, err := imageService.ListImages(nil) + assert.NoError(t, err) + assert.Equal(t, len(imagesBeforeRestart), len(imagesAfterRestart)) + for _, i1 := range imagesBeforeRestart { + found := false + for _, i2 := range imagesAfterRestart { + if i1.Id == i2.Id { + sort.Strings(i1.RepoTags) + sort.Strings(i1.RepoDigests) + sort.Strings(i2.RepoTags) + sort.Strings(i2.RepoDigests) + assert.Equal(t, i1, i2) + found = true + break + } + } + assert.True(t, found, "should find image %+v", i1) + } +} + +// TODO: Add back the unknown state test. diff -Nru containerd-1.2.6/integration/runtime_handler_test.go containerd-1.5.9/integration/runtime_handler_test.go --- containerd-1.2.6/integration/runtime_handler_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/runtime_handler_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// TODO(chrisfegly): add/update test(s) to allow testing of multiple runtimes at the same time +func TestRuntimeHandler(t *testing.T) { + t.Logf("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "test-runtime-handler") + + if *runtimeHandler == "" { + t.Logf("The --runtime-handler flag value is empty which results internally to setting the default runtime") + } else { + t.Logf("The --runtime-handler flag value is %s", *runtimeHandler) + } + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + // Make sure the sandbox is cleaned up in any case. + runtimeService.StopPodSandbox(sb) + runtimeService.RemovePodSandbox(sb) + }() + + t.Logf("Verify runtimeService.PodSandboxStatus() returns previously set runtimeHandler") + sbStatus, err := runtimeService.PodSandboxStatus(sb) + require.NoError(t, err) + assert.Equal(t, *runtimeHandler, sbStatus.RuntimeHandler) + + t.Logf("Verify runtimeService.ListPodSandbox() returns previously set runtimeHandler") + sandboxes, err := runtimeService.ListPodSandbox(&runtime.PodSandboxFilter{}) + require.NoError(t, err) + assert.Equal(t, *runtimeHandler, sandboxes[0].RuntimeHandler) +} diff -Nru containerd-1.2.6/integration/sandbox_clean_remove_test.go containerd-1.5.9/integration/sandbox_clean_remove_test.go --- containerd-1.2.6/integration/sandbox_clean_remove_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/sandbox_clean_remove_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,126 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + "time" + + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/sys/unix" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestSandboxRemoveWithoutIPLeakage(t *testing.T) { + const hostLocalCheckpointDir = "/var/lib/cni" + + t.Logf("Make sure host-local ipam is in use") + config, err := CRIConfig() + require.NoError(t, err) + fs, err := ioutil.ReadDir(config.NetworkPluginConfDir) + require.NoError(t, err) + require.NotEmpty(t, fs) + f := filepath.Join(config.NetworkPluginConfDir, fs[0].Name()) + cniConfig, err := ioutil.ReadFile(f) + require.NoError(t, err) + if !strings.Contains(string(cniConfig), "host-local") { + t.Skip("host-local ipam is not in use") + } + + t.Logf("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "remove-without-ip-leakage") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + // Make sure the sandbox is cleaned up in any case. + runtimeService.StopPodSandbox(sb) + runtimeService.RemovePodSandbox(sb) + }() + + t.Logf("Get pod information") + status, info, err := SandboxInfo(sb) + require.NoError(t, err) + ip := status.GetNetwork().GetIp() + require.NotEmpty(t, ip) + require.NotNil(t, info.RuntimeSpec.Linux) + var netNS string + for _, n := range info.RuntimeSpec.Linux.Namespaces { + if n.Type == runtimespec.NetworkNamespace { + netNS = n.Path + } + } + require.NotEmpty(t, netNS, "network namespace should be set") + + t.Logf("Should be able to find the pod ip in host-local checkpoint") + checkIP := func(ip string) bool { + found := false + filepath.Walk(hostLocalCheckpointDir, func(_ string, info os.FileInfo, _ error) error { + if info != nil && info.Name() == ip { + found = true + } + return nil + }) + return found + } + require.True(t, checkIP(ip)) + + t.Logf("Kill sandbox container") + require.NoError(t, KillPid(int(info.Pid))) + + t.Logf("Unmount network namespace") + require.NoError(t, unix.Unmount(netNS, unix.MNT_DETACH)) + + t.Logf("Network namespace should be closed") + _, info, err = SandboxInfo(sb) + require.NoError(t, err) + assert.True(t, info.NetNSClosed) + + t.Logf("Remove network namespace") + require.NoError(t, os.RemoveAll(netNS)) + + t.Logf("Network namespace should still be closed") + _, info, err = SandboxInfo(sb) + require.NoError(t, err) + assert.True(t, info.NetNSClosed) + + t.Logf("Sandbox state should be NOTREADY") + assert.NoError(t, Eventually(func() (bool, error) { + status, err := runtimeService.PodSandboxStatus(sb) + if err != nil { + return false, err + } + return status.GetState() == runtime.PodSandboxState_SANDBOX_NOTREADY, nil + }, time.Second, 30*time.Second), "sandbox state should become NOTREADY") + + t.Logf("Should still be able to find the pod ip in host-local checkpoint") + assert.True(t, checkIP(ip)) + + t.Logf("Should be able to stop and remove the sandbox") + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + + t.Logf("Should not be able to find the pod ip in host-local checkpoint") + assert.False(t, checkIP(ip)) +} diff -Nru containerd-1.2.6/integration/truncindex_test.go containerd-1.5.9/integration/truncindex_test.go --- containerd-1.2.6/integration/truncindex_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/truncindex_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,160 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func genTruncIndex(normalName string) string { + return normalName[:(len(normalName)+1)/2] +} + +func TestTruncIndex(t *testing.T) { + sbConfig := PodSandboxConfig("sandbox", "truncindex") + + t.Logf("Pull an image") + var appImage = GetImage(BusyBox) + imgID, err := imageService.PullImage(&runtimeapi.ImageSpec{Image: appImage}, nil, sbConfig) + require.NoError(t, err) + imgTruncID := genTruncIndex(imgID) + defer func() { + assert.NoError(t, imageService.RemoveImage(&runtimeapi.ImageSpec{Image: imgTruncID})) + }() + + t.Logf("Get image status by truncindex, truncID: %s", imgTruncID) + res, err := imageService.ImageStatus(&runtimeapi.ImageSpec{Image: imgTruncID}) + require.NoError(t, err) + require.NotEqual(t, nil, res) + assert.Equal(t, imgID, res.Id) + + // TODO(yanxuean): for failure test case where there are two images with the same truncindex. + // if you add n images at least two will share the same leading digit. + // "sha256:n" where n is the a number from 0-9 where two images have the same trunc, + // for example sha256:9 + // https://github.com/containerd/cri/pull/352 + // I am thinking how I get the two image which have same trunc. + + // TODO(yanxuean): add test case for ListImages + + t.Logf("Create a sandbox") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + sbTruncIndex := genTruncIndex(sb) + var hasStoppedSandbox bool + defer func() { + // The 2th StopPodSandbox will fail, the 2th RemovePodSandbox will success. + if !hasStoppedSandbox { + assert.NoError(t, runtimeService.StopPodSandbox(sbTruncIndex)) + } + assert.NoError(t, runtimeService.RemovePodSandbox(sbTruncIndex)) + }() + + t.Logf("Get sandbox status by truncindex") + sbStatus, err := runtimeService.PodSandboxStatus(sbTruncIndex) + require.NoError(t, err) + assert.Equal(t, sb, sbStatus.Id) + + t.Logf("Forward port for sandbox by truncindex") + _, err = runtimeService.PortForward(&runtimeapi.PortForwardRequest{PodSandboxId: sbTruncIndex, Port: []int32{80}}) + assert.NoError(t, err) + + // TODO(yanxuean): add test case for ListPodSandbox + + t.Logf("Create a container") + cnConfig := ContainerConfig( + "containerTruncIndex", + appImage, + WithCommand("top"), + ) + cn, err := runtimeService.CreateContainer(sbTruncIndex, cnConfig, sbConfig) + require.NoError(t, err) + cnTruncIndex := genTruncIndex(cn) + defer func() { + // the 2th RemovePodSandbox will success. + assert.NoError(t, runtimeService.RemoveContainer(cnTruncIndex)) + }() + + t.Logf("Get container status by truncindex") + cStatus, err := runtimeService.ContainerStatus(cnTruncIndex) + require.NoError(t, err) + assert.Equal(t, cn, cStatus.Id) + + t.Logf("Start the container") + require.NoError(t, runtimeService.StartContainer(cnTruncIndex)) + var hasStoppedContainer bool + defer func() { + // The 2th StopPodSandbox will fail + if !hasStoppedContainer { + assert.NoError(t, runtimeService.StopContainer(cnTruncIndex, 10)) + } + }() + + t.Logf("Stats the container") + cStats, err := runtimeService.ContainerStats(cnTruncIndex) + require.NoError(t, err) + assert.Equal(t, cn, cStats.Attributes.Id) + + t.Logf("Update container memory limit after started") + err = runtimeService.UpdateContainerResources(cnTruncIndex, &runtimeapi.LinuxContainerResources{ + MemoryLimitInBytes: 50 * 1024 * 1024, + }) + assert.NoError(t, err) + + t.Logf("Execute cmd in container") + execReq := &runtimeapi.ExecRequest{ + ContainerId: cnTruncIndex, + Cmd: []string{"pwd"}, + Stdout: true, + } + _, err = runtimeService.Exec(execReq) + assert.NoError(t, err) + + t.Logf("Execute cmd in container by sync") + _, _, err = runtimeService.ExecSync(cnTruncIndex, []string{"pwd"}, 10) + assert.NoError(t, err) + + // TODO(yanxuean): add test case for ListContainers + + t.Logf("Get a non exist container status by truncindex") + err = runtimeService.StopContainer(cnTruncIndex, 10) + assert.NoError(t, err) + if err == nil { + hasStoppedContainer = true + } + _, err = runtimeService.ContainerStats(cnTruncIndex) + assert.Error(t, err) + assert.NoError(t, runtimeService.RemoveContainer(cnTruncIndex)) + _, err = runtimeService.ContainerStatus(cnTruncIndex) + assert.Error(t, err) + + t.Logf("Get a non exist sandbox status by truncindex") + err = runtimeService.StopPodSandbox(sbTruncIndex) + assert.NoError(t, err) + if err == nil { + hasStoppedSandbox = true + } + assert.NoError(t, runtimeService.RemovePodSandbox(sbTruncIndex)) + _, err = runtimeService.PodSandboxStatus(sbTruncIndex) + assert.Error(t, err) +} diff -Nru containerd-1.2.6/integration/util/boottime_util_darwin.go containerd-1.5.9/integration/util/boottime_util_darwin.go --- containerd-1.2.6/integration/util/boottime_util_darwin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/boottime_util_darwin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +// +build darwin + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "fmt" + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/unix" +) + +// GetBootTime returns the time at which the machine was started, truncated to the nearest second +func GetBootTime() (time.Time, error) { + output, err := unix.SysctlRaw("kern.boottime") + if err != nil { + return time.Time{}, err + } + var timeval syscall.Timeval + if len(output) != int(unsafe.Sizeof(timeval)) { + return time.Time{}, fmt.Errorf("unexpected output when calling syscall kern.bootime. Expected len(output) to be %v, but got %v", + int(unsafe.Sizeof(timeval)), len(output)) + } + timeval = *(*syscall.Timeval)(unsafe.Pointer(&output[0])) + sec, nsec := timeval.Unix() + return time.Unix(sec, nsec).Truncate(time.Second), nil +} diff -Nru containerd-1.2.6/integration/util/boottime_util_linux.go containerd-1.5.9/integration/util/boottime_util_linux.go --- containerd-1.2.6/integration/util/boottime_util_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/boottime_util_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +// +build freebsd linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "fmt" + "time" + + "golang.org/x/sys/unix" +) + +// GetBootTime returns the time at which the machine was started, truncated to the nearest second +func GetBootTime() (time.Time, error) { + currentTime := time.Now() + var info unix.Sysinfo_t + if err := unix.Sysinfo(&info); err != nil { + return time.Time{}, fmt.Errorf("error getting system uptime: %s", err) + } + return currentTime.Add(-time.Duration(info.Uptime) * time.Second).Truncate(time.Second), nil +} diff -Nru containerd-1.2.6/integration/util/doc.go containerd-1.5.9/integration/util/doc.go --- containerd-1.2.6/integration/util/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package util holds utility functions. +package util diff -Nru containerd-1.2.6/integration/util/util.go containerd-1.5.9/integration/util/util.go --- containerd-1.2.6/integration/util/util.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/util.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// FromApiserverCache modifies so that the GET request will +// be served from apiserver cache instead of from etcd. +func FromApiserverCache(opts *metav1.GetOptions) { + opts.ResourceVersion = "0" +} diff -Nru containerd-1.2.6/integration/util/util_unix.go containerd-1.5.9/integration/util/util_unix.go --- containerd-1.2.6/integration/util/util_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/util_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,166 @@ +// +build freebsd linux darwin + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "io/ioutil" + "net" + "net/url" + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +const ( + // unixProtocol is the network protocol of unix socket. + unixProtocol = "unix" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) + if err != nil { + return nil, err + } + if protocol != unixProtocol { + return nil, fmt.Errorf("only support unix socket endpoint") + } + + // Unlink to cleanup the previous socket file. + err = unix.Unlink(addr) + if err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("failed to unlink socket file %q: %v", addr, err) + } + + if err := os.MkdirAll(filepath.Dir(addr), 0750); err != nil { + return nil, fmt.Errorf("error creating socket directory %q: %v", filepath.Dir(addr), err) + } + + // Create the socket on a tempfile and move it to the destination socket to handle improprer cleanup + file, err := ioutil.TempFile(filepath.Dir(addr), "") + if err != nil { + return nil, fmt.Errorf("failed to create temporary file: %v", err) + } + + if err := os.Remove(file.Name()); err != nil { + return nil, fmt.Errorf("failed to remove temporary file: %v", err) + } + + l, err := net.Listen(protocol, file.Name()) + if err != nil { + return nil, err + } + + if err = os.Rename(file.Name(), addr); err != nil { + return nil, fmt.Errorf("failed to move temporary file to addr %q: %v", addr, err) + } + + return l, nil +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol) + if err != nil { + return "", nil, err + } + if protocol != unixProtocol { + return "", nil, fmt.Errorf("only support unix socket endpoint") + } + + return addr, dial, nil +} + +func dial(ctx context.Context, addr string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, unixProtocol, addr) +} + +func parseEndpointWithFallbackProtocol(endpoint string, fallbackProtocol string) (protocol string, addr string, err error) { + if protocol, addr, err = parseEndpoint(endpoint); err != nil && protocol == "" { + fallbackEndpoint := fallbackProtocol + "://" + endpoint + protocol, addr, err = parseEndpoint(fallbackEndpoint) + } + return +} + +func parseEndpoint(endpoint string) (string, string, error) { + u, err := url.Parse(endpoint) + if err != nil { + return "", "", err + } + + switch u.Scheme { + case "tcp": + return "tcp", u.Host, nil + + case "unix": + return "unix", u.Path, nil + + case "": + return "", "", fmt.Errorf("using %q as endpoint is deprecated, please consider using full url format", endpoint) + + default: + return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme) + } +} + +// LocalEndpoint returns the full path to a unix socket at the given endpoint +func LocalEndpoint(path, file string) (string, error) { + u := url.URL{ + Scheme: unixProtocol, + Path: path, + } + return filepath.Join(u.String(), file+".sock"), nil +} + +// IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file +func IsUnixDomainSocket(filePath string) (bool, error) { + fi, err := os.Stat(filePath) + if err != nil { + return false, fmt.Errorf("stat file %s failed: %v", filePath, err) + } + if fi.Mode()&os.ModeSocket == 0 { + return false, nil + } + return true, nil +} + +// NormalizePath is a no-op for Linux for now +func NormalizePath(path string) string { + return path +} diff -Nru containerd-1.2.6/integration/util/util_unsupported.go containerd-1.5.9/integration/util/util_unsupported.go --- containerd-1.2.6/integration/util/util_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/util_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,71 @@ +// +build !freebsd,!linux,!windows,!darwin + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "net" + "time" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + return nil, fmt.Errorf("CreateListener is unsupported in this build") +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + return "", nil, fmt.Errorf("GetAddressAndDialer is unsupported in this build") +} + +// LockAndCheckSubPath empty implementation +func LockAndCheckSubPath(volumePath, subPath string) ([]uintptr, error) { + return []uintptr{}, nil +} + +// UnlockPath empty implementation +func UnlockPath(fileHandles []uintptr) { +} + +// LocalEndpoint empty implementation +func LocalEndpoint(path, file string) (string, error) { + return "", fmt.Errorf("LocalEndpoints are unsupported in this build") +} + +// GetBootTime empty implementation +func GetBootTime() (time.Time, error) { + return time.Time{}, fmt.Errorf("GetBootTime is unsupported in this build") +} diff -Nru containerd-1.2.6/integration/util/util_windows.go containerd-1.5.9/integration/util/util_windows.go --- containerd-1.2.6/integration/util/util_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/util/util_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,170 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "context" + "fmt" + "net" + "net/url" + "strings" + "syscall" + "time" + + "github.com/Microsoft/go-winio" +) + +const ( + tcpProtocol = "tcp" + npipeProtocol = "npipe" +) + +// CreateListener creates a listener on the specified endpoint. +func CreateListener(endpoint string) (net.Listener, error) { + protocol, addr, err := parseEndpoint(endpoint) + if err != nil { + return nil, err + } + + switch protocol { + case tcpProtocol: + return net.Listen(tcpProtocol, addr) + + case npipeProtocol: + return winio.ListenPipe(addr, nil) + + default: + return nil, fmt.Errorf("only support tcp and npipe endpoint") + } +} + +// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer. +func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) { + protocol, addr, err := parseEndpoint(endpoint) + if err != nil { + return "", nil, err + } + + if protocol == tcpProtocol { + return addr, tcpDial, nil + } + + if protocol == npipeProtocol { + return addr, npipeDial, nil + } + + return "", nil, fmt.Errorf("only support tcp and npipe endpoint") +} + +func tcpDial(ctx context.Context, addr string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, tcpProtocol, addr) +} + +func npipeDial(ctx context.Context, addr string) (net.Conn, error) { + return winio.DialPipeContext(ctx, addr) +} + +func parseEndpoint(endpoint string) (string, string, error) { + // url.Parse doesn't recognize \, so replace with / first. + endpoint = strings.Replace(endpoint, "\\", "/", -1) + u, err := url.Parse(endpoint) + if err != nil { + return "", "", err + } + + if u.Scheme == "tcp" { + return "tcp", u.Host, nil + } else if u.Scheme == "npipe" { + if strings.HasPrefix(u.Path, "//./pipe") { + return "npipe", u.Path, nil + } + + // fallback host if not provided. + host := u.Host + if host == "" { + host = "." + } + return "npipe", fmt.Sprintf("//%s%s", host, u.Path), nil + } else if u.Scheme == "" { + return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint) + } else { + return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme) + } +} + +// LocalEndpoint empty implementation +func LocalEndpoint(path, file string) (string, error) { + return "", fmt.Errorf("LocalEndpoints are unsupported in this build") +} + +var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64") + +// GetBootTime returns the time at which the machine was started, truncated to the nearest second +func GetBootTime() (time.Time, error) { + currentTime := time.Now() + output, _, err := tickCount.Call() + if errno, ok := err.(syscall.Errno); !ok || errno != 0 { + return time.Time{}, err + } + return currentTime.Add(-time.Duration(output) * time.Millisecond).Truncate(time.Second), nil +} + +// IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file +func IsUnixDomainSocket(filePath string) (bool, error) { + // Due to the absence of golang support for os.ModeSocket in Windows (https://github.com/golang/go/issues/33357) + // we need to dial the file and check if we receive an error to determine if a file is Unix Domain Socket file. + + // Note that querrying for the Reparse Points (https://docs.microsoft.com/en-us/windows/win32/fileio/reparse-points) + // for the file (using FSCTL_GET_REPARSE_POINT) and checking for reparse tag: reparseTagSocket + // does NOT work in 1809 if the socket file is created within a bind mounted directory by a container + // and the FSCTL is issued in the host by the kubelet. + + c, err := net.Dial("unix", filePath) + if err == nil { + c.Close() + return true, nil + } + return false, nil +} + +// NormalizePath converts FS paths returned by certain go frameworks (like fsnotify) +// to native Windows paths that can be passed to Windows specific code +func NormalizePath(path string) string { + path = strings.ReplaceAll(path, "/", "\\") + if strings.HasPrefix(path, "\\") { + path = "c:" + path + } + return path +} diff -Nru containerd-1.2.6/integration/volume_copy_up_test.go containerd-1.5.9/integration/volume_copy_up_test.go --- containerd-1.2.6/integration/volume_copy_up_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/integration/volume_copy_up_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,140 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "fmt" + "os/exec" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestVolumeCopyUp(t *testing.T) { + var ( + testImage = GetImage(VolumeCopyUp) + execTimeout = time.Minute + ) + + t.Logf("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "volume-copy-up") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + t.Logf("Pull test image") + _, err = imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + + t.Logf("Create a container with volume-copy-up test image") + cnConfig := ContainerConfig( + "container", + testImage, + WithCommand("tail", "-f", "/dev/null"), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Logf("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + // gcr.io/k8s-cri-containerd/volume-copy-up:2.0 contains a test_dir + // volume, which contains a test_file with content "test_content". + t.Logf("Check whether volume contains the test file") + stdout, stderr, err := runtimeService.ExecSync(cn, []string{ + "cat", + "/test_dir/test_file", + }, execTimeout) + require.NoError(t, err) + assert.Empty(t, stderr) + assert.Equal(t, "test_content\n", string(stdout)) + + t.Logf("Check host path of the volume") + hostCmd := fmt.Sprintf("find %s/containers/%s/volumes/*/test_file | xargs cat", *criRoot, cn) + output, err := exec.Command("sh", "-c", hostCmd).CombinedOutput() + require.NoError(t, err) + assert.Equal(t, "test_content\n", string(output)) + + t.Logf("Update volume from inside the container") + _, _, err = runtimeService.ExecSync(cn, []string{ + "sh", + "-c", + "echo new_content > /test_dir/test_file", + }, execTimeout) + require.NoError(t, err) + + t.Logf("Check whether host path of the volume is updated") + output, err = exec.Command("sh", "-c", hostCmd).CombinedOutput() + require.NoError(t, err) + assert.Equal(t, "new_content\n", string(output)) +} + +func TestVolumeOwnership(t *testing.T) { + var ( + testImage = GetImage(VolumeOwnership) + execTimeout = time.Minute + ) + + t.Logf("Create a sandbox") + sbConfig := PodSandboxConfig("sandbox", "volume-ownership") + sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) + require.NoError(t, err) + defer func() { + assert.NoError(t, runtimeService.StopPodSandbox(sb)) + assert.NoError(t, runtimeService.RemovePodSandbox(sb)) + }() + + t.Logf("Pull test image") + _, err = imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) + require.NoError(t, err) + + t.Logf("Create a container with volume-ownership test image") + cnConfig := ContainerConfig( + "container", + testImage, + WithCommand("tail", "-f", "/dev/null"), + ) + cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) + require.NoError(t, err) + + t.Logf("Start the container") + require.NoError(t, runtimeService.StartContainer(cn)) + + // gcr.io/k8s-cri-containerd/volume-ownership:2.0 contains a test_dir + // volume, which is owned by nobody:nogroup. + t.Logf("Check ownership of test directory inside container") + stdout, stderr, err := runtimeService.ExecSync(cn, []string{ + "stat", "-c", "%U:%G", "/test_dir", + }, execTimeout) + require.NoError(t, err) + assert.Empty(t, stderr) + assert.Equal(t, "nobody:nogroup\n", string(stdout)) + + t.Logf("Check ownership of test directory on the host") + hostCmd := fmt.Sprintf("find %s/containers/%s/volumes/* | xargs stat -c %%U:%%G", *criRoot, cn) + output, err := exec.Command("sh", "-c", hostCmd).CombinedOutput() + require.NoError(t, err) + assert.Equal(t, "nobody:nogroup\n", string(output)) +} diff -Nru containerd-1.2.6/labels/labels.go containerd-1.5.9/labels/labels.go --- containerd-1.2.6/labels/labels.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/labels/labels.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package labels + +// LabelUncompressed is added to compressed layer contents. +// The value is digest of the uncompressed content. +const LabelUncompressed = "containerd.io/uncompressed" diff -Nru containerd-1.2.6/lease.go containerd-1.5.9/lease.go --- containerd-1.2.6/lease.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/lease.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,19 +24,27 @@ ) // WithLease attaches a lease on the context -func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.Context) error, error) { +func (c *Client) WithLease(ctx context.Context, opts ...leases.Opt) (context.Context, func(context.Context) error, error) { + nop := func(context.Context) error { return nil } + _, ok := leases.FromContext(ctx) if ok { - return ctx, func(context.Context) error { - return nil - }, nil + return ctx, nop, nil } ls := c.LeasesService() - l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(24*time.Hour)) + if len(opts) == 0 { + // Use default lease configuration if no options provided + opts = []leases.Opt{ + leases.WithRandomID(), + leases.WithExpiration(24 * time.Hour), + } + } + + l, err := ls.Create(ctx, opts...) if err != nil { - return nil, nil, err + return ctx, nop, err } ctx = leases.WithLease(ctx, l.ID) diff -Nru containerd-1.2.6/leases/lease.go containerd-1.5.9/leases/lease.go --- containerd-1.2.6/leases/lease.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/leases/lease.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,6 +32,9 @@ Create(context.Context, ...Opt) (Lease, error) Delete(context.Context, Lease, ...DeleteOpt) error List(context.Context, ...string) ([]Lease, error) + AddResource(context.Context, Lease, Resource) error + DeleteResource(context.Context, Lease, Resource) error + ListResources(context.Context, Lease) ([]Resource, error) } // Lease retains resources to prevent cleanup before @@ -42,6 +45,13 @@ Labels map[string]string } +// Resource represents low level resource of image, like content, ingest and +// snapshotter. +type Resource struct { + ID string + Type string +} + // DeleteOptions provide options on image delete type DeleteOptions struct { Synchronous bool diff -Nru containerd-1.2.6/leases/proxy/manager.go containerd-1.5.9/leases/proxy/manager.go --- containerd-1.2.6/leases/proxy/manager.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/leases/proxy/manager.go 2022-01-05 17:30:58.000000000 +0000 @@ -91,3 +91,43 @@ return l, nil } + +func (pm *proxyManager) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { + _, err := pm.client.AddResource(ctx, &leasesapi.AddResourceRequest{ + ID: lease.ID, + Resource: leasesapi.Resource{ + ID: r.ID, + Type: r.Type, + }, + }) + return errdefs.FromGRPC(err) +} + +func (pm *proxyManager) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { + _, err := pm.client.DeleteResource(ctx, &leasesapi.DeleteResourceRequest{ + ID: lease.ID, + Resource: leasesapi.Resource{ + ID: r.ID, + Type: r.Type, + }, + }) + return errdefs.FromGRPC(err) +} + +func (pm *proxyManager) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) { + resp, err := pm.client.ListResources(ctx, &leasesapi.ListResourcesRequest{ + ID: lease.ID, + }) + if err != nil { + return nil, errdefs.FromGRPC(err) + } + + rs := make([]leases.Resource, 0, len(resp.Resources)) + for _, i := range resp.Resources { + rs = append(rs, leases.Resource{ + ID: i.ID, + Type: i.Type, + }) + } + return rs, nil +} diff -Nru containerd-1.2.6/log/context.go containerd-1.5.9/log/context.go --- containerd-1.2.6/log/context.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/log/context.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,7 +18,6 @@ import ( "context" - "sync/atomic" "github.com/sirupsen/logrus" ) @@ -30,7 +29,7 @@ // messages. G = GetLogger - // L is an alias for the the standard logger. + // L is an alias for the standard logger. L = logrus.NewEntry(logrus.StandardLogger()) ) @@ -38,22 +37,17 @@ loggerKey struct{} ) -// TraceLevel is the log level for tracing. Trace level is lower than debug level, -// and is usually used to trace detailed behavior of the program. -const TraceLevel = logrus.Level(uint32(logrus.DebugLevel + 1)) - -// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to -// ensure the formatted time is always the same number of characters. -const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" - -// ParseLevel takes a string level and returns the Logrus log level constant. -// It supports trace level. -func ParseLevel(lvl string) (logrus.Level, error) { - if lvl == "trace" { - return TraceLevel, nil - } - return logrus.ParseLevel(lvl) -} +const ( + // RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to + // ensure the formatted time is always the same number of characters. + RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" + + // TextFormat represents the text logging format + TextFormat = "text" + + // JSONFormat represents the JSON logging format + JSONFormat = "json" +) // WithLogger returns a new context with the provided logger. Use in // combination with logger.WithField(s) for great effect. @@ -72,19 +66,3 @@ return logger.(*logrus.Entry) } - -// Trace logs a message at level Trace with the log entry passed-in. -func Trace(e *logrus.Entry, args ...interface{}) { - level := logrus.Level(atomic.LoadUint32((*uint32)(&e.Logger.Level))) - if level >= TraceLevel { - e.Debug(args...) - } -} - -// Tracef logs a message at level Trace with the log entry passed-in. -func Tracef(e *logrus.Entry, format string, args ...interface{}) { - level := logrus.Level(atomic.LoadUint32((*uint32)(&e.Logger.Level))) - if level >= TraceLevel { - e.Debugf(format, args...) - } -} diff -Nru containerd-1.2.6/log/context_test.go containerd-1.5.9/log/context_test.go --- containerd-1.2.6/log/context_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/log/context_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,7 @@ "context" "testing" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) func TestLoggerContext(t *testing.T) { diff -Nru containerd-1.2.6/log/logtest/context.go containerd-1.5.9/log/logtest/context.go --- containerd-1.2.6/log/logtest/context.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/log/logtest/context.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logtest + +import ( + "context" + "fmt" + "io/ioutil" + "path/filepath" + "runtime" + "testing" + + "github.com/containerd/containerd/log" + "github.com/sirupsen/logrus" +) + +// WithT adds a logging hook for the given test +// Changes debug level to debug, clears output, and +// outputs all log messages as test logs. +func WithT(ctx context.Context, t testing.TB) context.Context { + // Create a new logger to avoid adding hooks from multiple tests + l := logrus.New() + + // Increase debug level for tests + l.SetLevel(logrus.DebugLevel) + l.SetOutput(ioutil.Discard) + l.SetReportCaller(true) + + // Add testing hook + l.AddHook(&testHook{ + t: t, + fmt: &logrus.TextFormatter{ + DisableColors: true, + TimestampFormat: log.RFC3339NanoFixed, + CallerPrettyfier: func(frame *runtime.Frame) (string, string) { + return filepath.Base(frame.Function), fmt.Sprintf("%s:%d", frame.File, frame.Line) + }, + }, + }) + + return log.WithLogger(ctx, logrus.NewEntry(l)) +} diff -Nru containerd-1.2.6/log/logtest/log_hook.go containerd-1.5.9/log/logtest/log_hook.go --- containerd-1.2.6/log/logtest/log_hook.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/log/logtest/log_hook.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logtest + +import ( + "bytes" + "testing" + + "github.com/sirupsen/logrus" +) + +type testHook struct { + t testing.TB + fmt logrus.Formatter +} + +func (*testHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *testHook) Fire(e *logrus.Entry) error { + s, err := h.fmt.Format(e) + if err != nil { + return err + } + h.t.Log(string(bytes.TrimRight(s, "\n"))) + return nil +} diff -Nru containerd-1.2.6/.mailmap containerd-1.5.9/.mailmap --- containerd-1.2.6/.mailmap 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.mailmap 2022-01-05 17:30:58.000000000 +0000 @@ -1,30 +1,127 @@ -Abhinandan Prativadi Abhinandan Prativadi -Abhinandan Prativadi abhi -Akihiro Suda Akihiro Suda -Andrei Vagin Andrei Vagin -Brent Baude baude -Frank Yang frank yang -Georgia Panoutsakopoulou gpanouts -Jie Zhang kadisi -John Howard John Howard -Justin Terry Justin Terry (VM) -Justin Terry Justin -Kenfe-Mickaël Laventure Kenfe-Mickael Laventure -Kevin Xu kevin.xu -Lu Jingxiao l00397676 -Lantao Liu Lantao Liu -Phil Estes Phil Estes -Stephen J Day Stephen J Day -Stephen J Day Stephen Day -Stephen J Day Stephen Day -Sudeesh John sudeesh john -Tõnis Tiigi Tonis Tiigi -Lifubang Lifubang -Xiaodong Zhang nashasha1 -Jian Liao liaoj -Jian Liao liaojian -Rui Cao ruicao -Xuean Yan yanxuean -Mike Brown Mike Brown +Abhinandan Prativadi +Abhinandan Prativadi Ace-Tang +Akihiro Suda +Akihiro Suda +Allen Sun +Alexander Morozov +Antonio Ojea +Amit Krishnan +Andrei Vagin +Andrey Kolomentsev +Arnaud Porterie +Arnaud Porterie +Bob Mader +Boris Popovschi +Bowen Yan +Brent Baude +Cao Zhihao +Cao Zhihao +Carlos Eduardo +chenxiaoyu +Cory Bennett +Cristian Staretu +Cristian Staretu +Daniel Dao +Derek McGowan +Edgar Lee +Eric Ernst +Eric Ren +Eric Ren +Eric Ren +Fahed Dorgaa +Frank Yang +Fupan Li +Fupan Li +Georgia Panoutsakopoulou +Guangming Wang +Haiyan Meng +Harry Zhang +Hu Shuai +Hu Shuai +Iceber Gu +Jaana Burcu Dogan +Jess Valarezo +Jess Valarezo +Jian Liao +Jian Liao +Ji'an Liu +Jie Zhang +John Howard +John Howard +John Howard +John Howard +Lorenz Brun +Luc Perkins +Julien Balestra +Jun Lin Chen <1913688+mc256@users.noreply.github.com> +Justin Cormack +Justin Terry +Justin Terry +Kenfe-Mickaël Laventure +Kevin Kern +Kevin Parsons +Kevin Xu +Kohei Tokunaga +Krasi Georgiev +Lantao Liu +Lantao Liu +Li Yuxuan +Lifubang +Lu Jingxiao +Maksym Pavlenko +Maksym Pavlenko +Mario Hros +Mario Hros +Mario Macias +Mark Gordon +Michael Crosby +Michael Katsoulis +Mike Brown +Mohammad Asif Siddiqui +Nishchay Kumar +Oliver Stenbom +Phil Estes +Phil Estes +Reid Li +Robin Winkelewski +Ross Boucher +Ruediger Maass +Rui Cao +Sakeven Jiang +Samuel Karp +Seth Pellegrino <30441101+sethp-nr@users.noreply.github.com> +Shaobao Feng +Shengbo Song +Shengjing Zhu +Siddharth Yadav +SiYu Zhao +Stefan Berger +Stefan Berger +Stephen J Day +Stephen J Day +Stephen J Day +Sudeesh John +Su Fei +Su Xiaolin +Ted Yu +Tõnis Tiigi +Wade Lee +Wade Lee +Wade Lee <21621232@zju.edu.cn> +wanglei Wei Fu +Wei Fu +Xiaodong Zhang +Xuean Yan +Yue Zhang +Yuxing Liu +Zhang Wei +zhangyadong +Zhenguang Zhu +Zhiyu Li +Zhiyu Li <404977848@qq.com> +Zhongming Chang +Zhoulin Xie +Zhoulin Xie <42261994+JoeWrightss@users.noreply.github.com> +张潇 diff -Nru containerd-1.2.6/Makefile containerd-1.5.9/Makefile --- containerd-1.2.6/Makefile 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -13,20 +13,25 @@ # limitations under the License. +# Go command to use for build +GO ?= go + # Root directory of the project (absolute path). ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) # Base path used to install. -DESTDIR=/usr/local +DESTDIR ?= /usr/local +TEST_IMAGE_LIST ?= # Used to populate variables in version package. VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always) REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi) PACKAGE=github.com/containerd/containerd +SHIM_CGO_ENABLED ?= 0 -ifneq "$(strip $(shell command -v go 2>/dev/null))" "" - GOOS ?= $(shell go env GOOS) - GOARCH ?= $(shell go env GOARCH) +ifneq "$(strip $(shell command -v $(GO) 2>/dev/null))" "" + GOOS ?= $(shell $(GO) env GOOS) + GOARCH ?= $(shell $(GO) env GOARCH) else ifeq ($(GOOS),) # approximate GOOS for the platform if we don't have Go and GOOS isn't @@ -51,16 +56,39 @@ endif endif +ifndef GODEBUG + EXTRA_LDFLAGS += -s -w + DEBUG_GO_GCFLAGS := + DEBUG_TAGS := +else + DEBUG_GO_GCFLAGS := -gcflags=all="-N -l" + DEBUG_TAGS := static_build +endif + WHALE = "🇩" ONI = "👹" RELEASE=containerd-$(VERSION:v%=%).${GOOS}-${GOARCH} +CRIRELEASE=cri-containerd-$(VERSION:v%=%)-${GOOS}-${GOARCH} +CRICNIRELEASE=cri-containerd-cni-$(VERSION:v%=%)-${GOOS}-${GOARCH} PKG=github.com/containerd/containerd +# Project binaries. +COMMANDS=ctr containerd containerd-stress +MANPAGES=ctr.8 containerd.8 containerd-config.8 containerd-config.toml.5 + +ifdef BUILDTAGS + GO_BUILDTAGS = ${BUILDTAGS} +endif +GO_BUILDTAGS ?= +GO_BUILDTAGS += ${DEBUG_TAGS} +GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(GO_BUILDTAGS)",) +GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)' +SHIM_GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static" $(EXTRA_LDFLAGS)' + # Project packages. -PACKAGES=$(shell go list ./... | grep -v /vendor/) -INTEGRATION_PACKAGE=${PKG} +PACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration) TEST_REQUIRES_ROOT_PACKAGES=$(filter \ ${PACKAGES}, \ $(shell \ @@ -71,15 +99,10 @@ done | sort -u) \ ) -# Project binaries. -COMMANDS=ctr containerd containerd-stress -MANPAGES=ctr.1 containerd.1 containerd-config.1 containerd-config.toml.5 - -# Build tags seccomp and apparmor are needed by CRI plugin. -BUILDTAGS ?= seccomp apparmor -GO_TAGS=$(if $(BUILDTAGS),-tags "$(BUILDTAGS)",) -GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)' -SHIM_GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static"' +ifdef SKIPTESTS + PACKAGES:=$(filter-out ${SKIPTESTS},${PACKAGES}) + TEST_REQUIRES_ROOT_PACKAGES:=$(filter-out ${SKIPTESTS},${TEST_REQUIRES_ROOT_PACKAGES}) +endif #Replaces ":" (*nix), ";" (windows) with newline for easy parsing GOPATHS=$(shell echo ${GOPATH} | tr ":" "\n" | tr ";" "\n") @@ -92,23 +115,29 @@ echo "-gcflags=-trimpath=$${1}/src"; \ ) +BINARIES=$(addprefix bin/,$(COMMANDS)) + #include platform specific makefile -include Makefile.$(GOOS) -BINARIES=$(addprefix bin/,$(COMMANDS)) - # Flags passed to `go test` -TESTFLAGS ?= -v $(TESTFLAGS_RACE) +TESTFLAGS ?= $(TESTFLAGS_RACE) $(EXTRA_TESTFLAGS) TESTFLAGS_PARALLEL ?= 8 -.PHONY: clean all AUTHORS build binaries test integration generate protos checkprotos coverage ci check help install uninstall vendor release mandir install-man +# Use this to replace `go test` with, for instance, `gotestsum` +GOTEST ?= $(GO) test + +OUTPUTDIR = $(join $(ROOTDIR), _output) +CRIDIR=$(OUTPUTDIR)/cri + +.PHONY: clean all AUTHORS build binaries test integration generate protos checkprotos coverage ci check help install uninstall vendor release mandir install-man genman install-cri-deps cri-release cri-cni-release cri-integration install-deps bin/cri-integration.test .DEFAULT: default all: binaries check: proto-fmt ## run all linters @echo "$(WHALE) $@" - gometalinter --config .gometalinter.json ./... + GOGC=75 golangci-lint run ci: check binaries checkprotos coverage coverage-integration ## to be used by the CI @@ -117,7 +146,7 @@ generate: protos @echo "$(WHALE) $@" - @PATH="${ROOTDIR}/bin:${PATH}" go generate -x ${PACKAGES} + @PATH="${ROOTDIR}/bin:${PATH}" $(GO) generate -x ${PACKAGES} protos: bin/protoc-gen-gogoctrd ## generate protobuf @echo "$(WHALE) $@" @@ -144,42 +173,56 @@ build: ## build the go packages @echo "$(WHALE) $@" - @go build ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES} + @$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES} test: ## run tests, except integration tests and tests that require root @echo "$(WHALE) $@" - @go test ${TESTFLAGS} $(filter-out ${INTEGRATION_PACKAGE},${PACKAGES}) + @$(GOTEST) ${TESTFLAGS} ${PACKAGES} root-test: ## run tests, except integration tests @echo "$(WHALE) $@" - @go test ${TESTFLAGS} $(filter-out ${INTEGRATION_PACKAGE},${TEST_REQUIRES_ROOT_PACKAGES}) -test.root + @$(GOTEST) ${TESTFLAGS} ${TEST_REQUIRES_ROOT_PACKAGES} -test.root integration: ## run integration tests @echo "$(WHALE) $@" - @go test ${TESTFLAGS} -test.root -parallel ${TESTFLAGS_PARALLEL} + @cd "${ROOTDIR}/integration/client" && $(GO) mod download && $(GOTEST) -v ${TESTFLAGS} -test.root -parallel ${TESTFLAGS_PARALLEL} . + +# TODO integrate cri integration bucket with coverage +bin/cri-integration.test: + @echo "$(WHALE) $@" + @$(GO) test -c ./integration -o bin/cri-integration.test + +cri-integration: binaries bin/cri-integration.test ## run cri integration tests + @echo "$(WHALE) $@" + @./script/test/cri-integration.sh + @rm -rf bin/cri-integration.test benchmark: ## run benchmarks tests @echo "$(WHALE) $@" - @go test ${TESTFLAGS} -bench . -run Benchmark -test.root + @$(GO) test ${TESTFLAGS} -bench . -run Benchmark -test.root FORCE: +define BUILD_BINARY +@echo "$(WHALE) $@" +@$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_LDFLAGS} ${GO_TAGS} ./$< +endef + # Build a binary from a cmd. bin/%: cmd/% FORCE - @echo "$(WHALE) $@${BINARY_SUFFIX}" - @go build ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@${BINARY_SUFFIX} ${GO_LDFLAGS} ${GO_TAGS} ./$< + $(call BUILD_BINARY) bin/containerd-shim: cmd/containerd-shim FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 @echo "$(WHALE) bin/containerd-shim" - @CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim + @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 @echo "$(WHALE) bin/containerd-shim-runc-v1" - @CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1 + @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1 -bin/containerd-shim-runhcs-v1: cmd/containerd-shim-runhcs-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 - @echo "$(WHALE) bin/containerd-shim-runhcs-v1${BINARY_SUFFIX}" - @CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runhcs-v1${BINARY_SUFFIX} ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runhcs-v1 +bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 + @echo "$(WHALE) bin/containerd-shim-runc-v2" + @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v2 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 binaries: $(BINARIES) ## build binaries @echo "$(WHALE) $@" @@ -190,8 +233,19 @@ mandir: @mkdir -p man +# Kept for backwards compatibility +genman: man/containerd.8 man/ctr.8 + +man/containerd.8: FORCE + @echo "$(WHALE) $@" + $(GO) run cmd/gen-manpages/main.go $(@F) $(@D) + +man/ctr.8: FORCE + @echo "$(WHALE) $@" + $(GO) run cmd/gen-manpages/main.go $(@F) $(@D) + man/%: docs/man/%.md FORCE - @echo "$(WHALE) $<" + @echo "$(WHALE) $@" go-md2man -in "$<" -out "$@" define installmanpage @@ -203,16 +257,91 @@ @echo "$(WHALE) $@" $(foreach manpage,$(addprefix man/,$(MANPAGES)), $(call installmanpage,$(manpage),$(subst .,,$(suffix $(manpage))),$(notdir $(manpage)))) -release: $(BINARIES) +releases/$(RELEASE).tar.gz: $(BINARIES) @echo "$(WHALE) $@" @rm -rf releases/$(RELEASE) releases/$(RELEASE).tar.gz @install -d releases/$(RELEASE)/bin @install $(BINARIES) releases/$(RELEASE)/bin - @cd releases/$(RELEASE) && tar -czf ../$(RELEASE).tar.gz * + @tar -czf releases/$(RELEASE).tar.gz -C releases/$(RELEASE) bin + @rm -rf releases/$(RELEASE) + +release: releases/$(RELEASE).tar.gz + @echo "$(WHALE) $@" + @cd releases && sha256sum $(RELEASE).tar.gz >$(RELEASE).tar.gz.sha256sum + +# install of cri deps into release output directory +ifeq ($(GOOS),windows) +install-cri-deps: $(BINARIES) + mkdir -p $(CRIDIR) + DESTDIR=$(CRIDIR) script/setup/install-cni-windows + cp bin/* $(CRIDIR) +else +install-cri-deps: $(BINARIES) + @rm -rf ${CRIDIR} + @install -d ${CRIDIR}/usr/local/bin + @install -D -m 755 bin/* ${CRIDIR}/usr/local/bin + @install -d ${CRIDIR}/opt/containerd/cluster + @cp -r contrib/gce ${CRIDIR}/opt/containerd/cluster/ + @install -d ${CRIDIR}/etc/systemd/system + @install -m 644 containerd.service ${CRIDIR}/etc/systemd/system + echo "CONTAINERD_VERSION: '$(VERSION:v%=%)'" | tee ${CRIDIR}/opt/containerd/cluster/version + + DESTDIR=$(CRIDIR) script/setup/install-runc + DESTDIR=$(CRIDIR) script/setup/install-cni + DESTDIR=$(CRIDIR) script/setup/install-critools + DESTDIR=$(CRIDIR) script/setup/install-imgcrypt + + @install -d $(CRIDIR)/bin + @install $(BINARIES) $(CRIDIR)/bin +endif + +ifeq ($(GOOS),windows) +releases/$(CRIRELEASE).tar.gz: install-cri-deps + @echo "$(WHALE) $@" + @cd $(CRIDIR) && tar -czf ../../releases/$(CRIRELEASE).tar.gz * + +releases/$(CRICNIRELEASE).tar.gz: install-cri-deps + @echo "$(WHALE) $@" + @cd $(CRIDIR) && tar -czf ../../releases/$(CRICNIRELEASE).tar.gz * +else +releases/$(CRIRELEASE).tar.gz: install-cri-deps + @echo "$(WHALE) $@" + @tar -czf releases/$(CRIRELEASE).tar.gz -C $(CRIDIR) etc/crictl.yaml etc/systemd usr opt/containerd + +releases/$(CRICNIRELEASE).tar.gz: install-cri-deps + @echo "$(WHALE) $@" + @tar -czf releases/$(CRICNIRELEASE).tar.gz -C $(CRIDIR) etc usr opt +endif + +cri-release: releases/$(CRIRELEASE).tar.gz + @echo "$(WHALE) $@" + @cd releases && sha256sum $(CRIRELEASE).tar.gz >$(CRIRELEASE).tar.gz.sha256sum && ln -sf $(CRIRELEASE).tar.gz cri-containerd.tar.gz + +cri-cni-release: releases/$(CRICNIRELEASE).tar.gz + @echo "$(WHALE) $@" + @cd releases && sha256sum $(CRICNIRELEASE).tar.gz >$(CRICNIRELEASE).tar.gz.sha256sum && ln -sf $(CRICNIRELEASE).tar.gz cri-cni-containerd.tar.gz clean: ## clean up binaries @echo "$(WHALE) $@" @rm -f $(BINARIES) + @rm -f releases/*.tar.gz* + @rm -rf $(OUTPUTDIR) + @rm -rf bin/cri-integration.test + +clean-test: ## clean up debris from previously failed tests + @echo "$(WHALE) $@" + $(eval containers=$(shell find /run/containerd/runc -mindepth 2 -maxdepth 3 -type d -exec basename {} \;)) + $(shell pidof containerd containerd-shim runc | xargs -r -n 1 kill -9) + @( for container in $(containers); do \ + grep $$container /proc/self/mountinfo | while read -r mountpoint; do \ + umount $$(echo $$mountpoint | awk '{print $$5}'); \ + done; \ + find /sys/fs/cgroup -name $$container -print0 | xargs -r -0 rmdir; \ + done ) + @rm -rf /run/containerd/runc/* + @rm -rf /run/containerd/fifo/* + @rm -rf /run/containerd-test/* + @rm -rf bin/cri-integration.test install: ## install binaries @echo "$(WHALE) $@ $(BINARIES)" @@ -223,13 +352,25 @@ @echo "$(WHALE) $@" @rm -f $(addprefix $(DESTDIR)/bin/,$(notdir $(BINARIES))) +ifeq ($(GOOS),windows) +install-deps: + # TODO: need a script for hcshim something like containerd/cri/hack/install/windows/install-hcsshim.sh + script/setup/install-critools + script/setup/install-cni-windows +else +install-deps: ## install cri dependencies + script/setup/install-seccomp + script/setup/install-runc + script/setup/install-critools + script/setup/install-cni +endif coverage: ## generate coverprofiles from the unit tests, except tests that require root @echo "$(WHALE) $@" @rm -f coverage.txt - @go test -i ${TESTFLAGS} $(filter-out ${INTEGRATION_PACKAGE},${PACKAGES}) 2> /dev/null - @( for pkg in $(filter-out ${INTEGRATION_PACKAGE},${PACKAGES}); do \ - go test ${TESTFLAGS} \ + @$(GO) test -i ${TESTFLAGS} ${PACKAGES} 2> /dev/null + @( for pkg in ${PACKAGES}; do \ + $(GO) test ${TESTFLAGS} \ -cover \ -coverprofile=profile.out \ -covermode=atomic $$pkg || exit; \ @@ -241,9 +382,9 @@ root-coverage: ## generate coverage profiles for unit tests that require root @echo "$(WHALE) $@" - @go test -i ${TESTFLAGS} $(filter-out ${INTEGRATION_PACKAGE},${TEST_REQUIRES_ROOT_PACKAGES}) 2> /dev/null - @( for pkg in $(filter-out ${INTEGRATION_PACKAGE},${TEST_REQUIRES_ROOT_PACKAGES}); do \ - go test ${TESTFLAGS} \ + @$(GO) test -i ${TESTFLAGS} ${TEST_REQUIRES_ROOT_PACKAGES} 2> /dev/null + @( for pkg in ${TEST_REQUIRES_ROOT_PACKAGES}; do \ + $(GO) test ${TESTFLAGS} \ -cover \ -coverprofile=profile.out \ -covermode=atomic $$pkg -test.root || exit; \ @@ -253,9 +394,10 @@ fi; \ done ) -vendor: +vendor: ## vendor @echo "$(WHALE) $@" - @vndr + @$(GO) mod tidy + @$(GO) mod vendor help: ## this help @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort diff -Nru containerd-1.2.6/Makefile.linux containerd-1.5.9/Makefile.linux --- containerd-1.2.6/Makefile.linux 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/Makefile.linux 2022-01-05 17:30:58.000000000 +0000 @@ -14,11 +14,15 @@ #linux specific settings -COMMANDS += containerd-shim containerd-shim-runc-v1 +WHALE="+" +ONI="-" +COMMANDS += containerd-shim containerd-shim-runc-v1 containerd-shim-runc-v2 # check GOOS for cross compile builds ifeq ($(GOOS),linux) + ifneq ($(GOARCH),$(filter $(GOARCH),mips mipsle mips64 mips64le ppc64 riscv64)) GO_GCFLAGS += -buildmode=pie + endif endif # amd64 supports go test -race diff -Nru containerd-1.2.6/Makefile.windows containerd-1.5.9/Makefile.windows --- containerd-1.2.6/Makefile.windows 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/Makefile.windows 2022-01-05 17:30:58.000000000 +0000 @@ -16,18 +16,13 @@ #Windows specific settings. WHALE = "+" ONI = "-" -COMMANDS += containerd-shim-runhcs-v1 - -BINARY_SUFFIX=".exe" # amd64 supports go test -race ifeq ($(GOARCH),amd64) TESTFLAGS_RACE= -race endif -# add support for building the Windows v2 runtime -# based on the containerd-shim-runhcs-v1 shim rather -# than the existing runtime on hcsshim -ifeq (${BUILD_WINDOWS_V2},1) - BUILDTAGS += windows_v2 -endif +BINARIES:=$(addsuffix .exe,$(BINARIES)) + +bin/%.exe: cmd/% FORCE + $(BUILD_BINARY) diff -Nru containerd-1.2.6/metadata/adaptors.go containerd-1.5.9/metadata/adaptors.go --- containerd-1.2.6/metadata/adaptors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/adaptors.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,6 +24,7 @@ "github.com/containerd/containerd/filters" "github.com/containerd/containerd/images" "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/snapshots" ) func adaptImage(o interface{}) filters.Adaptor { @@ -51,6 +52,8 @@ return checkMap(fieldpath[1:], obj.Labels) // TODO(stevvooe): Greater/Less than filters would be awesome for // size. Let's do it! + case "annotations": + return checkMap(fieldpath[1:], obj.Target.Annotations) } return "", false @@ -87,50 +90,59 @@ }) } -func adaptContentInfo(info content.Info) filters.Adaptor { +func adaptContentStatus(status content.Status) filters.Adaptor { return filters.AdapterFunc(func(fieldpath []string) (string, bool) { if len(fieldpath) == 0 { return "", false } - switch fieldpath[0] { - case "digest": - return info.Digest.String(), true - case "size": - // TODO: support size based filtering - case "labels": - return checkMap(fieldpath[1:], info.Labels) + case "ref": + return status.Ref, true } return "", false }) } -func adaptContentStatus(status content.Status) filters.Adaptor { +func adaptLease(lease leases.Lease) filters.Adaptor { return filters.AdapterFunc(func(fieldpath []string) (string, bool) { if len(fieldpath) == 0 { return "", false } + switch fieldpath[0] { - case "ref": - return status.Ref, true + case "id": + return lease.ID, len(lease.ID) > 0 + case "labels": + return checkMap(fieldpath[1:], lease.Labels) } return "", false }) } -func adaptLease(lease leases.Lease) filters.Adaptor { +func adaptSnapshot(info snapshots.Info) filters.Adaptor { return filters.AdapterFunc(func(fieldpath []string) (string, bool) { if len(fieldpath) == 0 { return "", false } switch fieldpath[0] { - case "id": - return lease.ID, len(lease.ID) > 0 + case "kind": + switch info.Kind { + case snapshots.KindActive: + return "active", true + case snapshots.KindView: + return "view", true + case snapshots.KindCommitted: + return "committed", true + } + case "name": + return info.Name, true + case "parent": + return info.Parent, true case "labels": - return checkMap(fieldpath[1:], lease.Labels) + return checkMap(fieldpath[1:], info.Labels) } return "", false diff -Nru containerd-1.2.6/metadata/boltutil/helpers.go containerd-1.5.9/metadata/boltutil/helpers.go --- containerd-1.2.6/metadata/boltutil/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/boltutil/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,20 +19,34 @@ import ( "time" + "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/types" "github.com/pkg/errors" bolt "go.etcd.io/bbolt" ) var ( - bucketKeyLabels = []byte("labels") - bucketKeyCreatedAt = []byte("createdat") - bucketKeyUpdatedAt = []byte("updatedat") + bucketKeyAnnotations = []byte("annotations") + bucketKeyLabels = []byte("labels") + bucketKeyCreatedAt = []byte("createdat") + bucketKeyUpdatedAt = []byte("updatedat") + bucketKeyExtensions = []byte("extensions") ) // ReadLabels reads the labels key from the bucket // Uses the key "labels" func ReadLabels(bkt *bolt.Bucket) (map[string]string, error) { - lbkt := bkt.Bucket(bucketKeyLabels) + return readMap(bkt, bucketKeyLabels) +} + +// ReadAnnotations reads the OCI Descriptor Annotations key from the bucket +// Uses the key "annotations" +func ReadAnnotations(bkt *bolt.Bucket) (map[string]string, error) { + return readMap(bkt, bucketKeyAnnotations) +} + +func readMap(bkt *bolt.Bucket, bucketName []byte) (map[string]string, error) { + lbkt := bkt.Bucket(bucketName) if lbkt == nil { return nil, nil } @@ -53,9 +67,18 @@ // bucket. Typically, this removes zero-value entries. // Uses the key "labels" func WriteLabels(bkt *bolt.Bucket, labels map[string]string) error { + return writeMap(bkt, bucketKeyLabels, labels) +} + +// WriteAnnotations writes the OCI Descriptor Annotations +func WriteAnnotations(bkt *bolt.Bucket, labels map[string]string) error { + return writeMap(bkt, bucketKeyAnnotations, labels) +} + +func writeMap(bkt *bolt.Bucket, bucketName []byte, labels map[string]string) error { // Remove existing labels to keep from merging - if lbkt := bkt.Bucket(bucketKeyLabels); lbkt != nil { - if err := bkt.DeleteBucket(bucketKeyLabels); err != nil { + if lbkt := bkt.Bucket(bucketName); lbkt != nil { + if err := bkt.DeleteBucket(bucketName); err != nil { return err } } @@ -64,7 +87,7 @@ return nil } - lbkt, err := bkt.CreateBucket(bucketKeyLabels) + lbkt, err := bkt.CreateBucket(bucketName) if err != nil { return err } @@ -125,3 +148,88 @@ return nil } + +// WriteExtensions will write a KV map to the given bucket, +// where `K` is a string key and `V` is a protobuf's Any type that represents a generic extension. +func WriteExtensions(bkt *bolt.Bucket, extensions map[string]types.Any) error { + if len(extensions) == 0 { + return nil + } + + ebkt, err := bkt.CreateBucketIfNotExists(bucketKeyExtensions) + if err != nil { + return err + } + + for name, ext := range extensions { + p, err := proto.Marshal(&ext) + if err != nil { + return err + } + + if err := ebkt.Put([]byte(name), p); err != nil { + return err + } + } + + return nil +} + +// ReadExtensions will read back a map of extensions from the given bucket, previously written by WriteExtensions +func ReadExtensions(bkt *bolt.Bucket) (map[string]types.Any, error) { + var ( + extensions = make(map[string]types.Any) + ebkt = bkt.Bucket(bucketKeyExtensions) + ) + + if ebkt == nil { + return extensions, nil + } + + if err := ebkt.ForEach(func(k, v []byte) error { + var t types.Any + if err := proto.Unmarshal(v, &t); err != nil { + return err + } + + extensions[string(k)] = t + return nil + }); err != nil { + return nil, err + } + + return extensions, nil +} + +// WriteAny write a protobuf's Any type to the bucket +func WriteAny(bkt *bolt.Bucket, name []byte, any *types.Any) error { + if any == nil { + return nil + } + + data, err := proto.Marshal(any) + if err != nil { + return err + } + + if err := bkt.Put(name, data); err != nil { + return err + } + + return nil +} + +// ReadAny reads back protobuf's Any type from the bucket +func ReadAny(bkt *bolt.Bucket, name []byte) (*types.Any, error) { + bytes := bkt.Get(name) + if bytes == nil { + return nil, nil + } + + out := types.Any{} + if err := proto.Unmarshal(bytes, &out); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal any") + } + + return &out, nil +} diff -Nru containerd-1.2.6/metadata/buckets.go containerd-1.5.9/metadata/buckets.go --- containerd-1.2.6/metadata/buckets.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/buckets.go 2022-01-05 17:30:58.000000000 +0000 @@ -14,13 +14,11 @@ limitations under the License. */ -package metadata - -import ( - digest "github.com/opencontainers/go-digest" - bolt "go.etcd.io/bbolt" -) - +// Package metadata stores all labels and object specific metadata by namespace. +// This package also contains the main garbage collection logic for cleaning up +// resources consistently and atomically. Resources used by backends will be +// tracked in the metadata store to be exposed to consumers of this package. +// // The layout where a "/" delineates a bucket is described in the following // section. Please try to follow this as closely as possible when adding // functionality. We can bolster this with helpers and more structure if that @@ -43,6 +41,84 @@ // // key: object-specific key identifying the storage bucket for the objects // contents. +// +// Below is the current database schema. This should be updated each time +// the structure is changed in addition to adding a migration and incrementing +// the database version. Note that `╘â•â•*...*` refers to maps with arbitrary +// keys. +// ├──version : - Latest version, see migrations +// └──v1 - Schema version bucket +// ╘â•â•*namespace* +// ├──labels +// │  ╘â•â•*key* : - Label value +// ├──image +// │  ╘â•â•*image name* +// │   ├──createdat : - Created at +// │   ├──updatedat : - Updated at +// │   ├──target +// │   │  ├──digest : - Descriptor digest +// │   │  ├──mediatype : - Descriptor media type +// │   │  └──size : - Descriptor size +// │   └──labels +// │   ╘â•â•*key* : - Label value +// ├──containers +// │  ╘â•â•*container id* +// │   ├──createdat : - Created at +// │   ├──updatedat : - Updated at +// │   ├──spec : - Proto marshaled spec +// │   ├──image : - Image name +// │   ├──snapshotter : - Snapshotter name +// │   ├──snapshotKey : - Snapshot key +// │   ├──runtime +// │   │  ├──name : - Runtime name +// │   │  ├──extensions +// │   │  │  ╘â•â•*name* : - Proto marshaled extension +// │   │  └──options : - Proto marshaled options +// │   └──labels +// │   ╘â•â•*key* : - Label value +// ├──snapshots +// │  ╘â•â•*snapshotter* +// │   ╘â•â•*snapshot key* +// │    ├──name : - Snapshot name in backend +// │   ├──createdat : - Created at +// │   ├──updatedat : - Updated at +// │    ├──parent : - Parent snapshot name +// │   ├──children +// │   │  ╘â•â•*snapshot key* : - Child snapshot reference +// │   └──labels +// │   ╘â•â•*key* : - Label value +// ├──content +// │  ├──blob +// │  │ ╘â•â•*blob digest* +// │  │ ├──createdat : - Created at +// │  │ ├──updatedat : - Updated at +// │  │   ├──size : - Blob size +// │  │ └──labels +// │  │ ╘â•â•*key* : - Label value +// │  └──ingests +// │   ╘â•â•*ingest reference* +// │    ├──ref : - Ingest reference in backend +// │   ├──expireat : - Time to expire ingest +// │   └──expected : - Expected commit digest +// └──leases +// ╘â•â•*lease id* +//   ├──createdat : - Created at +// ├──labels +// │ ╘â•â•*key* : - Label value +//   ├──snapshots +// │  ╘â•â•*snapshotter* +// │   ╘â•â•*snapshot key* : - Snapshot reference +//   ├──content +// │  ╘â•â•*blob digest* : - Content blob reference +// └──ingests +//   ╘â•â•*ingest reference* : - Content ingest reference +package metadata + +import ( + digest "github.com/opencontainers/go-digest" + bolt "go.etcd.io/bbolt" +) + var ( bucketKeyVersion = []byte(schemaVersion) bucketKeyDBVersion = []byte("version") // stores the version of the schema diff -Nru containerd-1.2.6/metadata/containers.go containerd-1.5.9/metadata/containers.go --- containerd-1.2.6/metadata/containers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/containers.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,7 @@ import ( "context" "strings" + "sync/atomic" "time" "github.com/containerd/containerd/containers" @@ -35,13 +36,13 @@ ) type containerStore struct { - tx *bolt.Tx + db *DB } // NewContainerStore returns a Store backed by an underlying bolt DB -func NewContainerStore(tx *bolt.Tx) containers.Store { +func NewContainerStore(db *DB) containers.Store { return &containerStore{ - tx: tx, + db: db, } } @@ -51,14 +52,21 @@ return containers.Container{}, err } - bkt := getContainerBucket(s.tx, namespace, id) - if bkt == nil { - return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace) - } - container := containers.Container{ID: id} - if err := readContainer(&container, bkt); err != nil { - return containers.Container{}, errors.Wrapf(err, "failed to read container %q", id) + + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getContainerBucket(tx, namespace, id) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace) + } + + if err := readContainer(&container, bkt); err != nil { + return errors.Wrapf(err, "failed to read container %q", id) + } + + return nil + }); err != nil { + return containers.Container{}, err } return container, nil @@ -72,30 +80,33 @@ filter, err := filters.ParseAll(fs...) if err != nil { - return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error()) - } - - bkt := getContainersBucket(s.tx, namespace) - if bkt == nil { - return nil, nil // empty store + return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error()) } var m []containers.Container - if err := bkt.ForEach(func(k, v []byte) error { - cbkt := bkt.Bucket(k) - if cbkt == nil { - return nil - } - container := containers.Container{ID: string(k)} - if err := readContainer(&container, cbkt); err != nil { - return errors.Wrapf(err, "failed to read container %q", string(k)) + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getContainersBucket(tx, namespace) + if bkt == nil { + return nil // empty store } - if filter.Match(adaptContainer(container)) { - m = append(m, container) - } - return nil + return bkt.ForEach(func(k, v []byte) error { + cbkt := bkt.Bucket(k) + if cbkt == nil { + return nil + } + container := containers.Container{ID: string(k)} + + if err := readContainer(&container, cbkt); err != nil { + return errors.Wrapf(err, "failed to read container %q", string(k)) + } + + if filter.Match(adaptContainer(container)) { + m = append(m, container) + } + return nil + }) }); err != nil { return nil, err } @@ -113,23 +124,29 @@ return containers.Container{}, errors.Wrap(err, "create container failed validation") } - bkt, err := createContainersBucket(s.tx, namespace) - if err != nil { - return containers.Container{}, err - } + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt, err := createContainersBucket(tx, namespace) + if err != nil { + return err + } - cbkt, err := bkt.CreateBucket([]byte(container.ID)) - if err != nil { - if err == bolt.ErrBucketExists { - err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID) + cbkt, err := bkt.CreateBucket([]byte(container.ID)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID) + } + return err + } + + container.CreatedAt = time.Now().UTC() + container.UpdatedAt = container.CreatedAt + if err := writeContainer(cbkt, &container); err != nil { + return errors.Wrapf(err, "failed to write container %q", container.ID) } - return containers.Container{}, err - } - container.CreatedAt = time.Now().UTC() - container.UpdatedAt = container.CreatedAt - if err := writeContainer(cbkt, &container); err != nil { - return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID) + return nil + }); err != nil { + return containers.Container{}, err } return container, nil @@ -145,85 +162,91 @@ return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id") } - bkt := getContainersBucket(s.tx, namespace) - if bkt == nil { - return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace) - } - - cbkt := bkt.Bucket([]byte(container.ID)) - if cbkt == nil { - return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID) - } - var updated containers.Container - if err := readContainer(&updated, cbkt); err != nil { - return updated, errors.Wrapf(err, "failed to read container %q", container.ID) - } - createdat := updated.CreatedAt - updated.ID = container.ID - - if len(fieldpaths) == 0 { - // only allow updates to these field on full replace. - fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"} + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getContainersBucket(tx, namespace) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace) + } - // Fields that are immutable must cause an error when no field paths - // are provided. This allows these fields to become mutable in the - // future. - if updated.Snapshotter != container.Snapshotter { - return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable") + cbkt := bkt.Bucket([]byte(container.ID)) + if cbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID) } - if updated.Runtime.Name != container.Runtime.Name { - return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable") + if err := readContainer(&updated, cbkt); err != nil { + return errors.Wrapf(err, "failed to read container %q", container.ID) } - } + createdat := updated.CreatedAt + updated.ID = container.ID + + if len(fieldpaths) == 0 { + // only allow updates to these field on full replace. + fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"} - // apply the field mask. If you update this code, you better follow the - // field mask rules in field_mask.proto. If you don't know what this - // is, do not update this code. - for _, path := range fieldpaths { - if strings.HasPrefix(path, "labels.") { - if updated.Labels == nil { - updated.Labels = map[string]string{} + // Fields that are immutable must cause an error when no field paths + // are provided. This allows these fields to become mutable in the + // future. + if updated.Snapshotter != container.Snapshotter { + return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable") } - key := strings.TrimPrefix(path, "labels.") - updated.Labels[key] = container.Labels[key] - continue - } - if strings.HasPrefix(path, "extensions.") { - if updated.Extensions == nil { - updated.Extensions = map[string]types.Any{} + if updated.Runtime.Name != container.Runtime.Name { + return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable") } - key := strings.TrimPrefix(path, "extensions.") - updated.Extensions[key] = container.Extensions[key] - continue } - switch path { - case "labels": - updated.Labels = container.Labels - case "spec": - updated.Spec = container.Spec - case "extensions": - updated.Extensions = container.Extensions - case "image": - updated.Image = container.Image - case "snapshotkey": - updated.SnapshotKey = container.SnapshotKey - default: - return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID) + // apply the field mask. If you update this code, you better follow the + // field mask rules in field_mask.proto. If you don't know what this + // is, do not update this code. + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + key := strings.TrimPrefix(path, "labels.") + updated.Labels[key] = container.Labels[key] + continue + } + + if strings.HasPrefix(path, "extensions.") { + if updated.Extensions == nil { + updated.Extensions = map[string]types.Any{} + } + key := strings.TrimPrefix(path, "extensions.") + updated.Extensions[key] = container.Extensions[key] + continue + } + + switch path { + case "labels": + updated.Labels = container.Labels + case "spec": + updated.Spec = container.Spec + case "extensions": + updated.Extensions = container.Extensions + case "image": + updated.Image = container.Image + case "snapshotkey": + updated.SnapshotKey = container.SnapshotKey + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID) + } } - } - if err := validateContainer(&updated); err != nil { - return containers.Container{}, errors.Wrap(err, "update failed validation") - } + if err := validateContainer(&updated); err != nil { + return errors.Wrap(err, "update failed validation") + } + + updated.CreatedAt = createdat + updated.UpdatedAt = time.Now().UTC() + if err := writeContainer(cbkt, &updated); err != nil { + return errors.Wrapf(err, "failed to write container %q", container.ID) + } - updated.CreatedAt = createdat - updated.UpdatedAt = time.Now().UTC() - if err := writeContainer(cbkt, &updated); err != nil { - return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID) + return nil + }); err != nil { + return containers.Container{}, err } return updated, nil @@ -235,15 +258,23 @@ return err } - bkt := getContainersBucket(s.tx, namespace) - if bkt == nil { - return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace) - } + return update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getContainersBucket(tx, namespace) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace) + } - if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound { - return errors.Wrapf(errdefs.ErrNotFound, "container %v", id) - } - return err + if err := bkt.DeleteBucket([]byte(id)); err != nil { + if err == bolt.ErrBucketNotFound { + err = errors.Wrapf(errdefs.ErrNotFound, "container %v", id) + } + return err + } + + atomic.AddUint32(&s.db.dirty, 1) + + return nil + }) } func validateContainer(container *containers.Container) error { @@ -259,7 +290,7 @@ // image has no validation for k, v := range container.Labels { - if err := labels.Validate(k, v); err == nil { + if err := labels.Validate(k, v); err != nil { return errors.Wrapf(err, "containers.Labels") } } @@ -305,16 +336,11 @@ container.Runtime.Name = string(n) } - obkt := rbkt.Get(bucketKeyOptions) - if obkt == nil { - return nil - } - - var any types.Any - if err := proto.Unmarshal(obkt, &any); err != nil { + any, err := boltutil.ReadAny(rbkt, bucketKeyOptions) + if err != nil { return err } - container.Runtime.Options = &any + container.Runtime.Options = any case string(bucketKeySpec): var any types.Any if err := proto.Unmarshal(v, &any); err != nil { @@ -326,22 +352,8 @@ case string(bucketKeySnapshotter): container.Snapshotter = string(v) case string(bucketKeyExtensions): - ebkt := bkt.Bucket(bucketKeyExtensions) - if ebkt == nil { - return nil - } - - extensions := make(map[string]types.Any) - if err := ebkt.ForEach(func(k, v []byte) error { - var a types.Any - if err := proto.Unmarshal(v, &a); err != nil { - return err - } - - extensions[string(k)] = a - return nil - }); err != nil { - + extensions, err := boltutil.ReadExtensions(bkt) + if err != nil { return err } @@ -357,15 +369,8 @@ return err } - if container.Spec != nil { - spec, err := container.Spec.Marshal() - if err != nil { - return err - } - - if err := bkt.Put(bucketKeySpec, spec); err != nil { - return err - } + if err := boltutil.WriteAny(bkt, bucketKeySpec, container.Spec); err != nil { + return err } for _, v := range [][2][]byte{ @@ -393,33 +398,12 @@ return err } - if len(container.Extensions) > 0 { - ebkt, err := bkt.CreateBucketIfNotExists(bucketKeyExtensions) - if err != nil { - return err - } - - for name, ext := range container.Extensions { - p, err := proto.Marshal(&ext) - if err != nil { - return err - } - - if err := ebkt.Put([]byte(name), p); err != nil { - return err - } - } + if err := boltutil.WriteExtensions(bkt, container.Extensions); err != nil { + return err } - if container.Runtime.Options != nil { - data, err := proto.Marshal(container.Runtime.Options) - if err != nil { - return err - } - - if err := rbkt.Put(bucketKeyOptions, data); err != nil { - return err - } + if err := boltutil.WriteAny(rbkt, bucketKeyOptions, container.Runtime.Options); err != nil { + return err } return boltutil.WriteLabels(bkt, container.Labels) diff -Nru containerd-1.2.6/metadata/containers_test.go containerd-1.5.9/metadata/containers_test.go --- containerd-1.2.6/metadata/containers_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/containers_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -30,6 +30,7 @@ "github.com/containerd/containerd/containers" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" + "github.com/containerd/containerd/log/logtest" "github.com/containerd/containerd/namespaces" "github.com/containerd/typeurl" "github.com/gogo/protobuf/types" @@ -46,6 +47,8 @@ ctx, db, cancel := testEnv(t) defer cancel() + store := NewContainerStore(NewDB(db, nil, nil)) + spec := &specs.Spec{} encoded, err := typeurl.MarshalAny(spec) if err != nil { @@ -72,9 +75,8 @@ } if err := db.Update(func(tx *bolt.Tx) error { - store := NewContainerStore(tx) now := time.Now() - result, err := store.Create(ctx, *testset[id]) + result, err := store.Create(WithTransactionContext(ctx, tx), *testset[id]) if err != nil { return err } @@ -137,46 +139,35 @@ testset = newtestset } - if err := db.View(func(tx *bolt.Tx) error { - store := NewContainerStore(tx) - results, err := store.List(ctx, testcase.filters...) - if err != nil { - t.Fatal(err) - } - - if len(results) == 0 { // all tests return a non-empty result set - t.Fatalf("not results returned") - } + results, err := store.List(ctx, testcase.filters...) + if err != nil { + t.Fatal(err) + } - if len(results) != len(testset) { - t.Fatalf("length of result does not match testset: %v != %v", len(results), len(testset)) - } + if len(results) == 0 { // all tests return a non-empty result set + t.Fatalf("not results returned") + } - for _, result := range results { - checkContainersEqual(t, &result, testset[result.ID], "list results did not match") - } + if len(results) != len(testset) { + t.Fatalf("length of result does not match testset: %v != %v", len(results), len(testset)) + } - return nil - }); err != nil { - t.Fatal(err) + for _, result := range results { + checkContainersEqual(t, &result, testset[result.ID], "list results did not match") } }) } // delete everything to test it for id := range testset { - if err := db.Update(func(tx *bolt.Tx) error { - store := NewContainerStore(tx) - return store.Delete(ctx, id) - }); err != nil { + if err := store.Delete(ctx, id); err != nil { t.Fatal(err) } // try it again, get NotFound - if err := db.Update(func(tx *bolt.Tx) error { - store := NewContainerStore(tx) - return store.Delete(ctx, id) - }); errors.Cause(err) != errdefs.ErrNotFound { + if err := store.Delete(ctx, id); err == nil { + t.Fatalf("expected error deleting non-existent container") + } else if !errdefs.IsNotFound(err) { t.Fatalf("unexpected error %v", err) } } @@ -187,6 +178,8 @@ ctx, db, cancel := testEnv(t) defer cancel() + store := NewContainerStore(NewDB(db, nil, nil)) + spec := &specs.Spec{} encoded, err := typeurl.MarshalAny(spec) if err != nil { @@ -640,79 +633,51 @@ } testcase.expected.ID = testcase.name - done := errors.New("test complete") - if err := db.Update(func(tx *bolt.Tx) error { - var ( - now = time.Now().UTC() - store = NewContainerStore(tx) - ) - - result, err := store.Create(ctx, testcase.original) - if errors.Cause(err) != testcase.createerr { - if testcase.createerr == nil { - t.Fatalf("unexpected error: %v", err) - } else { - t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.createerr) - } - } else if testcase.createerr != nil { - return done - } - - checkContainerTimestamps(t, &result, now, true) + now := time.Now().UTC() - // ensure that createdat is never tampered with - testcase.original.CreatedAt = result.CreatedAt - testcase.expected.CreatedAt = result.CreatedAt - testcase.original.UpdatedAt = result.UpdatedAt - testcase.expected.UpdatedAt = result.UpdatedAt - - checkContainersEqual(t, &result, &testcase.original, "unexpected result on container update") - return nil - }); err != nil { - if err == done { - return + result, err := store.Create(ctx, testcase.original) + if !errors.Is(err, testcase.createerr) { + if testcase.createerr == nil { + t.Fatalf("unexpected error: %v", err) + } else { + t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.createerr) } - t.Fatal(err) + } else if testcase.createerr != nil { + return } - if err := db.Update(func(tx *bolt.Tx) error { - now := time.Now() - store := NewContainerStore(tx) - result, err := store.Update(ctx, testcase.input, testcase.fieldpaths...) - if errors.Cause(err) != testcase.cause { - if testcase.cause == nil { - t.Fatalf("unexpected error: %v", err) - } else { - t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.cause) - } - } else if testcase.cause != nil { - return done - } + checkContainerTimestamps(t, &result, now, true) - checkContainerTimestamps(t, &result, now, false) - testcase.expected.UpdatedAt = result.UpdatedAt - checkContainersEqual(t, &result, &testcase.expected, "updated failed to get expected result") - return nil - }); err != nil { - if err == done { - return + // ensure that createdat is never tampered with + testcase.original.CreatedAt = result.CreatedAt + testcase.expected.CreatedAt = result.CreatedAt + testcase.original.UpdatedAt = result.UpdatedAt + testcase.expected.UpdatedAt = result.UpdatedAt + + checkContainersEqual(t, &result, &testcase.original, "unexpected result on container update") + + now = time.Now() + result, err = store.Update(ctx, testcase.input, testcase.fieldpaths...) + if !errors.Is(err, testcase.cause) { + if testcase.cause == nil { + t.Fatalf("unexpected error: %v", err) + } else { + t.Fatalf("cause of %v (cause: %v) != %v", err, errors.Cause(err), testcase.cause) } - t.Fatal(err) + } else if testcase.cause != nil { + return } - if err := db.View(func(tx *bolt.Tx) error { - store := NewContainerStore(tx) - result, err := store.Get(ctx, testcase.original.ID) - if err != nil { - t.Fatal(err) - } + checkContainerTimestamps(t, &result, now, false) + testcase.expected.UpdatedAt = result.UpdatedAt + checkContainersEqual(t, &result, &testcase.expected, "updated failed to get expected result") - checkContainersEqual(t, &result, &testcase.expected, "get after failed to get expected result") - return nil - }); err != nil { + result, err = store.Get(ctx, testcase.original.ID) + if err != nil { t.Fatal(err) } + checkContainersEqual(t, &result, &testcase.expected, "get after failed to get expected result") }) } } @@ -748,6 +713,7 @@ func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) { ctx, cancel := context.WithCancel(context.Background()) ctx = namespaces.WithNamespace(ctx, "testing") + ctx = logtest.WithT(ctx, t) dirname, err := ioutil.TempDir("", strings.Replace(t.Name(), "/", "_", -1)+"-") if err != nil { diff -Nru containerd-1.2.6/metadata/content.go containerd-1.5.9/metadata/content.go --- containerd-1.2.6/metadata/content.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/content.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "encoding/binary" "strings" "sync" + "sync/atomic" "time" "github.com/containerd/containerd/content" @@ -38,16 +39,31 @@ type contentStore struct { content.Store - db *DB - l sync.RWMutex + db *DB + shared bool + l sync.RWMutex } // newContentStore returns a namespaced content store using an existing // content store interface. -func newContentStore(db *DB, cs content.Store) *contentStore { +// policy defines the sharing behavior for content between namespaces. Both +// modes will result in shared storage in the backend for committed. Choose +// "shared" to prevent separate namespaces from having to pull the same content +// twice. Choose "isolated" if the content must not be shared between +// namespaces. +// +// If the policy is "shared", writes will try to resolve the "expected" digest +// against the backend, allowing imports of content from other namespaces. In +// "isolated" mode, the client must prove they have the content by providing +// the entire blob before the content can be added to another namespace. +// +// Since we have only two policies right now, it's simpler using bool to +// represent it internally. +func newContentStore(db *DB, shared bool, cs content.Store) *contentStore { return &contentStore{ - Store: cs, - db: db, + Store: cs, + db: db, + shared: shared, } } @@ -165,7 +181,7 @@ if err := readInfo(&info, bkt.Bucket(k)); err != nil { return err } - if filter.Match(adaptContentInfo(info)) { + if filter.Match(content.AdaptInfo(info)) { infos = append(infos, info) } return nil @@ -206,9 +222,8 @@ } // Mark content store as dirty for triggering garbage collection - cs.db.dirtyL.Lock() + atomic.AddUint32(&cs.db.dirty, 1) cs.db.dirtyCS = true - cs.db.dirtyL.Unlock() return nil }) @@ -383,13 +398,15 @@ return nil } - if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil { - // Ensure the expected size is the same, it is likely - // an error if the size is mismatched but the caller - // must resolve this on commit - if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size { - shared = true - wOpts.Desc.Size = st.Size + if cs.shared { + if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil { + // Ensure the expected size is the same, it is likely + // an error if the size is mismatched but the caller + // must resolve this on commit + if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size { + shared = true + wOpts.Desc.Size = st.Size + } } } } @@ -534,13 +551,13 @@ if desc.Size > 0 { ra, err := nw.provider.ReaderAt(ctx, nw.desc) if err != nil { + w.Close() return err } defer ra.Close() if err := content.CopyReaderAt(w, ra, desc.Size); err != nil { - nw.w.Close() - nw.w = nil + w.Close() return err } } @@ -550,6 +567,8 @@ } func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { + ctx = namespaces.WithNamespace(ctx, nw.namespace) + nw.l.RLock() defer nw.l.RUnlock() @@ -618,11 +637,11 @@ return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "%q failed size validation: %v != %v", nw.ref, status.Offset, size) } size = status.Offset - actual = nw.w.Digest() if err := nw.w.Commit(ctx, size, expected); err != nil && !errdefs.IsAlreadyExists(err) { return "", err } + actual = nw.w.Digest() } bkt, err := createBlobBucket(tx, nw.namespace, actual) @@ -689,7 +708,7 @@ func validateInfo(info *content.Info) error { for k, v := range info.Labels { - if err := labels.Validate(k, v); err == nil { + if err := labels.Validate(k, v); err != nil { return errors.Wrapf(err, "info.Labels") } } @@ -750,11 +769,7 @@ if err != nil { return err } - if err := bkt.Put(bucketKeyExpireAt, expireAt); err != nil { - return err - } - - return nil + return bkt.Put(bucketKeyExpireAt, expireAt) } func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, err error) { diff -Nru containerd-1.2.6/metadata/content_test.go containerd-1.5.9/metadata/content_test.go --- containerd-1.2.6/metadata/content_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/content_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -36,7 +36,7 @@ bolt "go.etcd.io/bbolt" ) -func createContentStore(ctx context.Context, root string) (context.Context, content.Store, func() error, error) { +func createContentStore(ctx context.Context, root string, opts ...DBOpt) (context.Context, content.Store, func() error, error) { // TODO: Use mocked or in-memory store cs, err := local.NewStore(root) if err != nil { @@ -60,13 +60,24 @@ } ctx = testsuite.SetContextWrapper(ctx, wrap) - return ctx, NewDB(db, cs, nil).ContentStore(), func() error { + return ctx, NewDB(db, cs, nil, opts...).ContentStore(), func() error { return db.Close() }, nil } +func createContentStoreWithPolicy(opts ...DBOpt) testsuite.StoreInitFn { + return func(ctx context.Context, root string) (context.Context, content.Store, func() error, error) { + return createContentStore(ctx, root, opts...) + } +} + func TestContent(t *testing.T) { - testsuite.ContentSuite(t, "metadata", createContentStore) + testsuite.ContentSuite(t, "metadata", createContentStoreWithPolicy()) + testsuite.ContentCrossNSSharedSuite(t, "metadata", createContentStoreWithPolicy()) + testsuite.ContentCrossNSIsolatedSuite( + t, "metadata", createContentStoreWithPolicy([]DBOpt{ + WithPolicyIsolated, + }...)) } func TestContentLeased(t *testing.T) { @@ -155,17 +166,13 @@ } func createLease(ctx context.Context, db *DB, name string) (context.Context, func() error, error) { - if err := db.Update(func(tx *bolt.Tx) error { - _, err := NewLeaseManager(tx).Create(ctx, leases.WithID(name)) - return err - }); err != nil { + lm := NewLeaseManager(db) + if _, err := lm.Create(ctx, leases.WithID(name)); err != nil { return nil, nil, err } return leases.WithLease(ctx, name), func() error { - return db.Update(func(tx *bolt.Tx) error { - return NewLeaseManager(tx).Delete(ctx, leases.Lease{ - ID: name, - }) + return lm.Delete(ctx, leases.Lease{ + ID: name, }) }, nil } diff -Nru containerd-1.2.6/metadata/db.go containerd-1.5.9/metadata/db.go --- containerd-1.2.6/metadata/db.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/db.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "encoding/binary" "strings" "sync" + "sync/atomic" "time" "github.com/containerd/containerd/content" @@ -46,6 +47,19 @@ dbVersion = 3 ) +// DBOpt configures how we set up the DB +type DBOpt func(*dbOptions) + +// WithPolicyIsolated isolates contents between namespaces +func WithPolicyIsolated(o *dbOptions) { + o.shared = false +} + +// dbOptions configure db options. +type dbOptions struct { + shared bool +} + // DB represents a metadata database backed by a bolt // database. The database is fully namespaced and stores // image, container, namespace, snapshot, and content data @@ -62,29 +76,44 @@ // sweep phases without preventing read transactions. wlock sync.RWMutex - // dirty flags and lock keeps track of datastores which have had deletions - // since the last garbage collection. These datastores will will be garbage - // collected during the next garbage collection. - dirtyL sync.Mutex + // dirty flag indicates that references have been removed which require + // a garbage collection to ensure the database is clean. This tracks + // the number of dirty operations. This should be updated and read + // atomically if outside of wlock.Lock. + dirty uint32 + + // dirtySS and dirtyCS flags keeps track of datastores which have had + // deletions since the last garbage collection. These datastores will + // be garbage collected during the next garbage collection. These + // should only be updated inside of a write transaction or wlock.Lock. dirtySS map[string]struct{} dirtyCS bool // mutationCallbacks are called after each mutation with the flag // set indicating whether any dirty flags are set mutationCallbacks []func(bool) + + dbopts dbOptions } // NewDB creates a new metadata database using the provided // bolt database, content store, and snapshotters. -func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter) *DB { +func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter, opts ...DBOpt) *DB { m := &DB{ db: db, ss: make(map[string]*snapshotter, len(ss)), dirtySS: map[string]struct{}{}, + dbopts: dbOptions{ + shared: true, + }, + } + + for _, opt := range opts { + opt(&m.dbopts) } // Initialize data stores - m.cs = newContentStore(m, cs) + m.cs = newContentStore(m, m.dbopts.shared, cs) for name, sn := range ss { m.ss[name] = newSnapshotter(m, name, sn) } @@ -140,7 +169,7 @@ } } - // Previous version fo database found + // Previous version of database found if schema != "v0" { updates := migrations[i:] @@ -215,12 +244,10 @@ defer m.wlock.RUnlock() err := m.db.Update(fn) if err == nil { - m.dirtyL.Lock() - dirty := m.dirtyCS || len(m.dirtySS) > 0 + dirty := atomic.LoadUint32(&m.dirty) > 0 for _, fn := range m.mutationCallbacks { fn(dirty) } - m.dirtyL.Unlock() } return err @@ -232,9 +259,9 @@ // The callback function is an argument for whether a deletion has occurred // since the last garbage collection. func (m *DB) RegisterMutationCallback(fn func(bool)) { - m.dirtyL.Lock() + m.wlock.Lock() m.mutationCallbacks = append(m.mutationCallbacks, fn) - m.dirtyL.Unlock() + m.wlock.Unlock() } // GCStats holds the duration for the different phases of the garbage collector @@ -260,8 +287,6 @@ return nil, err } - m.dirtyL.Lock() - if err := m.db.Update(func(tx *bolt.Tx) error { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -287,7 +312,6 @@ return nil }); err != nil { - m.dirtyL.Unlock() m.wlock.Unlock() return nil, err } @@ -295,6 +319,9 @@ var stats GCStats var wg sync.WaitGroup + // reset dirty, no need for atomic inside of wlock.Lock + m.dirty = 0 + if len(m.dirtySS) > 0 { var sl sync.Mutex stats.SnapshotD = map[string]time.Duration{} @@ -327,8 +354,6 @@ m.dirtyCS = false } - m.dirtyL.Unlock() - stats.MetaD = time.Since(t1) m.wlock.Unlock() diff -Nru containerd-1.2.6/metadata/db_test.go containerd-1.5.9/metadata/db_test.go --- containerd-1.2.6/metadata/db_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/db_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -36,6 +36,8 @@ "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/gc" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/log/logtest" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/native" @@ -46,9 +48,31 @@ bolt "go.etcd.io/bbolt" ) -func testDB(t *testing.T) (context.Context, *DB, func()) { +type testOptions struct { + extraSnapshots map[string]func(string) (snapshots.Snapshotter, error) +} + +type testOpt func(*testOptions) + +func withSnapshotter(name string, fn func(string) (snapshots.Snapshotter, error)) testOpt { + return func(to *testOptions) { + if to.extraSnapshots == nil { + to.extraSnapshots = map[string]func(string) (snapshots.Snapshotter, error){} + } + to.extraSnapshots[name] = fn + } +} + +func testDB(t *testing.T, opt ...testOpt) (context.Context, *DB, func()) { ctx, cancel := context.WithCancel(context.Background()) ctx = namespaces.WithNamespace(ctx, "testing") + ctx = logtest.WithT(ctx, t) + + var topts testOptions + + for _, o := range opt { + o(&topts) + } dirname, err := ioutil.TempDir("", strings.Replace(t.Name(), "/", "_", -1)+"-") if err != nil { @@ -60,6 +84,18 @@ t.Fatal(err) } + snapshotters := map[string]snapshots.Snapshotter{ + "native": snapshotter, + } + + for name, fn := range topts.extraSnapshots { + snapshotter, err := fn(filepath.Join(dirname, name)) + if err != nil { + t.Fatal(err) + } + snapshotters[name] = snapshotter + } + cs, err := local.NewStore(filepath.Join(dirname, "content")) if err != nil { t.Fatal(err) @@ -70,7 +106,7 @@ t.Fatal(err) } - db := NewDB(bdb, cs, map[string]snapshots.Snapshotter{"native": snapshotter}) + db := NewDB(bdb, cs, snapshotters) if err := db.Init(ctx); err != nil { t.Fatal(err) } @@ -330,7 +366,7 @@ defer cleanup() var ( - ctx = context.Background() + ctx = logtest.WithT(context.Background(), t) objects = []object{ blob(bytesFor(1), true), @@ -344,13 +380,47 @@ newSnapshot("5", "3", false, true), container("1", "4"), image("image-1", digestFor(2)), + + // Test lease preservation + blob(bytesFor(5), false, "containerd.io/gc.ref.content.0", digestFor(6).String()), + blob(bytesFor(6), false), + blob(bytesFor(7), false), + newSnapshot("6", "", false, false, "containerd.io/gc.ref.content.0", digestFor(7).String()), + lease("lease-1", []leases.Resource{ + { + ID: digestFor(5).String(), + Type: "content", + }, + { + ID: "6", + Type: "snapshots/native", + }, + }, false), + + // Test flat lease + blob(bytesFor(8), false, "containerd.io/gc.ref.content.0", digestFor(9).String()), + blob(bytesFor(9), true), + blob(bytesFor(10), true), + newSnapshot("7", "", false, false, "containerd.io/gc.ref.content.0", digestFor(10).String()), + newSnapshot("8", "7", false, false), + newSnapshot("9", "8", false, false), + lease("lease-2", []leases.Resource{ + { + ID: digestFor(8).String(), + Type: "content", + }, + { + ID: "9", + Type: "snapshots/native", + }, + }, false, "containerd.io/gc.flat", time.Now().String()), } remaining []gc.Node ) if err := mdb.Update(func(tx *bolt.Tx) error { for _, obj := range objects { - node, err := create(obj, tx, NewImageStore(mdb), cs, sn) + node, err := create(obj, tx, mdb, cs, sn) if err != nil { return err } @@ -425,7 +495,7 @@ if err := mdb.Update(func(tx *bolt.Tx) error { for _, obj := range objects { - node, err := create(obj, tx, NewImageStore(mdb), cs, sn) + node, err := create(obj, tx, mdb, cs, sn) if err != nil { return err } @@ -505,16 +575,15 @@ labels map[string]string } -func create(obj object, tx *bolt.Tx, is images.Store, cs content.Store, sn snapshots.Snapshotter) (*gc.Node, error) { +func create(obj object, tx *bolt.Tx, db *DB, cs content.Store, sn snapshots.Snapshotter) (*gc.Node, error) { var ( node *gc.Node namespace = "test" - ctx = namespaces.WithNamespace(context.Background(), namespace) + ctx = WithTransactionContext(namespaces.WithNamespace(context.Background(), namespace), tx) ) switch v := obj.data.(type) { case testContent: - ctx := WithTransactionContext(ctx, tx) expected := digest.FromBytes(v.data) w, err := cs.Writer(ctx, content.WithRef("test-ref"), @@ -536,7 +605,6 @@ } } case testSnapshot: - ctx := WithTransactionContext(ctx, tx) if v.active { _, err := sn.Prepare(ctx, v.key, v.parent, snapshots.WithLabels(obj.labels)) if err != nil { @@ -560,14 +628,13 @@ } } case testImage: - ctx := WithTransactionContext(ctx, tx) - image := images.Image{ Name: v.name, Target: v.target, Labels: obj.labels, } - _, err := is.Create(ctx, image) + + _, err := NewImageStore(db).Create(ctx, image) if err != nil { return nil, errors.Wrap(err, "failed to create image") } @@ -583,10 +650,31 @@ }, Spec: &types.Any{}, } - _, err := NewContainerStore(tx).Create(ctx, container) + _, err := NewContainerStore(db).Create(ctx, container) if err != nil { return nil, err } + case testLease: + lm := NewLeaseManager(db) + + l, err := lm.Create(ctx, leases.WithID(v.id), leases.WithLabels(obj.labels)) + if err != nil { + return nil, err + } + + for _, ref := range v.refs { + if err := lm.AddResource(ctx, l, ref); err != nil { + return nil, err + } + } + + if !obj.removed { + node = &gc.Node{ + Type: ResourceLease, + Namespace: namespace, + Key: v.id, + } + } } return node, nil @@ -640,6 +728,17 @@ } } +func lease(id string, refs []leases.Resource, r bool, l ...string) object { + return object{ + data: testLease{ + id: id, + refs: refs, + }, + removed: r, + labels: labelmap(l...), + } +} + type testContent struct { data []byte } @@ -660,6 +759,11 @@ snapshot string } +type testLease struct { + id string + refs []leases.Resource +} + func newStores(t testing.TB) (*DB, content.Store, snapshots.Snapshotter, func()) { td, err := ioutil.TempDir("", "gc-test-") if err != nil { diff -Nru containerd-1.2.6/metadata/gc.go containerd-1.5.9/metadata/gc.go --- containerd-1.2.6/metadata/gc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/gc.go 2022-01-05 17:30:58.000000000 +0000 @@ -46,11 +46,17 @@ ResourceIngest ) +const ( + resourceContentFlat = ResourceContent | 0x20 + resourceSnapshotFlat = ResourceSnapshot | 0x20 +) + var ( labelGCRoot = []byte("containerd.io/gc.root") labelGCSnapRef = []byte("containerd.io/gc.ref.snapshot.") labelGCContentRef = []byte("containerd.io/gc.ref.content") labelGCExpire = []byte("containerd.io/gc.expire") + labelGCFlat = []byte("containerd.io/gc.flat") ) func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error { @@ -90,6 +96,7 @@ return nil } libkt := lbkt.Bucket(k) + var flat bool if lblbkt := libkt.Bucket(bucketKeyObjectLabels); lblbkt != nil { if expV := lblbkt.Get(labelGCExpire); expV != nil { @@ -102,6 +109,10 @@ return nil } } + + if flatV := lblbkt.Get(labelGCFlat); flatV != nil { + flat = true + } } fn(gcnode(ResourceLease, ns, string(k))) @@ -111,16 +122,26 @@ // no need to allow the lookup to be recursive, handling here // therefore reduces the number of database seeks. + ctype := ResourceContent + if flat { + ctype = resourceContentFlat + } + cbkt := libkt.Bucket(bucketKeyObjectContent) if cbkt != nil { if err := cbkt.ForEach(func(k, v []byte) error { - fn(gcnode(ResourceContent, ns, string(k))) + fn(gcnode(ctype, ns, string(k))) return nil }); err != nil { return err } } + stype := ResourceSnapshot + if flat { + stype = resourceSnapshotFlat + } + sbkt := libkt.Bucket(bucketKeyObjectSnapshots) if sbkt != nil { if err := sbkt.ForEach(func(sk, sv []byte) error { @@ -130,7 +151,7 @@ snbkt := sbkt.Bucket(sk) return snbkt.ForEach(func(k, v []byte) error { - fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k))) + fn(gcnode(stype, ns, fmt.Sprintf("%s/%s", sk, k))) return nil }) }); err != nil { @@ -257,7 +278,8 @@ } func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)) error { - if node.Type == ResourceContent { + switch node.Type { + case ResourceContent: bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectBlob, []byte(node.Key)) if bkt == nil { // Node may be created from dead edge @@ -265,7 +287,7 @@ } return sendLabelRefs(node.Namespace, bkt, fn) - } else if node.Type == ResourceSnapshot { + case ResourceSnapshot, resourceSnapshotFlat: parts := strings.SplitN(node.Key, "/", 2) if len(parts) != 2 { return errors.Errorf("invalid snapshot gc key %s", node.Key) @@ -280,11 +302,16 @@ } if pv := bkt.Get(bucketKeyParent); len(pv) > 0 { - fn(gcnode(ResourceSnapshot, node.Namespace, fmt.Sprintf("%s/%s", ss, pv))) + fn(gcnode(node.Type, node.Namespace, fmt.Sprintf("%s/%s", ss, pv))) + } + + // Do not send labeled references for flat snapshot refs + if node.Type == resourceSnapshotFlat { + return nil } return sendLabelRefs(node.Namespace, bkt, fn) - } else if node.Type == ResourceIngest { + case ResourceIngest: // Send expected value bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(node.Key)) if bkt == nil { diff -Nru containerd-1.2.6/metadata/gc_test.go containerd-1.5.9/metadata/gc_test.go --- containerd-1.2.6/metadata/gc_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/gc_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,6 +33,15 @@ bolt "go.etcd.io/bbolt" ) +func TestResourceMax(t *testing.T) { + if ResourceContent != resourceContentFlat&gc.ResourceMax { + t.Fatalf("Invalid flat content type: %d (max %d)", resourceContentFlat, gc.ResourceMax) + } + if ResourceSnapshot != resourceSnapshotFlat&gc.ResourceMax { + t.Fatalf("Invalid flat snapshot type: %d (max %d)", resourceSnapshotFlat, gc.ResourceMax) + } +} + func TestGCRoots(t *testing.T) { db, cleanup, err := newDatabase() if err != nil { @@ -90,6 +99,11 @@ addLeaseSnapshot("ns2", "l4", "overlay", "sn8"), addLeaseIngest("ns2", "l4", "ingest-6"), addLeaseIngest("ns2", "l4", "ingest-7"), + + addLease("ns3", "l1", labelmap(string(labelGCFlat), time.Now().Add(time.Hour).Format(time.RFC3339))), + addLeaseContent("ns3", "l1", dgst(1)), + addLeaseSnapshot("ns3", "l1", "overlay", "sn1"), + addLeaseIngest("ns3", "l1", "ingest-1"), } expected := []gc.Node{ @@ -121,6 +135,10 @@ gcnode(ResourceIngest, "ns1", "ingest-3"), gcnode(ResourceIngest, "ns2", "ingest-4"), gcnode(ResourceIngest, "ns2", "ingest-5"), + gcnode(ResourceLease, "ns3", "l1"), + gcnode(ResourceIngest, "ns3", "ingest-1"), + gcnode(resourceContentFlat, "ns3", dgst(1).String()), + gcnode(resourceSnapshotFlat, "ns3", "overlay/sn1"), } if err := db.Update(func(tx *bolt.Tx) error { @@ -268,6 +286,14 @@ addSnapshot("ns2", "overlay", "sn3", "", labelmap( string(labelGCContentRef), dgst(1).String(), string(labelGCContentRef)+".keep-me", dgst(6).String())), + + // Test flat references don't follow label references + addContent("ns3", dgst(1), nil), + addContent("ns3", dgst(2), labelmap(string(labelGCContentRef)+".0", dgst(1).String())), + + addSnapshot("ns3", "overlay", "sn1", "", nil), + addSnapshot("ns3", "overlay", "sn2", "sn1", nil), + addSnapshot("ns3", "overlay", "sn3", "", labelmap(string(labelGCSnapRef)+"btrfs", "sn1", string(labelGCSnapRef)+"overlay", "sn1")), } refs := map[gc.Node][]gc.Node{ @@ -316,6 +342,18 @@ gcnode(ResourceIngest, "ns2", "ingest-2"): { gcnode(ResourceContent, "ns2", dgst(8).String()), }, + gcnode(resourceSnapshotFlat, "ns3", "overlay/sn2"): { + gcnode(resourceSnapshotFlat, "ns3", "overlay/sn1"), + }, + gcnode(ResourceSnapshot, "ns3", "overlay/sn2"): { + gcnode(ResourceSnapshot, "ns3", "overlay/sn1"), + }, + gcnode(resourceSnapshotFlat, "ns3", "overlay/sn1"): nil, + gcnode(resourceSnapshotFlat, "ns3", "overlay/sn3"): nil, + gcnode(ResourceSnapshot, "ns3", "overlay/sn3"): { + gcnode(ResourceSnapshot, "ns3", "btrfs/sn1"), + gcnode(ResourceSnapshot, "ns3", "overlay/sn1"), + }, } if err := db.Update(func(tx *bolt.Tx) error { diff -Nru containerd-1.2.6/metadata/images.go containerd-1.5.9/metadata/images.go --- containerd-1.2.6/metadata/images.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/images.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "encoding/binary" "fmt" "strings" + "sync/atomic" "time" "github.com/containerd/containerd/errdefs" @@ -84,7 +85,7 @@ filter, err := filters.ParseAll(fs...) if err != nil { - return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error()) + return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error()) } var m []images.Image @@ -192,6 +193,14 @@ key := strings.TrimPrefix(path, "labels.") updated.Labels[key] = image.Labels[key] continue + } else if strings.HasPrefix(path, "annotations.") { + if updated.Target.Annotations == nil { + updated.Target.Annotations = map[string]string{} + } + + key := strings.TrimPrefix(path, "annotations.") + updated.Target.Annotations[key] = image.Target.Annotations[key] + continue } switch path { @@ -204,6 +213,8 @@ // make sense to modify the size or digest without touching the // mediatype, as well, for example. updated.Target = image.Target + case "annotations": + updated.Target.Annotations = image.Target.Annotations default: return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on image %q", path, image.Name) } @@ -239,19 +250,16 @@ return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) } - err = bkt.DeleteBucket([]byte(name)) - if err == bolt.ErrBucketNotFound { - return errors.Wrapf(errdefs.ErrNotFound, "image %q", name) + if err = bkt.DeleteBucket([]byte(name)); err != nil { + if err == bolt.ErrBucketNotFound { + err = errors.Wrapf(errdefs.ErrNotFound, "image %q", name) + } + return err } - // A reference to a piece of content has been removed, - // mark content store as dirty for triggering garbage - // collection - s.db.dirtyL.Lock() - s.db.dirtyCS = true - s.db.dirtyL.Unlock() + atomic.AddUint32(&s.db.dirty, 1) - return err + return nil }) } @@ -298,6 +306,11 @@ } image.Labels = labels + image.Target.Annotations, err = boltutil.ReadAnnotations(bkt) + if err != nil { + return err + } + tbkt := bkt.Bucket(bucketKeyTarget) if tbkt == nil { return errors.New("unable to read target bucket") @@ -331,6 +344,10 @@ return errors.Wrapf(err, "writing labels for image %v", image.Name) } + if err := boltutil.WriteAnnotations(bkt, image.Target.Annotations); err != nil { + return errors.Wrapf(err, "writing Annotations for image %v", image.Name) + } + // write the target bucket tbkt, err := bkt.CreateBucketIfNotExists(bucketKeyTarget) if err != nil { diff -Nru containerd-1.2.6/metadata/images_test.go containerd-1.5.9/metadata/images_test.go --- containerd-1.2.6/metadata/images_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/images_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -49,6 +49,9 @@ Size: 10, MediaType: "application/vnd.containerd.test", Digest: digest.FromString(id), + Annotations: map[string]string{ + "foo": "bar", + }, }, } @@ -138,7 +141,7 @@ } // try it again, get NotFound - if err := store.Delete(ctx, id); errors.Cause(err) != errdefs.ErrNotFound { + if err := store.Delete(ctx, id); !errdefs.IsNotFound(err) { t.Fatalf("unexpected error %v", err) } } @@ -168,6 +171,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, expected: images.Image{ @@ -178,6 +184,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, }, @@ -203,6 +212,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, expected: images.Image{ @@ -213,6 +225,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, }, @@ -227,6 +242,10 @@ Target: ocispec.Descriptor{ Size: 20, // ignored MediaType: "application/vnd.oci.blab+ignored", // make sure other stuff is ignored + Annotations: map[string]string{ + "not": "bar", + "new": "boo", + }, }, }, fieldpaths: []string{"labels"}, @@ -238,6 +257,41 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + "baz": "boo", + }, + }, + }, + }, + { + name: "ReplaceLabelsAnnotationsFieldPath", + original: imageBase(), + input: images.Image{ + Labels: map[string]string{ + "for": "bar", + "boo": "boo", + }, + Target: ocispec.Descriptor{ + Size: 20, // ignored + MediaType: "application/vnd.oci.blab+ignored", // make sure other stuff is ignored + Annotations: map[string]string{ + "foo": "boo", + }, + }, + }, + fieldpaths: []string{"annotations", "labels"}, + expected: images.Image{ + Labels: map[string]string{ + "for": "bar", + "boo": "boo", + }, + Target: ocispec.Descriptor{ + Size: 10, + MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "boo", + }, }, }, }, @@ -252,6 +306,9 @@ Target: ocispec.Descriptor{ Size: 20, // ignored MediaType: "application/vnd.oci.blab+ignored", // make sure other stuff is ignored + Annotations: map[string]string{ + "foo": "bar", + }, }, }, fieldpaths: []string{"labels.foo"}, @@ -263,6 +320,43 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + "baz": "boo", + }, + }, + }, + }, + { + name: "ReplaceAnnotation", + original: imageBase(), + input: images.Image{ + Labels: map[string]string{ + "foo": "baz", + "baz": "bunk", + }, + Target: ocispec.Descriptor{ + Size: 20, // ignored + MediaType: "application/vnd.oci.blab+ignored", // make sure other stuff is ignored + Annotations: map[string]string{ + "foo": "baz", + "baz": "bunk", + }, + }, + }, + fieldpaths: []string{"annotations.foo"}, + expected: images.Image{ + Labels: map[string]string{ + "foo": "bar", + "baz": "boo", + }, + Target: ocispec.Descriptor{ + Size: 10, + MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "baz", + "baz": "boo", + }, }, }, }, @@ -273,6 +367,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab+replaced", + Annotations: map[string]string{ + "fox": "dog", + }, }, }, fieldpaths: []string{"target"}, @@ -284,6 +381,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab+replaced", + Annotations: map[string]string{ + "fox": "dog", + }, }, }, }, @@ -298,6 +398,9 @@ Target: ocispec.Descriptor{ Size: 0, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, cause: errdefs.ErrInvalidArgument, @@ -311,6 +414,9 @@ }, Target: ocispec.Descriptor{ MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, createerr: errdefs.ErrInvalidArgument, @@ -352,6 +458,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, input: images.Image{ @@ -363,6 +472,9 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + }, }, }, cause: errdefs.ErrNotFound, @@ -384,7 +496,7 @@ // Create now := time.Now() created, err := store.Create(ctx, testcase.original) - if errors.Cause(err) != testcase.createerr { + if !errors.Is(err, testcase.createerr) { if testcase.createerr == nil { t.Fatalf("unexpected error: %v", err) } else { @@ -406,7 +518,7 @@ // Update now = time.Now() updated, err := store.Update(ctx, testcase.input, testcase.fieldpaths...) - if errors.Cause(err) != testcase.cause { + if !errors.Is(err, testcase.cause) { if testcase.cause == nil { t.Fatalf("unexpected error: %v", err) } else { @@ -440,6 +552,10 @@ Target: ocispec.Descriptor{ Size: 10, MediaType: "application/vnd.oci.blab", + Annotations: map[string]string{ + "foo": "bar", + "baz": "boo", + }, }, } } diff -Nru containerd-1.2.6/metadata/leases.go containerd-1.5.9/metadata/leases.go --- containerd-1.2.6/metadata/leases.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/leases.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,9 @@ import ( "context" + "fmt" + "strings" + "sync/atomic" "time" "github.com/containerd/containerd/errdefs" @@ -30,17 +33,17 @@ bolt "go.etcd.io/bbolt" ) -// LeaseManager manages the create/delete lifecyle of leases +// LeaseManager manages the create/delete lifecycle of leases // and also returns existing leases type LeaseManager struct { - tx *bolt.Tx + db *DB } // NewLeaseManager creates a new lease manager for managing leases using // the provided database transaction. -func NewLeaseManager(tx *bolt.Tx) *LeaseManager { +func NewLeaseManager(db *DB) *LeaseManager { return &LeaseManager{ - tx: tx, + db: db, } } @@ -61,56 +64,66 @@ return leases.Lease{}, err } - topbkt, err := createBucketIfNotExists(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) - if err != nil { - return leases.Lease{}, err - } + if err := update(ctx, lm.db, func(tx *bolt.Tx) error { + topbkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) + if err != nil { + return err + } - txbkt, err := topbkt.CreateBucket([]byte(l.ID)) - if err != nil { - if err == bolt.ErrBucketExists { - err = errdefs.ErrAlreadyExists + txbkt, err := topbkt.CreateBucket([]byte(l.ID)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errdefs.ErrAlreadyExists + } + return errors.Wrapf(err, "lease %q", l.ID) } - return leases.Lease{}, errors.Wrapf(err, "lease %q", l.ID) - } - t := time.Now().UTC() - createdAt, err := t.MarshalBinary() - if err != nil { - return leases.Lease{}, err - } - if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil { - return leases.Lease{}, err - } + t := time.Now().UTC() + createdAt, err := t.MarshalBinary() + if err != nil { + return err + } + if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil { + return err + } - if l.Labels != nil { - if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil { - return leases.Lease{}, err + if l.Labels != nil { + if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil { + return err + } } - } - l.CreatedAt = t + l.CreatedAt = t + return nil + }); err != nil { + return leases.Lease{}, err + } return l, nil } -// Delete delets the lease with the provided lease ID +// Delete deletes the lease with the provided lease ID func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease, _ ...leases.DeleteOpt) error { namespace, err := namespaces.NamespaceRequired(ctx) if err != nil { return err } - topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) - if topbkt == nil { - return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) - } - if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil { - if err == bolt.ErrBucketNotFound { - err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) + return update(ctx, lm.db, func(tx *bolt.Tx) error { + topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) + if topbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) } - return err - } - return nil + if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil { + if err == bolt.ErrBucketNotFound { + err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) + } + return err + } + + atomic.AddUint32(&lm.db.dirty, 1) + + return nil + }) } // List lists all active leases @@ -122,49 +135,189 @@ filter, err := filters.ParseAll(fs...) if err != nil { - return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error()) + return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error()) } var ll []leases.Lease - topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) - if topbkt == nil { - return ll, nil - } + if err := view(ctx, lm.db, func(tx *bolt.Tx) error { + topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases) + if topbkt == nil { + return nil + } + + return topbkt.ForEach(func(k, v []byte) error { + if v != nil { + return nil + } + txbkt := topbkt.Bucket(k) + + l := leases.Lease{ + ID: string(k), + } + + if v := txbkt.Get(bucketKeyCreatedAt); v != nil { + t := &l.CreatedAt + if err := t.UnmarshalBinary(v); err != nil { + return err + } + } + + labels, err := boltutil.ReadLabels(txbkt) + if err != nil { + return err + } + l.Labels = labels + + if filter.Match(adaptLease(l)) { + ll = append(ll, l) + } - if err := topbkt.ForEach(func(k, v []byte) error { - if v != nil { return nil + }) + }); err != nil { + return nil, err + } + + return ll, nil +} + +// AddResource references the resource by the provided lease. +func (lm *LeaseManager) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { + namespace, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + + return update(ctx, lm.db, func(tx *bolt.Tx) error { + topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID)) + if topbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) } - txbkt := topbkt.Bucket(k) - l := leases.Lease{ - ID: string(k), + keys, ref, err := parseLeaseResource(r) + if err != nil { + return err } - if v := txbkt.Get(bucketKeyCreatedAt); v != nil { - t := &l.CreatedAt - if err := t.UnmarshalBinary(v); err != nil { + bkt := topbkt + for _, key := range keys { + bkt, err = bkt.CreateBucketIfNotExists([]byte(key)) + if err != nil { return err } } + return bkt.Put([]byte(ref), nil) + }) +} - labels, err := boltutil.ReadLabels(txbkt) +// DeleteResource dereferences the resource by the provided lease. +func (lm *LeaseManager) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error { + namespace, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + + return update(ctx, lm.db, func(tx *bolt.Tx) error { + topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID)) + if topbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) + } + + keys, ref, err := parseLeaseResource(r) if err != nil { return err } - l.Labels = labels - if filter.Match(adaptLease(l)) { - ll = append(ll, l) + bkt := topbkt + for _, key := range keys { + if bkt == nil { + break + } + bkt = bkt.Bucket([]byte(key)) } + if bkt != nil { + if err := bkt.Delete([]byte(ref)); err != nil { + return err + } + } + + atomic.AddUint32(&lm.db.dirty, 1) + return nil - }); err != nil { + }) +} + +// ListResources lists all the resources referenced by the lease. +func (lm *LeaseManager) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) { + namespace, err := namespaces.NamespaceRequired(ctx) + if err != nil { return nil, err } - return ll, nil + var rs []leases.Resource + + if err := view(ctx, lm.db, func(tx *bolt.Tx) error { + + topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID)) + if topbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID) + } + + // content resources + if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil { + if err := cbkt.ForEach(func(k, _ []byte) error { + rs = append(rs, leases.Resource{ + ID: string(k), + Type: string(bucketKeyObjectContent), + }) + + return nil + }); err != nil { + return err + } + } + + // ingest resources + if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil { + if err := lbkt.ForEach(func(k, _ []byte) error { + rs = append(rs, leases.Resource{ + ID: string(k), + Type: string(bucketKeyObjectIngests), + }) + + return nil + }); err != nil { + return err + } + } + + // snapshot resources + if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil { + if err := sbkt.ForEach(func(sk, sv []byte) error { + if sv != nil { + return nil + } + + snbkt := sbkt.Bucket(sk) + return snbkt.ForEach(func(k, _ []byte) error { + rs = append(rs, leases.Resource{ + ID: string(k), + Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk), + }) + return nil + }) + }); err != nil { + return err + } + } + + return nil + }); err != nil { + return nil, err + } + return rs, nil } func addSnapshotLease(ctx context.Context, tx *bolt.Tx, snapshotter, key string) error { @@ -307,3 +460,36 @@ return bkt.Delete([]byte(ref)) } + +func parseLeaseResource(r leases.Resource) ([]string, string, error) { + var ( + ref = r.ID + typ = r.Type + keys = strings.Split(typ, "/") + ) + + switch k := keys[0]; k { + case string(bucketKeyObjectContent), + string(bucketKeyObjectIngests): + + if len(keys) != 1 { + return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid resource type %s", typ) + } + + if k == string(bucketKeyObjectContent) { + dgst, err := digest.Parse(ref) + if err != nil { + return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid content resource id %s: %v", ref, err) + } + ref = dgst.String() + } + case string(bucketKeyObjectSnapshots): + if len(keys) != 2 { + return nil, "", errors.Wrapf(errdefs.ErrInvalidArgument, "invalid snapshot resource type %s", typ) + } + default: + return nil, "", errors.Wrapf(errdefs.ErrNotImplemented, "resource type %s not supported yet", typ) + } + + return keys, ref, nil +} diff -Nru containerd-1.2.6/metadata/leases_test.go containerd-1.5.9/metadata/leases_test.go --- containerd-1.2.6/metadata/leases_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/leases_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package metadata import ( + _ "crypto/sha256" "testing" "github.com/containerd/containerd/errdefs" @@ -29,6 +30,8 @@ ctx, db, cancel := testEnv(t) defer cancel() + lm := NewLeaseManager(NewDB(db, nil, nil)) + testCases := []struct { ID string CreateErr error @@ -51,9 +54,9 @@ for _, tc := range testCases { if err := db.Update(func(tx *bolt.Tx) error { - lease, err := NewLeaseManager(tx).Create(ctx, leases.WithID(tc.ID)) + lease, err := lm.Create(WithTransactionContext(ctx, tx), leases.WithID(tc.ID)) if err != nil { - if tc.CreateErr != nil && errors.Cause(err) == tc.CreateErr { + if tc.CreateErr != nil && errors.Is(err, tc.CreateErr) { return nil } return err @@ -65,13 +68,8 @@ } } - var listed []leases.Lease - // List leases, check same - if err := db.View(func(tx *bolt.Tx) error { - var err error - listed, err = NewLeaseManager(tx).List(ctx) - return err - }); err != nil { + listed, err := lm.List(ctx) + if err != nil { t.Fatal(err) } @@ -88,23 +86,18 @@ } for _, tc := range testCases { - if err := db.Update(func(tx *bolt.Tx) error { - return NewLeaseManager(tx).Delete(ctx, leases.Lease{ - ID: tc.ID, - }) + if err := lm.Delete(ctx, leases.Lease{ + ID: tc.ID, }); err != nil { - if tc.DeleteErr == nil && errors.Cause(err) != tc.DeleteErr { + if tc.DeleteErr == nil && !errors.Is(err, tc.DeleteErr) { t.Fatal(err) } } } - if err := db.View(func(tx *bolt.Tx) error { - var err error - listed, err = NewLeaseManager(tx).List(ctx) - return err - }); err != nil { + listed, err = lm.List(ctx) + if err != nil { t.Fatal(err) } @@ -117,6 +110,8 @@ ctx, db, cancel := testEnv(t) defer cancel() + lm := NewLeaseManager(NewDB(db, nil, nil)) + testset := [][]leases.Opt{ { leases.WithID("lease1"), @@ -143,14 +138,16 @@ } // Insert all - for _, opts := range testset { - if err := db.Update(func(tx *bolt.Tx) error { - lm := NewLeaseManager(tx) - _, err := lm.Create(ctx, opts...) - return err - }); err != nil { - t.Fatal(err) + if err := db.Update(func(tx *bolt.Tx) error { + for _, opts := range testset { + _, err := lm.Create(WithTransactionContext(ctx, tx), opts...) + if err != nil { + return err + } } + return nil + }); err != nil { + t.Fatal(err) } for _, testcase := range []struct { @@ -201,39 +198,33 @@ }, } { t.Run(testcase.name, func(t *testing.T) { - if err := db.View(func(tx *bolt.Tx) error { - lm := NewLeaseManager(tx) - results, err := lm.List(ctx, testcase.filters...) - if err != nil { - return err - } + results, err := lm.List(ctx, testcase.filters...) + if err != nil { + t.Fatal(err) + } - if len(results) != len(testcase.expected) { - t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected)) - } + if len(results) != len(testcase.expected) { + t.Errorf("length of result does not match expected: %v != %v", len(results), len(testcase.expected)) + } - expectedMap := map[string]struct{}{} - for _, expected := range testcase.expected { - expectedMap[expected] = struct{}{} - } + expectedMap := map[string]struct{}{} + for _, expected := range testcase.expected { + expectedMap[expected] = struct{}{} + } - for _, result := range results { - if _, ok := expectedMap[result.ID]; !ok { - t.Errorf("unexpected match: %v", result.ID) - } else { - delete(expectedMap, result.ID) - } + for _, result := range results { + if _, ok := expectedMap[result.ID]; !ok { + t.Errorf("unexpected match: %v", result.ID) + } else { + delete(expectedMap, result.ID) } - if len(expectedMap) > 0 { - for match := range expectedMap { - t.Errorf("missing match: %v", match) - } + } + if len(expectedMap) > 0 { + for match := range expectedMap { + t.Errorf("missing match: %v", match) } - - return nil - }); err != nil { - t.Fatal(err) } + }) } @@ -246,21 +237,184 @@ } } - if err := db.Update(func(tx *bolt.Tx) error { - lm := NewLeaseManager(tx) - return lm.Delete(ctx, lease) - }); err != nil { + if err := lm.Delete(ctx, lease); err != nil { t.Fatal(err) } // try it again, get not found - if err := db.Update(func(tx *bolt.Tx) error { - lm := NewLeaseManager(tx) - return lm.Delete(ctx, lease) - }); err == nil { + if err := lm.Delete(ctx, lease); err == nil { t.Fatalf("expected error deleting non-existent lease") } else if !errdefs.IsNotFound(err) { t.Fatalf("unexpected error: %s", err) } } } + +func TestLeaseResource(t *testing.T) { + ctx, db, cancel := testEnv(t) + defer cancel() + + lm := NewLeaseManager(NewDB(db, nil, nil)) + + var ( + leaseID = "l1" + + lease = leases.Lease{ + ID: leaseID, + } + + snapshotterKey = "RstMI3X8vguKoPFkmIStZ5fQFI7F1L0o" + ) + + // prepare lease + if _, err := lm.Create(ctx, leases.WithID(leaseID)); err != nil { + t.Fatal(err) + } + + testCases := []struct { + lease leases.Lease + resource leases.Resource + err error + }{ + { + lease: lease, + resource: leases.Resource{ + ID: "sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912", + Type: "content", + }, + }, + { + lease: lease, + resource: leases.Resource{ + ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH", + Type: "ingests", + }, + }, + { + // allow to add resource which exists + lease: lease, + resource: leases.Resource{ + ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH", + Type: "ingests", + }, + }, + { + // not allow to reference to lease + lease: lease, + resource: leases.Resource{ + ID: "xCAV3F6PddlXitbtby0Vo23Qof6RTWpG", + Type: "leases", + }, + err: errdefs.ErrNotImplemented, + }, + { + // not allow to reference to container + lease: lease, + resource: leases.Resource{ + ID: "05O9ljptPu5Qq9kZGOacEfymBwQFM8ZH", + Type: "containers", + }, + err: errdefs.ErrNotImplemented, + }, + { + // not allow to reference to image + lease: lease, + resource: leases.Resource{ + ID: "qBUHpWBn03YaCt9cL3PPGKWoxBqTlLfu", + Type: "image", + }, + err: errdefs.ErrNotImplemented, + }, + { + lease: lease, + resource: leases.Resource{ + ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", + Type: "snapshots", + }, + err: errdefs.ErrInvalidArgument, + }, + { + lease: lease, + resource: leases.Resource{ + ID: snapshotterKey, + Type: "snapshots/overlayfs", + }, + }, + { + lease: lease, + resource: leases.Resource{ + ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", + Type: "snapshots/overlayfs/type1", + }, + err: errdefs.ErrInvalidArgument, + }, + { + lease: leases.Lease{ + ID: "non-found", + }, + resource: leases.Resource{ + ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2", + Type: "snapshots/overlayfs", + }, + err: errdefs.ErrNotFound, + }, + } + + idxList := make(map[leases.Resource]bool) + for i, tc := range testCases { + if err := db.Update(func(tx *bolt.Tx) error { + err0 := lm.AddResource(WithTransactionContext(ctx, tx), tc.lease, tc.resource) + if !errors.Is(err0, tc.err) { + return errors.Errorf("expect error (%v), but got (%v)", tc.err, err0) + } + + if err0 == nil { + // not visited yet + idxList[tc.resource] = false + } + return nil + }); err != nil { + t.Fatalf("failed to run case %d with resource: %v", i, err) + } + } + + // check list function + var gotList []leases.Resource + gotList, err := lm.ListResources(ctx, lease) + if err != nil { + t.Fatal(err) + } + + if len(gotList) != len(idxList) { + t.Fatalf("expected (%d) resources, but got (%d)", len(idxList), len(gotList)) + } + + for _, r := range gotList { + visited, ok := idxList[r] + if !ok { + t.Fatalf("unexpected resource(%v)", r) + } + if visited { + t.Fatalf("duplicate resource(%v)", r) + } + idxList[r] = true + } + + // remove snapshots + if err := lm.DeleteResource(ctx, lease, leases.Resource{ + ID: snapshotterKey, + Type: "snapshots/overlayfs", + }); err != nil { + t.Fatal(err) + } + + // check list number + gotList, err = lm.ListResources(ctx, lease) + if err != nil { + t.Fatal(err) + } + + if len(gotList)+1 != len(idxList) { + t.Fatalf("expected (%d) resources, but got (%d)", len(idxList)-1, len(gotList)) + } +} diff -Nru containerd-1.2.6/metadata/namespaces.go containerd-1.5.9/metadata/namespaces.go --- containerd-1.2.6/metadata/namespaces.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/namespaces.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,8 +18,10 @@ import ( "context" + "strings" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/identifiers" l "github.com/containerd/containerd/labels" "github.com/containerd/containerd/namespaces" "github.com/pkg/errors" @@ -41,7 +43,7 @@ return err } - if err := namespaces.Validate(namespace); err != nil { + if err := identifiers.Validate(namespace); err != nil { return err } @@ -129,12 +131,27 @@ return namespaces, nil } -func (s *namespaceStore) Delete(ctx context.Context, namespace string) error { +func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { + i := &namespaces.DeleteInfo{ + Name: namespace, + } + for _, o := range opts { + if err := o(ctx, i); err != nil { + return err + } + } bkt := getBucket(s.tx, bucketKeyVersion) - if empty, err := s.namespaceEmpty(ctx, namespace); err != nil { + types, err := s.listNs(namespace) + if err != nil { return err - } else if !empty { - return errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace %q must be empty", namespace) + } + + if len(types) > 0 { + return errors.Wrapf( + errdefs.ErrFailedPrecondition, + "namespace %q must be empty, but it still has %s", + namespace, strings.Join(types, ", "), + ) } if err := bkt.DeleteBucket([]byte(namespace)); err != nil { @@ -148,32 +165,35 @@ return nil } -func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (bool, error) { - // Get all data buckets - buckets := []*bolt.Bucket{ - getImagesBucket(s.tx, namespace), - getBlobsBucket(s.tx, namespace), - getContainersBucket(s.tx, namespace), +// listNs returns the types of the remaining objects inside the given namespace. +// It doesn't return exact objects due to performance concerns. +func (s *namespaceStore) listNs(namespace string) ([]string, error) { + var out []string + + if !isBucketEmpty(getImagesBucket(s.tx, namespace)) { + out = append(out, "images") + } + if !isBucketEmpty(getBlobsBucket(s.tx, namespace)) { + out = append(out, "blobs") } + if !isBucketEmpty(getContainersBucket(s.tx, namespace)) { + out = append(out, "containers") + } + if snbkt := getSnapshottersBucket(s.tx, namespace); snbkt != nil { if err := snbkt.ForEach(func(k, v []byte) error { if v == nil { - buckets = append(buckets, snbkt.Bucket(k)) + if !isBucketEmpty(snbkt.Bucket(k)) { + out = append(out, "snapshot-"+string(k)) + } } return nil }); err != nil { - return false, err - } - } - - // Ensure data buckets are empty - for _, bkt := range buckets { - if !isBucketEmpty(bkt) { - return false, nil + return nil, err } } - return true, nil + return out, nil } func isBucketEmpty(bkt *bolt.Bucket) bool { diff -Nru containerd-1.2.6/metadata/namespaces_test.go containerd-1.5.9/metadata/namespaces_test.go --- containerd-1.2.6/metadata/namespaces_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metadata/namespaces_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,85 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package metadata + +import ( + "context" + "testing" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/namespaces" + "github.com/gogo/protobuf/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func TestCreateDelete(t *testing.T) { + ctx, db, cleanup := testDB(t) + defer cleanup() + + subtests := []struct { + name string + create func(t *testing.T, ctx context.Context) + validate func(t *testing.T, err error) + }{ + { + name: "empty", + create: func(t *testing.T, ctx context.Context) {}, + validate: func(t *testing.T, err error) { + require.NoError(t, err) + }, + }, + { + name: "not-empty", + create: func(t *testing.T, ctx context.Context) { + store := NewContainerStore(db) + _, err := store.Create(ctx, containers.Container{ + ID: "c1", + Runtime: containers.RuntimeInfo{Name: "rt"}, + Spec: &types.Any{}, + }) + require.NoError(t, err) + }, + validate: func(t *testing.T, err error) { + require.Error(t, err) + assert.Contains(t, err.Error(), "still has containers") + }, + }, + } + + for _, subtest := range subtests { + ns := subtest.name + ctx = namespaces.WithNamespace(ctx, ns) + + t.Run(subtest.name, func(t *testing.T) { + err := db.Update(func(tx *bbolt.Tx) error { + store := NewNamespaceStore(tx) + return store.Create(ctx, ns, nil) + }) + require.NoError(t, err) + + subtest.create(t, ctx) + + err = db.Update(func(tx *bbolt.Tx) error { + store := NewNamespaceStore(tx) + return store.Delete(ctx, ns) + }) + subtest.validate(t, err) + }) + } +} diff -Nru containerd-1.2.6/metadata/snapshot.go containerd-1.5.9/metadata/snapshot.go --- containerd-1.2.6/metadata/snapshot.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/snapshot.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,9 +21,11 @@ "fmt" "strings" "sync" + "sync/atomic" "time" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/filters" "github.com/containerd/containerd/labels" "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata/boltutil" @@ -34,6 +36,11 @@ bolt "go.etcd.io/bbolt" ) +const ( + inheritedLabelsPrefix = "containerd.io/snapshot/" + labelSnapshotRef = "containerd.io/snapshot.ref" +) + type snapshotter struct { snapshots.Snapshotter name string @@ -153,6 +160,7 @@ local = snapshots.Info{ Name: info.Name, } + updated bool ) if err := update(ctx, s.db, func(tx *bolt.Tx) error { bkt := getSnapshotterBucket(tx, ns, s.name) @@ -209,13 +217,24 @@ bkey = string(sbkt.Get(bucketKeyName)) local.Parent = string(sbkt.Get(bucketKeyParent)) + inner := snapshots.Info{ + Name: bkey, + Labels: snapshots.FilterInheritedLabels(local.Labels), + } + + // NOTE: Perform this inside the transaction to reduce the + // chances of out of sync data. The backend snapshotters + // should perform the Update as fast as possible. + if info, err = s.Snapshotter.Update(ctx, inner, fieldpaths...); err != nil { + return err + } + updated = true + return nil }); err != nil { - return snapshots.Info{}, err - } - - info, err = s.Snapshotter.Stat(ctx, bkey) - if err != nil { + if updated { + log.G(ctx).WithField("snapshotter", s.name).WithField("key", local.Name).WithError(err).Error("transaction failed after updating snapshot backend") + } return snapshots.Info{}, err } @@ -232,7 +251,7 @@ info.Labels = overlay.Labels } else { for k, v := range overlay.Labels { - overlay.Labels[k] = v + info.Labels[k] = v } } return info @@ -282,31 +301,158 @@ return nil, err } - var m []mount.Mount + var ( + target = base.Labels[labelSnapshotRef] + bparent string + bkey string + bopts = []snapshots.Opt{ + snapshots.WithLabels(snapshots.FilterInheritedLabels(base.Labels)), + } + ) + if err := update(ctx, s.db, func(tx *bolt.Tx) error { bkt, err := createSnapshotterBucket(tx, ns, s.name) if err != nil { return err } - bbkt, err := bkt.CreateBucket([]byte(key)) - if err != nil { - if err == bolt.ErrBucketExists { - err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", key) + // Check if target exists, if so, return already exists + if target != "" { + if tbkt := bkt.Bucket([]byte(target)); tbkt != nil { + return errors.Wrapf(errdefs.ErrAlreadyExists, "target snapshot %q", target) } + } + + if bbkt := bkt.Bucket([]byte(key)); bbkt != nil { + return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", key) + } + + if parent != "" { + pbkt := bkt.Bucket([]byte(parent)) + if pbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", parent) + } + bparent = string(pbkt.Get(bucketKeyName)) + } + + sid, err := bkt.NextSequence() + if err != nil { return err } + bkey = createKey(sid, ns, key) + + return err + }); err != nil { + return nil, err + } + + var ( + m []mount.Mount + created string + rerr error + ) + if readonly { + m, err = s.Snapshotter.View(ctx, bkey, bparent, bopts...) + } else { + m, err = s.Snapshotter.Prepare(ctx, bkey, bparent, bopts...) + } + + // An already exists error should indicate the backend found a snapshot + // matching a provided target reference. + if errdefs.IsAlreadyExists(err) { + if target != "" { + var tinfo *snapshots.Info + filter := fmt.Sprintf(`labels."containerd.io/snapshot.ref"==%s,parent==%q`, target, bparent) + if err := s.Snapshotter.Walk(ctx, func(ctx context.Context, i snapshots.Info) error { + if tinfo == nil && i.Kind == snapshots.KindCommitted { + if i.Labels["containerd.io/snapshot.ref"] != target { + // Walk did not respect filter + return nil + } + if i.Parent != bparent { + // Walk did not respect filter + return nil + } + tinfo = &i + } + return nil + + }, filter); err != nil { + return nil, errors.Wrap(err, "failed walking backend snapshots") + } + + if tinfo == nil { + return nil, errors.Wrapf(errdefs.ErrNotFound, "target snapshot %q in backend", target) + } + + key = target + bkey = tinfo.Name + bparent = tinfo.Parent + base.Created = tinfo.Created + base.Updated = tinfo.Updated + if base.Labels == nil { + base.Labels = tinfo.Labels + } else { + for k, v := range tinfo.Labels { + if _, ok := base.Labels[k]; !ok { + base.Labels[k] = v + } + } + } + + // Propagate this error after the final update + rerr = errors.Wrapf(errdefs.ErrAlreadyExists, "target snapshot %q from snapshotter", target) + } else { + // This condition is unexpected as the key provided is expected + // to be new and unique, return as unknown response from backend + // to avoid confusing callers handling already exists. + return nil, errors.Wrapf(errdefs.ErrUnknown, "unexpected error from snapshotter: %v", err) + } + } else if err != nil { + return nil, err + } else { + ts := time.Now().UTC() + base.Created = ts + base.Updated = ts + created = bkey + } + + if txerr := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "can not find snapshotter %q", s.name) + } + if err := addSnapshotLease(ctx, tx, s.name, key); err != nil { return err } - var bparent string + bbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err != bolt.ErrBucketExists { + return err + } + if rerr == nil { + rerr = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %q", key) + } + return nil + } + if parent != "" { pbkt := bkt.Bucket([]byte(parent)) if pbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "parent snapshot %v does not exist", parent) } - bparent = string(pbkt.Get(bucketKeyName)) + + // Ensure the backend's parent matches the metadata store's parent + // If it is mismatched, then a target was provided for a snapshotter + // which has a different parent then requested. + // NOTE: The backend snapshotter is responsible for enforcing the + // uniqueness of the reference relationships, the metadata store + // can only error out to prevent inconsistent data. + if bparent != string(pbkt.Get(bucketKeyName)) { + return errors.Wrapf(errdefs.ErrInvalidArgument, "mismatched parent %s from target %s", parent, target) + } cbkt, err := pbkt.CreateBucketIfNotExists(bucketKeyChildren) if err != nil { @@ -321,34 +467,28 @@ } } - sid, err := bkt.NextSequence() - if err != nil { - return err - } - bkey := createKey(sid, ns, key) - if err := bbkt.Put(bucketKeyName, []byte(bkey)); err != nil { - return err - } - - ts := time.Now().UTC() - if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { + if err := boltutil.WriteTimestamps(bbkt, base.Created, base.Updated); err != nil { return err } if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { return err } - // TODO: Consider doing this outside of transaction to lessen - // metadata lock time - if readonly { - m, err = s.Snapshotter.View(ctx, bkey, bparent) - } else { - m, err = s.Snapshotter.Prepare(ctx, bkey, bparent) + return bbkt.Put(bucketKeyName, []byte(bkey)) + }); txerr != nil { + rerr = txerr + } + + if rerr != nil { + // If the created reference is not stored, attempt clean up + if created != "" { + if err := s.Snapshotter.Remove(ctx, created); err != nil { + log.G(ctx).WithField("snapshotter", s.name).WithField("key", created).WithError(err).Error("failed to cleanup unreferenced snapshot") + } } - return err - }); err != nil { - return nil, err + return nil, rerr } + return m, nil } @@ -372,7 +512,8 @@ return err } - return update(ctx, s.db, func(tx *bolt.Tx) error { + var bname string + if err := update(ctx, s.db, func(tx *bolt.Tx) error { bkt := getSnapshotterBucket(tx, ns, s.name) if bkt == nil { return errors.Wrapf(errdefs.ErrNotFound, @@ -445,10 +586,40 @@ return err } - // TODO: Consider doing this outside of transaction to lessen - // metadata lock time - return s.Snapshotter.Commit(ctx, nameKey, bkey) - }) + inheritedOpt := snapshots.WithLabels(snapshots.FilterInheritedLabels(base.Labels)) + + // NOTE: Backend snapshotters should commit fast and reliably to + // prevent metadata store locking and minimizing rollbacks. + // This operation should be done in the transaction to minimize the + // risk of the committed keys becoming out of sync. If this operation + // succeed and the overall transaction fails then the risk of out of + // sync data is higher and may require manual cleanup. + if err := s.Snapshotter.Commit(ctx, nameKey, bkey, inheritedOpt); err != nil { + if errdefs.IsNotFound(err) { + log.G(ctx).WithField("snapshotter", s.name).WithField("key", key).WithError(err).Error("uncommittable snapshot: missing in backend, snapshot should be removed") + } + // NOTE: Consider handling already exists here from the backend. Currently + // already exists from the backend may be confusing to the client since it + // may require the client to re-attempt from prepare. However, if handling + // here it is not clear what happened with the existing backend key and + // whether the already prepared snapshot would still be used or must be + // discarded. It is best that all implementations of the snapshotter + // interface behave the same, in which case the backend should handle the + // mapping of duplicates and not error. + return err + } + bname = nameKey + + return nil + }); err != nil { + if bname != "" { + log.G(ctx).WithField("snapshotter", s.name).WithField("key", key).WithField("bname", bname).WithError(err).Error("uncommittable snapshot: transaction failed after commit, snapshot should be removed") + + } + return err + } + + return nil } @@ -500,9 +671,8 @@ } // Mark snapshotter as dirty for triggering garbage collection - s.db.dirtyL.Lock() + atomic.AddUint32(&s.db.dirty, 1) s.db.dirtySS[s.name] = struct{}{} - s.db.dirtyL.Unlock() return nil }) @@ -513,7 +683,7 @@ info snapshots.Info } -func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (s *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return err @@ -525,6 +695,11 @@ lastKey string ) + filter, err := filters.ParseAll(fs...) + if err != nil { + return err + } + for { if err := view(ctx, s.db, func(tx *bolt.Tx) error { bkt := getSnapshotterBucket(tx, ns, s.name) @@ -587,8 +762,11 @@ return err } - if err := fn(ctx, overlayInfo(info, pair.info)); err != nil { - return err + info = overlayInfo(info, pair.info) + if filter.Match(adaptSnapshot(info)) { + if err := fn(ctx, info); err != nil { + return err + } } } @@ -613,18 +791,17 @@ return nil } -type cleaner interface { - Cleanup(ctx context.Context) error -} - func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err error) { s.l.Lock() t1 := time.Now() defer func() { s.l.Unlock() if err == nil { - if c, ok := s.Snapshotter.(cleaner); ok { + if c, ok := s.Snapshotter.(snapshots.Cleaner); ok { err = c.Cleanup(ctx) + if errdefs.IsNotImplemented(err) { + err = nil + } } } if err == nil { diff -Nru containerd-1.2.6/metadata/snapshot_test.go containerd-1.5.9/metadata/snapshot_test.go --- containerd-1.2.6/metadata/snapshot_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metadata/snapshot_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,13 +20,21 @@ "context" "os" "path/filepath" + "reflect" "runtime" + "sync" "testing" + "time" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/filters" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/pkg/testutil" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/native" "github.com/containerd/containerd/snapshots/testsuite" + "github.com/pkg/errors" bolt "go.etcd.io/bbolt" ) @@ -63,3 +71,364 @@ testutil.RequiresRoot(t) testsuite.SnapshotterSuite(t, "Metadata", newTestSnapshotter) } + +func TestSnapshotterWithRef(t *testing.T) { + ctx, db, done := testDB(t, withSnapshotter("tmp", func(string) (snapshots.Snapshotter, error) { + return NewTmpSnapshotter(), nil + })) + defer done() + + sn := db.Snapshotter("tmp") + + test1opt := snapshots.WithLabels( + map[string]string{ + labelSnapshotRef: "test1", + }, + ) + + _, err := sn.Prepare(ctx, "test1-tmp", "", test1opt) + if err != nil { + t.Fatal(err) + } + + err = sn.Commit(ctx, "test1", "test1-tmp", test1opt) + if err != nil { + t.Fatal(err) + } + + ctx2 := namespaces.WithNamespace(ctx, "testing2") + + _, err = sn.Prepare(ctx2, "test1-tmp", "", test1opt) + if err == nil { + t.Fatal("expected already exists error") + } else if !errdefs.IsAlreadyExists(err) { + t.Fatal(err) + } + + // test1 should now be in the namespace + _, err = sn.Stat(ctx2, "test1") + if err != nil { + t.Fatal(err) + } + + test2opt := snapshots.WithLabels( + map[string]string{ + labelSnapshotRef: "test2", + }, + ) + + _, err = sn.Prepare(ctx2, "test2-tmp", "test1", test2opt) + if err != nil { + t.Fatal(err) + } + + // In original namespace, but not committed + _, err = sn.Prepare(ctx, "test2-tmp", "test1", test2opt) + if err != nil { + t.Fatal(err) + } + + err = sn.Commit(ctx2, "test2", "test2-tmp", test2opt) + if err != nil { + t.Fatal(err) + } + + // See note in Commit function for why + // this does not return ErrAlreadyExists + err = sn.Commit(ctx, "test2", "test2-tmp", test2opt) + if err != nil { + t.Fatal(err) + } + + // This should error out, already exists in namespace + // despite mismatched parent + _, err = sn.Prepare(ctx2, "test2-tmp-again", "", test2opt) + if err == nil { + t.Fatal("expected already exists error") + } else if !errdefs.IsAlreadyExists(err) { + t.Fatal(err) + } + + // In original namespace, but already exists + _, err = sn.Prepare(ctx, "test2-tmp-again", "test1", test2opt) + if err == nil { + t.Fatal("expected already exists error") + } else if !errdefs.IsAlreadyExists(err) { + t.Fatal(err) + } + + // Now try a third namespace + + ctx3 := namespaces.WithNamespace(ctx, "testing3") + + // This should error out, matching parent not found + _, err = sn.Prepare(ctx3, "test2-tmp", "", test2opt) + if err != nil { + t.Fatal(err) + } + + // Remove, not going to use yet + err = sn.Remove(ctx3, "test2-tmp") + if err != nil { + t.Fatal(err) + } + + _, err = sn.Prepare(ctx3, "test2-tmp", "test1", test2opt) + if err == nil { + t.Fatal("expected not error") + } else if !errdefs.IsNotFound(err) { + t.Fatal(err) + } + + _, err = sn.Prepare(ctx3, "test1-tmp", "", test1opt) + if err == nil { + t.Fatal("expected already exists error") + } else if !errdefs.IsAlreadyExists(err) { + t.Fatal(err) + } + + _, err = sn.Prepare(ctx3, "test2-tmp", "test1", test2opt) + if err == nil { + t.Fatal("expected already exists error") + } else if !errdefs.IsAlreadyExists(err) { + t.Fatal(err) + } +} + +func TestFilterInheritedLabels(t *testing.T) { + tests := []struct { + labels map[string]string + expected map[string]string + }{ + { + nil, + nil, + }, + { + map[string]string{}, + map[string]string{}, + }, + { + map[string]string{"": ""}, + map[string]string{}, + }, + { + map[string]string{"foo": "bar"}, + map[string]string{}, + }, + { + map[string]string{inheritedLabelsPrefix + "foo": "bar"}, + map[string]string{inheritedLabelsPrefix + "foo": "bar"}, + }, + { + map[string]string{inheritedLabelsPrefix + "foo": "bar", "qux": "qaz"}, + map[string]string{inheritedLabelsPrefix + "foo": "bar"}, + }, + } + + for _, test := range tests { + if actual := snapshots.FilterInheritedLabels(test.labels); !reflect.DeepEqual(actual, test.expected) { + t.Fatalf("expected %v but got %v", test.expected, actual) + } + } +} + +type tmpSnapshotter struct { + l sync.Mutex + snapshots map[string]snapshots.Info + targets map[string][]string +} + +func NewTmpSnapshotter() snapshots.Snapshotter { + return &tmpSnapshotter{ + snapshots: map[string]snapshots.Info{}, + targets: map[string][]string{}, + } +} + +func (s *tmpSnapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { + s.l.Lock() + defer s.l.Unlock() + i, ok := s.snapshots[key] + if !ok { + return snapshots.Info{}, errdefs.ErrNotFound + } + return i, nil +} + +func (s *tmpSnapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { + s.l.Lock() + defer s.l.Unlock() + + i, ok := s.snapshots[info.Name] + if !ok { + return snapshots.Info{}, errdefs.ErrNotFound + } + + for k, v := range info.Labels { + i.Labels[k] = v + } + + s.snapshots[i.Name] = i + + return i, nil +} + +func (s *tmpSnapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { + s.l.Lock() + defer s.l.Unlock() + _, ok := s.snapshots[key] + if !ok { + return snapshots.Usage{}, errdefs.ErrNotFound + } + return snapshots.Usage{}, nil +} + +func (s *tmpSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { + s.l.Lock() + defer s.l.Unlock() + _, ok := s.snapshots[key] + if !ok { + return nil, errdefs.ErrNotFound + } + return []mount.Mount{}, nil +} + +func (s *tmpSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { + return s.create(ctx, key, parent, snapshots.KindActive, opts...) +} + +func (s *tmpSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { + return s.create(ctx, key, parent, snapshots.KindView, opts...) +} + +func (s *tmpSnapshotter) create(ctx context.Context, key, parent string, kind snapshots.Kind, opts ...snapshots.Opt) ([]mount.Mount, error) { + s.l.Lock() + defer s.l.Unlock() + + var base snapshots.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return nil, err + } + } + base.Name = key + base.Kind = kind + + target := base.Labels[labelSnapshotRef] + if target != "" { + for _, name := range s.targets[target] { + if s.snapshots[name].Parent == parent { + return nil, errors.Wrap(errdefs.ErrAlreadyExists, "found target") + } + } + } + + if parent != "" { + _, ok := s.snapshots[parent] + if !ok { + return nil, errdefs.ErrNotFound + } + base.Parent = parent + } + + ts := time.Now().UTC() + base.Created = ts + base.Updated = ts + + s.snapshots[base.Name] = base + + return []mount.Mount{}, nil +} + +func (s *tmpSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { + s.l.Lock() + defer s.l.Unlock() + + var base snapshots.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return err + } + } + base.Name = name + base.Kind = snapshots.KindCommitted + + if _, ok := s.snapshots[name]; ok { + return errors.Wrap(errdefs.ErrAlreadyExists, "found name") + } + + src, ok := s.snapshots[key] + if !ok { + return errdefs.ErrNotFound + } + if src.Kind == snapshots.KindCommitted { + return errdefs.ErrInvalidArgument + } + base.Parent = src.Parent + + ts := time.Now().UTC() + base.Created = ts + base.Updated = ts + + s.snapshots[name] = base + delete(s.snapshots, key) + + if target := base.Labels[labelSnapshotRef]; target != "" { + s.targets[target] = append(s.targets[target], name) + } + + return nil +} + +func (s *tmpSnapshotter) Remove(ctx context.Context, key string) error { + s.l.Lock() + defer s.l.Unlock() + + sn, ok := s.snapshots[key] + if !ok { + return errdefs.ErrNotFound + } + delete(s.snapshots, key) + + // scan and remove all instances of name as a target + for ref, names := range s.targets { + for i := range names { + if names[i] == sn.Name { + if len(names) == 1 { + delete(s.targets, ref) + } else { + copy(names[i:], names[i+1:]) + s.targets[ref] = names[:len(names)-1] + } + break + } + } + } + + return nil +} + +func (s *tmpSnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { + s.l.Lock() + defer s.l.Unlock() + + filter, err := filters.ParseAll(fs...) + if err != nil { + return err + } + + // call func for each + for _, i := range s.snapshots { + if filter.Match(adaptSnapshot(i)) { + if err := fn(ctx, i); err != nil { + return err + } + } + } + return nil +} + +func (s *tmpSnapshotter) Close() error { + return nil +} diff -Nru containerd-1.2.6/metrics/cgroups/blkio.go containerd-1.5.9/metrics/cgroups/blkio.go --- containerd-1.2.6/metrics/cgroups/blkio.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/blkio.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "strconv" - - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var blkioMetrics = []*metric{ - { - name: "blkio_io_merged_recursive", - help: "The blkio io merged recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoMergedRecursive) - }, - }, - { - name: "blkio_io_queued_recursive", - help: "The blkio io queued recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoQueuedRecursive) - }, - }, - { - name: "blkio_io_service_bytes_recursive", - help: "The blkio io service bytes recursive", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoServiceBytesRecursive) - }, - }, - { - name: "blkio_io_service_time_recursive", - help: "The blkio io servie time recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoServiceTimeRecursive) - }, - }, - { - name: "blkio_io_serviced_recursive", - help: "The blkio io servied recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoServicedRecursive) - }, - }, - { - name: "blkio_io_time_recursive", - help: "The blkio io time recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.IoTimeRecursive) - }, - }, - { - name: "blkio_sectors_recursive", - help: "The blkio sectors recursive", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"op", "device", "major", "minor"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Blkio == nil { - return nil - } - return blkioValues(stats.Blkio.SectorsRecursive) - }, - }, -} - -func blkioValues(l []*cgroups.BlkIOEntry) []value { - var out []value - for _, e := range l { - out = append(out, value{ - v: float64(e.Value), - l: []string{e.Op, e.Device, strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, - }) - } - return out -} diff -Nru containerd-1.2.6/metrics/cgroups/cgroups.go containerd-1.5.9/metrics/cgroups/cgroups.go --- containerd-1.2.6/metrics/cgroups/cgroups.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/cgroups.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,20 +19,13 @@ package cgroups import ( - "context" - "github.com/containerd/cgroups" - eventstypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" + v1 "github.com/containerd/containerd/metrics/cgroups/v1" + v2 "github.com/containerd/containerd/metrics/cgroups/v2" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime" - "github.com/containerd/containerd/runtime/v1/linux" metrics "github.com/docker/go-metrics" - "github.com/sirupsen/logrus" ) // Config for the cgroups monitor @@ -56,8 +49,15 @@ if !config.NoPrometheus { ns = metrics.NewNamespace("container", "", nil) } - collector := newCollector(ns) - oom, err := newOOMCollector(ns) + var ( + tm runtime.TaskMonitor + err error + ) + if cgroups.Mode() == cgroups.Unified { + tm, err = v2.NewTaskMonitor(ic.Context, ic.Events, ns) + } else { + tm, err = v1.NewTaskMonitor(ic.Context, ic.Events, ns) + } if err != nil { return nil, err } @@ -65,54 +65,5 @@ metrics.Register(ns) } ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) - return &cgroupsMonitor{ - collector: collector, - oom: oom, - context: ic.Context, - publisher: ic.Events, - }, nil -} - -type cgroupsMonitor struct { - collector *collector - oom *oomCollector - context context.Context - publisher events.Publisher -} - -func (m *cgroupsMonitor) Monitor(c runtime.Task) error { - if err := m.collector.Add(c); err != nil { - return err - } - t, ok := c.(*linux.Task) - if !ok { - return nil - } - cg, err := t.Cgroup() - if err != nil { - if errdefs.IsNotFound(err) { - return nil - } - return err - } - err = m.oom.Add(c.ID(), c.Namespace(), cg, m.trigger) - if err == cgroups.ErrMemoryNotSupported { - logrus.WithError(err).Warn("OOM monitoring failed") - return nil - } - return err -} - -func (m *cgroupsMonitor) Stop(c runtime.Task) error { - m.collector.Remove(c) - return nil -} - -func (m *cgroupsMonitor) trigger(id, namespace string, cg cgroups.Cgroup) { - ctx := namespaces.WithNamespace(m.context, namespace) - if err := m.publisher.Publish(ctx, runtime.TaskOOMEventTopic, &eventstypes.TaskOOM{ - ContainerID: id, - }); err != nil { - log.G(m.context).WithError(err).Error("post OOM event") - } + return tm, nil } diff -Nru containerd-1.2.6/metrics/cgroups/cpu.go containerd-1.5.9/metrics/cgroups/cpu.go --- containerd-1.2.6/metrics/cgroups/cpu.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/cpu.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "strconv" - - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var cpuMetrics = []*metric{ - { - name: "cpu_total", - help: "The total cpu time", - unit: metrics.Nanoseconds, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Usage.Total), - }, - } - }, - }, - { - name: "cpu_kernel", - help: "The total kernel cpu time", - unit: metrics.Nanoseconds, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Usage.Kernel), - }, - } - }, - }, - { - name: "cpu_user", - help: "The total user cpu time", - unit: metrics.Nanoseconds, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Usage.User), - }, - } - }, - }, - { - name: "per_cpu", - help: "The total cpu time per cpu", - unit: metrics.Nanoseconds, - vt: prometheus.GaugeValue, - labels: []string{"cpu"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - var out []value - for i, v := range stats.CPU.Usage.PerCPU { - out = append(out, value{ - v: float64(v), - l: []string{strconv.Itoa(i)}, - }) - } - return out - }, - }, - { - name: "cpu_throttle_periods", - help: "The total cpu throttle periods", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Throttling.Periods), - }, - } - }, - }, - { - name: "cpu_throttled_periods", - help: "The total cpu throttled periods", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Throttling.ThrottledPeriods), - }, - } - }, - }, - { - name: "cpu_throttled_time", - help: "The total cpu throttled time", - unit: metrics.Nanoseconds, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.CPU == nil { - return nil - } - return []value{ - { - v: float64(stats.CPU.Throttling.ThrottledTime), - }, - } - }, - }, -} diff -Nru containerd-1.2.6/metrics/cgroups/hugetlb.go containerd-1.5.9/metrics/cgroups/hugetlb.go --- containerd-1.2.6/metrics/cgroups/hugetlb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/hugetlb.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var hugetlbMetrics = []*metric{ - { - name: "hugetlb_usage", - help: "The hugetlb usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - labels: []string{"page"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Hugetlb == nil { - return nil - } - var out []value - for _, v := range stats.Hugetlb { - out = append(out, value{ - v: float64(v.Usage), - l: []string{v.Pagesize}, - }) - } - return out - }, - }, - { - name: "hugetlb_failcnt", - help: "The hugetlb failcnt", - unit: metrics.Total, - vt: prometheus.GaugeValue, - labels: []string{"page"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Hugetlb == nil { - return nil - } - var out []value - for _, v := range stats.Hugetlb { - out = append(out, value{ - v: float64(v.Failcnt), - l: []string{v.Pagesize}, - }) - } - return out - }, - }, - { - name: "hugetlb_max", - help: "The hugetlb maximum usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - labels: []string{"page"}, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Hugetlb == nil { - return nil - } - var out []value - for _, v := range stats.Hugetlb { - out = append(out, value{ - v: float64(v.Max), - l: []string{v.Pagesize}, - }) - } - return out - }, - }, -} diff -Nru containerd-1.2.6/metrics/cgroups/memory.go containerd-1.5.9/metrics/cgroups/memory.go --- containerd-1.2.6/metrics/cgroups/memory.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/memory.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,796 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var memoryMetrics = []*metric{ - { - name: "memory_cache", - help: "The cache amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Cache), - }, - } - }, - }, - { - name: "memory_rss", - help: "The rss amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.RSS), - }, - } - }, - }, - { - name: "memory_rss_huge", - help: "The rss_huge amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.RSSHuge), - }, - } - }, - }, - { - name: "memory_mapped_file", - help: "The mapped_file amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.MappedFile), - }, - } - }, - }, - { - name: "memory_dirty", - help: "The dirty amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Dirty), - }, - } - }, - }, - { - name: "memory_writeback", - help: "The writeback amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Writeback), - }, - } - }, - }, - { - name: "memory_pgpgin", - help: "The pgpgin amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.PgPgIn), - }, - } - }, - }, - { - name: "memory_pgpgout", - help: "The pgpgout amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.PgPgOut), - }, - } - }, - }, - { - name: "memory_pgfault", - help: "The pgfault amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.PgFault), - }, - } - }, - }, - { - name: "memory_pgmajfault", - help: "The pgmajfault amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.PgMajFault), - }, - } - }, - }, - { - name: "memory_inactive_anon", - help: "The inactive_anon amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.InactiveAnon), - }, - } - }, - }, - { - name: "memory_active_anon", - help: "The active_anon amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.ActiveAnon), - }, - } - }, - }, - { - name: "memory_inactive_file", - help: "The inactive_file amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.InactiveFile), - }, - } - }, - }, - { - name: "memory_active_file", - help: "The active_file amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.ActiveFile), - }, - } - }, - }, - { - name: "memory_unevictable", - help: "The unevictable amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Unevictable), - }, - } - }, - }, - { - name: "memory_hierarchical_memory_limit", - help: "The hierarchical_memory_limit amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.HierarchicalMemoryLimit), - }, - } - }, - }, - { - name: "memory_hierarchical_memsw_limit", - help: "The hierarchical_memsw_limit amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.HierarchicalSwapLimit), - }, - } - }, - }, - { - name: "memory_total_cache", - help: "The total_cache amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalCache), - }, - } - }, - }, - { - name: "memory_total_rss", - help: "The total_rss amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalRSS), - }, - } - }, - }, - { - name: "memory_total_rss_huge", - help: "The total_rss_huge amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalRSSHuge), - }, - } - }, - }, - { - name: "memory_total_mapped_file", - help: "The total_mapped_file amount used", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalMappedFile), - }, - } - }, - }, - { - name: "memory_total_dirty", - help: "The total_dirty amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalDirty), - }, - } - }, - }, - { - name: "memory_total_writeback", - help: "The total_writeback amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalWriteback), - }, - } - }, - }, - { - name: "memory_total_pgpgin", - help: "The total_pgpgin amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalPgPgIn), - }, - } - }, - }, - { - name: "memory_total_pgpgout", - help: "The total_pgpgout amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalPgPgOut), - }, - } - }, - }, - { - name: "memory_total_pgfault", - help: "The total_pgfault amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalPgFault), - }, - } - }, - }, - { - name: "memory_total_pgmajfault", - help: "The total_pgmajfault amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalPgMajFault), - }, - } - }, - }, - { - name: "memory_total_inactive_anon", - help: "The total_inactive_anon amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalInactiveAnon), - }, - } - }, - }, - { - name: "memory_total_active_anon", - help: "The total_active_anon amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalActiveAnon), - }, - } - }, - }, - { - name: "memory_total_inactive_file", - help: "The total_inactive_file amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalInactiveFile), - }, - } - }, - }, - { - name: "memory_total_active_file", - help: "The total_active_file amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalActiveFile), - }, - } - }, - }, - { - name: "memory_total_unevictable", - help: "The total_unevictable amount", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.TotalUnevictable), - }, - } - }, - }, - { - name: "memory_usage_failcnt", - help: "The usage failcnt", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Usage.Failcnt), - }, - } - }, - }, - { - name: "memory_usage_limit", - help: "The memory limit", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Usage.Limit), - }, - } - }, - }, - { - name: "memory_usage_max", - help: "The memory maximum usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Usage.Max), - }, - } - }, - }, - { - name: "memory_usage_usage", - help: "The memory usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Usage.Usage), - }, - } - }, - }, - { - name: "memory_swap_failcnt", - help: "The swap failcnt", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Swap.Failcnt), - }, - } - }, - }, - { - name: "memory_swap_limit", - help: "The swap limit", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Swap.Limit), - }, - } - }, - }, - { - name: "memory_swap_max", - help: "The swap maximum usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Swap.Max), - }, - } - }, - }, - { - name: "memory_swap_usage", - help: "The swap usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Swap.Usage), - }, - } - }, - }, - { - name: "memory_kernel_failcnt", - help: "The kernel failcnt", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Kernel.Failcnt), - }, - } - }, - }, - { - name: "memory_kernel_limit", - help: "The kernel limit", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Kernel.Limit), - }, - } - }, - }, - { - name: "memory_kernel_max", - help: "The kernel maximum usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Kernel.Max), - }, - } - }, - }, - { - name: "memory_kernel_usage", - help: "The kernel usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.Kernel.Usage), - }, - } - }, - }, - { - name: "memory_kerneltcp_failcnt", - help: "The kerneltcp failcnt", - unit: metrics.Total, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.KernelTCP.Failcnt), - }, - } - }, - }, - { - name: "memory_kerneltcp_limit", - help: "The kerneltcp limit", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.KernelTCP.Limit), - }, - } - }, - }, - { - name: "memory_kerneltcp_max", - help: "The kerneltcp maximum usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.KernelTCP.Max), - }, - } - }, - }, - { - name: "memory_kerneltcp_usage", - help: "The kerneltcp usage", - unit: metrics.Bytes, - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Memory == nil { - return nil - } - return []value{ - { - v: float64(stats.Memory.KernelTCP.Usage), - }, - } - }, - }, -} diff -Nru containerd-1.2.6/metrics/cgroups/metric.go containerd-1.5.9/metrics/cgroups/metric.go --- containerd-1.2.6/metrics/cgroups/metric.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/metric.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -type value struct { - v float64 - l []string -} - -type metric struct { - name string - help string - unit metrics.Unit - vt prometheus.ValueType - labels []string - // getValues returns the value and labels for the data - getValues func(stats *cgroups.Metrics) []value -} - -func (m *metric) desc(ns *metrics.Namespace) *prometheus.Desc { - // the namespace label is for containerd namespaces - return ns.NewDesc(m.name, m.help, m.unit, append([]string{"container_id", "namespace"}, m.labels...)...) -} - -func (m *metric) collect(id, namespace string, stats *cgroups.Metrics, ns *metrics.Namespace, ch chan<- prometheus.Metric, block bool) { - values := m.getValues(stats) - for _, v := range values { - // block signals to block on the sending the metrics so none are missed - if block { - ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...) - continue - } - // non-blocking metrics can be dropped if the chan is full - select { - case ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...): - default: - } - } -} diff -Nru containerd-1.2.6/metrics/cgroups/metrics.go containerd-1.5.9/metrics/cgroups/metrics.go --- containerd-1.2.6/metrics/cgroups/metrics.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/metrics.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "context" - "fmt" - "sync" - - "github.com/containerd/cgroups" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/runtime" - "github.com/containerd/typeurl" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -// Trigger will be called when an event happens and provides the cgroup -// where the event originated from -type Trigger func(string, string, cgroups.Cgroup) - -// newCollector registers the collector with the provided namespace and returns it so -// that cgroups can be added for collection -func newCollector(ns *metrics.Namespace) *collector { - if ns == nil { - return &collector{} - } - // add machine cpus and memory info - c := &collector{ - ns: ns, - tasks: make(map[string]runtime.Task), - } - c.metrics = append(c.metrics, pidMetrics...) - c.metrics = append(c.metrics, cpuMetrics...) - c.metrics = append(c.metrics, memoryMetrics...) - c.metrics = append(c.metrics, hugetlbMetrics...) - c.metrics = append(c.metrics, blkioMetrics...) - c.storedMetrics = make(chan prometheus.Metric, 100*len(c.metrics)) - ns.Add(c) - return c -} - -func taskID(id, namespace string) string { - return fmt.Sprintf("%s-%s", id, namespace) -} - -// collector provides the ability to collect container stats and export -// them in the prometheus format -type collector struct { - mu sync.RWMutex - - tasks map[string]runtime.Task - ns *metrics.Namespace - metrics []*metric - storedMetrics chan prometheus.Metric -} - -func (c *collector) Describe(ch chan<- *prometheus.Desc) { - for _, m := range c.metrics { - ch <- m.desc(c.ns) - } -} - -func (c *collector) Collect(ch chan<- prometheus.Metric) { - c.mu.RLock() - wg := &sync.WaitGroup{} - for _, t := range c.tasks { - wg.Add(1) - go c.collect(t, ch, true, wg) - } -storedLoop: - for { - // read stored metrics until the channel is flushed - select { - case m := <-c.storedMetrics: - ch <- m - default: - break storedLoop - } - } - c.mu.RUnlock() - wg.Wait() -} - -func (c *collector) collect(t runtime.Task, ch chan<- prometheus.Metric, block bool, wg *sync.WaitGroup) { - if wg != nil { - defer wg.Done() - } - ctx := namespaces.WithNamespace(context.Background(), t.Namespace()) - stats, err := t.Stats(ctx) - if err != nil { - log.L.WithError(err).Errorf("stat task %s", t.ID()) - return - } - data, err := typeurl.UnmarshalAny(stats) - if err != nil { - log.L.WithError(err).Errorf("unmarshal stats for %s", t.ID()) - return - } - s, ok := data.(*cgroups.Metrics) - if !ok { - log.L.WithError(err).Errorf("invalid metric type for %s", t.ID()) - return - } - for _, m := range c.metrics { - m.collect(t.ID(), t.Namespace(), s, c.ns, ch, block) - } -} - -// Add adds the provided cgroup and id so that metrics are collected and exported -func (c *collector) Add(t runtime.Task) error { - if c.ns == nil { - return nil - } - c.mu.Lock() - defer c.mu.Unlock() - id := taskID(t.ID(), t.Namespace()) - if _, ok := c.tasks[id]; ok { - return nil // requests to collect metrics should be idempotent - } - c.tasks[id] = t - return nil -} - -// Remove removes the provided cgroup by id from the collector -func (c *collector) Remove(t runtime.Task) { - if c.ns == nil { - return - } - c.mu.Lock() - defer c.mu.Unlock() - delete(c.tasks, taskID(t.ID(), t.Namespace())) -} diff -Nru containerd-1.2.6/metrics/cgroups/oom.go containerd-1.5.9/metrics/cgroups/oom.go --- containerd-1.2.6/metrics/cgroups/oom.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/oom.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "sync" - "sync/atomic" - - "golang.org/x/sys/unix" - - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" -) - -func newOOMCollector(ns *metrics.Namespace) (*oomCollector, error) { - fd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC) - if err != nil { - return nil, err - } - var desc *prometheus.Desc - if ns != nil { - desc = ns.NewDesc("memory_oom", "The number of times a container has received an oom event", metrics.Total, "container_id", "namespace") - } - c := &oomCollector{ - fd: fd, - desc: desc, - set: make(map[uintptr]*oom), - } - if ns != nil { - ns.Add(c) - } - go c.start() - return c, nil -} - -type oomCollector struct { - mu sync.Mutex - - desc *prometheus.Desc - fd int - set map[uintptr]*oom -} - -type oom struct { - // count needs to stay the first member of this struct to ensure 64bits - // alignment on a 32bits machine (e.g. arm32). This is necessary as we use - // the sync/atomic operations on this field. - count int64 - id string - namespace string - c cgroups.Cgroup - triggers []Trigger -} - -func (o *oomCollector) Add(id, namespace string, cg cgroups.Cgroup, triggers ...Trigger) error { - o.mu.Lock() - defer o.mu.Unlock() - fd, err := cg.OOMEventFD() - if err != nil { - return err - } - o.set[fd] = &oom{ - id: id, - c: cg, - triggers: triggers, - namespace: namespace, - } - event := unix.EpollEvent{ - Fd: int32(fd), - Events: unix.EPOLLHUP | unix.EPOLLIN | unix.EPOLLERR, - } - return unix.EpollCtl(o.fd, unix.EPOLL_CTL_ADD, int(fd), &event) -} - -func (o *oomCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- o.desc -} - -func (o *oomCollector) Collect(ch chan<- prometheus.Metric) { - o.mu.Lock() - defer o.mu.Unlock() - for _, t := range o.set { - c := atomic.LoadInt64(&t.count) - ch <- prometheus.MustNewConstMetric(o.desc, prometheus.CounterValue, float64(c), t.id, t.namespace) - } -} - -// Close closes the epoll fd -func (o *oomCollector) Close() error { - return unix.Close(o.fd) -} - -func (o *oomCollector) start() { - var events [128]unix.EpollEvent - for { - n, err := unix.EpollWait(o.fd, events[:], -1) - if err != nil { - if err == unix.EINTR { - continue - } - logrus.WithError(err).Error("cgroups: epoll wait failed, OOM notifications disabled") - return - } - for i := 0; i < n; i++ { - o.process(uintptr(events[i].Fd), events[i].Events) - } - } -} - -func (o *oomCollector) process(fd uintptr, event uint32) { - // make sure to always flush the fd - flush(fd) - - o.mu.Lock() - info, ok := o.set[fd] - if !ok { - o.mu.Unlock() - return - } - o.mu.Unlock() - // if we received an event but it was caused by the cgroup being deleted and the fd - // being closed make sure we close our copy and remove the container from the set - if info.c.State() == cgroups.Deleted { - o.mu.Lock() - delete(o.set, fd) - o.mu.Unlock() - unix.Close(int(fd)) - return - } - atomic.AddInt64(&info.count, 1) - for _, t := range info.triggers { - t(info.id, info.namespace, info.c) - } -} - -func flush(fd uintptr) error { - var buf [8]byte - _, err := unix.Read(int(fd), buf[:]) - return err -} diff -Nru containerd-1.2.6/metrics/cgroups/pids.go containerd-1.5.9/metrics/cgroups/pids.go --- containerd-1.2.6/metrics/cgroups/pids.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/pids.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package cgroups - -import ( - "github.com/containerd/cgroups" - metrics "github.com/docker/go-metrics" - "github.com/prometheus/client_golang/prometheus" -) - -var pidMetrics = []*metric{ - { - name: "pids", - help: "The limit to the number of pids allowed", - unit: metrics.Unit("limit"), - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Pids == nil { - return nil - } - return []value{ - { - v: float64(stats.Pids.Limit), - }, - } - }, - }, - { - name: "pids", - help: "The current number of pids", - unit: metrics.Unit("current"), - vt: prometheus.GaugeValue, - getValues: func(stats *cgroups.Metrics) []value { - if stats.Pids == nil { - return nil - } - return []value{ - { - v: float64(stats.Pids.Current), - }, - } - }, - }, -} diff -Nru containerd-1.2.6/metrics/cgroups/v1/blkio.go containerd-1.5.9/metrics/cgroups/v1/blkio.go --- containerd-1.2.6/metrics/cgroups/v1/blkio.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/blkio.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,132 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "strconv" + + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var blkioMetrics = []*metric{ + { + name: "blkio_io_merged_recursive", + help: "The blkio io merged recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoMergedRecursive) + }, + }, + { + name: "blkio_io_queued_recursive", + help: "The blkio io queued recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoQueuedRecursive) + }, + }, + { + name: "blkio_io_service_bytes_recursive", + help: "The blkio io service bytes recursive", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoServiceBytesRecursive) + }, + }, + { + name: "blkio_io_service_time_recursive", + help: "The blkio io service time recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoServiceTimeRecursive) + }, + }, + { + name: "blkio_io_serviced_recursive", + help: "The blkio io serviced recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoServicedRecursive) + }, + }, + { + name: "blkio_io_time_recursive", + help: "The blkio io time recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.IoTimeRecursive) + }, + }, + { + name: "blkio_sectors_recursive", + help: "The blkio sectors recursive", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"op", "device", "major", "minor"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Blkio == nil { + return nil + } + return blkioValues(stats.Blkio.SectorsRecursive) + }, + }, +} + +func blkioValues(l []*v1.BlkIOEntry) []value { + var out []value + for _, e := range l { + out = append(out, value{ + v: float64(e.Value), + l: []string{e.Op, e.Device, strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, + }) + } + return out +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/cgroups.go containerd-1.5.9/metrics/cgroups/v1/cgroups.go --- containerd-1.2.6/metrics/cgroups/v1/cgroups.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/cgroups.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,93 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "context" + + "github.com/containerd/cgroups" + eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/events" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/runtime" + "github.com/containerd/containerd/runtime/v1/linux" + metrics "github.com/docker/go-metrics" + "github.com/sirupsen/logrus" +) + +// NewTaskMonitor returns a new cgroups monitor +func NewTaskMonitor(ctx context.Context, publisher events.Publisher, ns *metrics.Namespace) (runtime.TaskMonitor, error) { + collector := NewCollector(ns) + oom, err := newOOMCollector(ns) + if err != nil { + return nil, err + } + return &cgroupsMonitor{ + collector: collector, + oom: oom, + context: ctx, + publisher: publisher, + }, nil +} + +type cgroupsMonitor struct { + collector *Collector + oom *oomCollector + context context.Context + publisher events.Publisher +} + +func (m *cgroupsMonitor) Monitor(c runtime.Task) error { + if err := m.collector.Add(c); err != nil { + return err + } + t, ok := c.(*linux.Task) + if !ok { + return nil + } + cg, err := t.Cgroup() + if err != nil { + if errdefs.IsNotFound(err) { + return nil + } + return err + } + err = m.oom.Add(c.ID(), c.Namespace(), cg, m.trigger) + if err == cgroups.ErrMemoryNotSupported { + logrus.WithError(err).Warn("OOM monitoring failed") + return nil + } + return err +} + +func (m *cgroupsMonitor) Stop(c runtime.Task) error { + m.collector.Remove(c) + return nil +} + +func (m *cgroupsMonitor) trigger(id, namespace string, cg cgroups.Cgroup) { + ctx := namespaces.WithNamespace(m.context, namespace) + if err := m.publisher.Publish(ctx, runtime.TaskOOMEventTopic, &eventstypes.TaskOOM{ + ContainerID: id, + }); err != nil { + log.G(m.context).WithError(err).Error("post OOM event") + } +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/cpu.go containerd-1.5.9/metrics/cgroups/v1/cpu.go --- containerd-1.2.6/metrics/cgroups/v1/cpu.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/cpu.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,146 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "strconv" + + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var cpuMetrics = []*metric{ + { + name: "cpu_total", + help: "The total cpu time", + unit: metrics.Nanoseconds, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Usage.Total), + }, + } + }, + }, + { + name: "cpu_kernel", + help: "The total kernel cpu time", + unit: metrics.Nanoseconds, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Usage.Kernel), + }, + } + }, + }, + { + name: "cpu_user", + help: "The total user cpu time", + unit: metrics.Nanoseconds, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Usage.User), + }, + } + }, + }, + { + name: "per_cpu", + help: "The total cpu time per cpu", + unit: metrics.Nanoseconds, + vt: prometheus.GaugeValue, + labels: []string{"cpu"}, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + var out []value + for i, v := range stats.CPU.Usage.PerCPU { + out = append(out, value{ + v: float64(v), + l: []string{strconv.Itoa(i)}, + }) + } + return out + }, + }, + { + name: "cpu_throttle_periods", + help: "The total cpu throttle periods", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Throttling.Periods), + }, + } + }, + }, + { + name: "cpu_throttled_periods", + help: "The total cpu throttled periods", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Throttling.ThrottledPeriods), + }, + } + }, + }, + { + name: "cpu_throttled_time", + help: "The total cpu throttled time", + unit: metrics.Nanoseconds, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.Throttling.ThrottledTime), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/hugetlb.go containerd-1.5.9/metrics/cgroups/v1/hugetlb.go --- containerd-1.2.6/metrics/cgroups/v1/hugetlb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/hugetlb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,88 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var hugetlbMetrics = []*metric{ + { + name: "hugetlb_usage", + help: "The hugetlb usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + labels: []string{"page"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Hugetlb == nil { + return nil + } + var out []value + for _, v := range stats.Hugetlb { + out = append(out, value{ + v: float64(v.Usage), + l: []string{v.Pagesize}, + }) + } + return out + }, + }, + { + name: "hugetlb_failcnt", + help: "The hugetlb failcnt", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"page"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Hugetlb == nil { + return nil + } + var out []value + for _, v := range stats.Hugetlb { + out = append(out, value{ + v: float64(v.Failcnt), + l: []string{v.Pagesize}, + }) + } + return out + }, + }, + { + name: "hugetlb_max", + help: "The hugetlb maximum usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + labels: []string{"page"}, + getValues: func(stats *v1.Metrics) []value { + if stats.Hugetlb == nil { + return nil + } + var out []value + for _, v := range stats.Hugetlb { + out = append(out, value{ + v: float64(v.Max), + l: []string{v.Pagesize}, + }) + } + return out + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/memory.go containerd-1.5.9/metrics/cgroups/v1/memory.go --- containerd-1.2.6/metrics/cgroups/v1/memory.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/memory.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,796 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var memoryMetrics = []*metric{ + { + name: "memory_cache", + help: "The cache amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Cache), + }, + } + }, + }, + { + name: "memory_rss", + help: "The rss amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.RSS), + }, + } + }, + }, + { + name: "memory_rss_huge", + help: "The rss_huge amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.RSSHuge), + }, + } + }, + }, + { + name: "memory_mapped_file", + help: "The mapped_file amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.MappedFile), + }, + } + }, + }, + { + name: "memory_dirty", + help: "The dirty amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Dirty), + }, + } + }, + }, + { + name: "memory_writeback", + help: "The writeback amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Writeback), + }, + } + }, + }, + { + name: "memory_pgpgin", + help: "The pgpgin amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.PgPgIn), + }, + } + }, + }, + { + name: "memory_pgpgout", + help: "The pgpgout amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.PgPgOut), + }, + } + }, + }, + { + name: "memory_pgfault", + help: "The pgfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.PgFault), + }, + } + }, + }, + { + name: "memory_pgmajfault", + help: "The pgmajfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.PgMajFault), + }, + } + }, + }, + { + name: "memory_inactive_anon", + help: "The inactive_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.InactiveAnon), + }, + } + }, + }, + { + name: "memory_active_anon", + help: "The active_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ActiveAnon), + }, + } + }, + }, + { + name: "memory_inactive_file", + help: "The inactive_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.InactiveFile), + }, + } + }, + }, + { + name: "memory_active_file", + help: "The active_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ActiveFile), + }, + } + }, + }, + { + name: "memory_unevictable", + help: "The unevictable amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Unevictable), + }, + } + }, + }, + { + name: "memory_hierarchical_memory_limit", + help: "The hierarchical_memory_limit amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.HierarchicalMemoryLimit), + }, + } + }, + }, + { + name: "memory_hierarchical_memsw_limit", + help: "The hierarchical_memsw_limit amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.HierarchicalSwapLimit), + }, + } + }, + }, + { + name: "memory_total_cache", + help: "The total_cache amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalCache), + }, + } + }, + }, + { + name: "memory_total_rss", + help: "The total_rss amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalRSS), + }, + } + }, + }, + { + name: "memory_total_rss_huge", + help: "The total_rss_huge amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalRSSHuge), + }, + } + }, + }, + { + name: "memory_total_mapped_file", + help: "The total_mapped_file amount used", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalMappedFile), + }, + } + }, + }, + { + name: "memory_total_dirty", + help: "The total_dirty amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalDirty), + }, + } + }, + }, + { + name: "memory_total_writeback", + help: "The total_writeback amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalWriteback), + }, + } + }, + }, + { + name: "memory_total_pgpgin", + help: "The total_pgpgin amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalPgPgIn), + }, + } + }, + }, + { + name: "memory_total_pgpgout", + help: "The total_pgpgout amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalPgPgOut), + }, + } + }, + }, + { + name: "memory_total_pgfault", + help: "The total_pgfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalPgFault), + }, + } + }, + }, + { + name: "memory_total_pgmajfault", + help: "The total_pgmajfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalPgMajFault), + }, + } + }, + }, + { + name: "memory_total_inactive_anon", + help: "The total_inactive_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalInactiveAnon), + }, + } + }, + }, + { + name: "memory_total_active_anon", + help: "The total_active_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalActiveAnon), + }, + } + }, + }, + { + name: "memory_total_inactive_file", + help: "The total_inactive_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalInactiveFile), + }, + } + }, + }, + { + name: "memory_total_active_file", + help: "The total_active_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalActiveFile), + }, + } + }, + }, + { + name: "memory_total_unevictable", + help: "The total_unevictable amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.TotalUnevictable), + }, + } + }, + }, + { + name: "memory_usage_failcnt", + help: "The usage failcnt", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage.Failcnt), + }, + } + }, + }, + { + name: "memory_usage_limit", + help: "The memory limit", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage.Limit), + }, + } + }, + }, + { + name: "memory_usage_max", + help: "The memory maximum usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage.Max), + }, + } + }, + }, + { + name: "memory_usage_usage", + help: "The memory usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage.Usage), + }, + } + }, + }, + { + name: "memory_swap_failcnt", + help: "The swap failcnt", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Swap.Failcnt), + }, + } + }, + }, + { + name: "memory_swap_limit", + help: "The swap limit", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Swap.Limit), + }, + } + }, + }, + { + name: "memory_swap_max", + help: "The swap maximum usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Swap.Max), + }, + } + }, + }, + { + name: "memory_swap_usage", + help: "The swap usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Swap.Usage), + }, + } + }, + }, + { + name: "memory_kernel_failcnt", + help: "The kernel failcnt", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Kernel.Failcnt), + }, + } + }, + }, + { + name: "memory_kernel_limit", + help: "The kernel limit", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Kernel.Limit), + }, + } + }, + }, + { + name: "memory_kernel_max", + help: "The kernel maximum usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Kernel.Max), + }, + } + }, + }, + { + name: "memory_kernel_usage", + help: "The kernel usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Kernel.Usage), + }, + } + }, + }, + { + name: "memory_kerneltcp_failcnt", + help: "The kerneltcp failcnt", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.KernelTCP.Failcnt), + }, + } + }, + }, + { + name: "memory_kerneltcp_limit", + help: "The kerneltcp limit", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.KernelTCP.Limit), + }, + } + }, + }, + { + name: "memory_kerneltcp_max", + help: "The kerneltcp maximum usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.KernelTCP.Max), + }, + } + }, + }, + { + name: "memory_kerneltcp_usage", + help: "The kerneltcp usage", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.KernelTCP.Usage), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/metric.go containerd-1.5.9/metrics/cgroups/v1/metric.go --- containerd-1.2.6/metrics/cgroups/v1/metric.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/metric.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,64 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +// IDName is the name that is used to identify the id being collected in the metric +var IDName = "container_id" + +type value struct { + v float64 + l []string +} + +type metric struct { + name string + help string + unit metrics.Unit + vt prometheus.ValueType + labels []string + // getValues returns the value and labels for the data + getValues func(stats *v1.Metrics) []value +} + +func (m *metric) desc(ns *metrics.Namespace) *prometheus.Desc { + // the namespace label is for containerd namespaces + return ns.NewDesc(m.name, m.help, m.unit, append([]string{IDName, "namespace"}, m.labels...)...) +} + +func (m *metric) collect(id, namespace string, stats *v1.Metrics, ns *metrics.Namespace, ch chan<- prometheus.Metric, block bool) { + values := m.getValues(stats) + for _, v := range values { + // block signals to block on the sending the metrics so none are missed + if block { + ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...) + continue + } + // non-blocking metrics can be dropped if the chan is full + select { + case ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...): + default: + } + } +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/metrics.go containerd-1.5.9/metrics/cgroups/v1/metrics.go --- containerd-1.2.6/metrics/cgroups/v1/metrics.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/metrics.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,170 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + "sync" + + "github.com/containerd/cgroups" + "github.com/containerd/containerd/log" + v1 "github.com/containerd/containerd/metrics/types/v1" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/typeurl" + metrics "github.com/docker/go-metrics" + "github.com/gogo/protobuf/types" + "github.com/prometheus/client_golang/prometheus" +) + +// Statable type that returns cgroup metrics +type Statable interface { + ID() string + Namespace() string + Stats(context.Context) (*types.Any, error) +} + +// Trigger will be called when an event happens and provides the cgroup +// where the event originated from +type Trigger func(string, string, cgroups.Cgroup) + +// NewCollector registers the collector with the provided namespace and returns it so +// that cgroups can be added for collection +func NewCollector(ns *metrics.Namespace) *Collector { + if ns == nil { + return &Collector{} + } + // add machine cpus and memory info + c := &Collector{ + ns: ns, + tasks: make(map[string]Statable), + } + c.metrics = append(c.metrics, pidMetrics...) + c.metrics = append(c.metrics, cpuMetrics...) + c.metrics = append(c.metrics, memoryMetrics...) + c.metrics = append(c.metrics, hugetlbMetrics...) + c.metrics = append(c.metrics, blkioMetrics...) + c.storedMetrics = make(chan prometheus.Metric, 100*len(c.metrics)) + ns.Add(c) + return c +} + +func taskID(id, namespace string) string { + return fmt.Sprintf("%s-%s", id, namespace) +} + +// Collector provides the ability to collect container stats and export +// them in the prometheus format +type Collector struct { + mu sync.RWMutex + + tasks map[string]Statable + ns *metrics.Namespace + metrics []*metric + storedMetrics chan prometheus.Metric +} + +// Describe prometheus metrics +func (c *Collector) Describe(ch chan<- *prometheus.Desc) { + for _, m := range c.metrics { + ch <- m.desc(c.ns) + } +} + +// Collect prometheus metrics +func (c *Collector) Collect(ch chan<- prometheus.Metric) { + c.mu.RLock() + wg := &sync.WaitGroup{} + for _, t := range c.tasks { + wg.Add(1) + go c.collect(t, ch, true, wg) + } +storedLoop: + for { + // read stored metrics until the channel is flushed + select { + case m := <-c.storedMetrics: + ch <- m + default: + break storedLoop + } + } + c.mu.RUnlock() + wg.Wait() +} + +func (c *Collector) collect(t Statable, ch chan<- prometheus.Metric, block bool, wg *sync.WaitGroup) { + if wg != nil { + defer wg.Done() + } + ctx := namespaces.WithNamespace(context.Background(), t.Namespace()) + stats, err := t.Stats(ctx) + if err != nil { + log.L.WithError(err).Errorf("stat task %s", t.ID()) + return + } + data, err := typeurl.UnmarshalAny(stats) + if err != nil { + log.L.WithError(err).Errorf("unmarshal stats for %s", t.ID()) + return + } + s, ok := data.(*v1.Metrics) + if !ok { + log.L.WithError(err).Errorf("invalid metric type for %s", t.ID()) + return + } + for _, m := range c.metrics { + m.collect(t.ID(), t.Namespace(), s, c.ns, ch, block) + } +} + +// Add adds the provided cgroup and id so that metrics are collected and exported +func (c *Collector) Add(t Statable) error { + if c.ns == nil { + return nil + } + c.mu.Lock() + defer c.mu.Unlock() + id := taskID(t.ID(), t.Namespace()) + if _, ok := c.tasks[id]; ok { + return nil // requests to collect metrics should be idempotent + } + c.tasks[id] = t + return nil +} + +// Remove removes the provided cgroup by id from the collector +func (c *Collector) Remove(t Statable) { + if c.ns == nil { + return + } + c.mu.Lock() + delete(c.tasks, taskID(t.ID(), t.Namespace())) + c.mu.Unlock() +} + +// RemoveAll statable items from the collector +func (c *Collector) RemoveAll() { + if c.ns == nil { + return + } + c.mu.Lock() + c.tasks = make(map[string]Statable) + c.mu.Unlock() +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/oom.go containerd-1.5.9/metrics/cgroups/v1/oom.go --- containerd-1.2.6/metrics/cgroups/v1/oom.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/oom.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,158 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "sync" + "sync/atomic" + + "golang.org/x/sys/unix" + + "github.com/containerd/cgroups" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" + "github.com/sirupsen/logrus" +) + +func newOOMCollector(ns *metrics.Namespace) (*oomCollector, error) { + fd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC) + if err != nil { + return nil, err + } + var desc *prometheus.Desc + if ns != nil { + desc = ns.NewDesc("memory_oom", "The number of times a container has received an oom event", metrics.Total, "container_id", "namespace") + } + c := &oomCollector{ + fd: fd, + desc: desc, + set: make(map[uintptr]*oom), + } + if ns != nil { + ns.Add(c) + } + go c.start() + return c, nil +} + +type oomCollector struct { + mu sync.Mutex + + desc *prometheus.Desc + fd int + set map[uintptr]*oom +} + +type oom struct { + // count needs to stay the first member of this struct to ensure 64bits + // alignment on a 32bits machine (e.g. arm32). This is necessary as we use + // the sync/atomic operations on this field. + count int64 + id string + namespace string + c cgroups.Cgroup + triggers []Trigger +} + +func (o *oomCollector) Add(id, namespace string, cg cgroups.Cgroup, triggers ...Trigger) error { + o.mu.Lock() + defer o.mu.Unlock() + fd, err := cg.OOMEventFD() + if err != nil { + return err + } + o.set[fd] = &oom{ + id: id, + c: cg, + triggers: triggers, + namespace: namespace, + } + event := unix.EpollEvent{ + Fd: int32(fd), + Events: unix.EPOLLHUP | unix.EPOLLIN | unix.EPOLLERR, + } + return unix.EpollCtl(o.fd, unix.EPOLL_CTL_ADD, int(fd), &event) +} + +func (o *oomCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- o.desc +} + +func (o *oomCollector) Collect(ch chan<- prometheus.Metric) { + o.mu.Lock() + defer o.mu.Unlock() + for _, t := range o.set { + c := atomic.LoadInt64(&t.count) + ch <- prometheus.MustNewConstMetric(o.desc, prometheus.CounterValue, float64(c), t.id, t.namespace) + } +} + +// Close closes the epoll fd +func (o *oomCollector) Close() error { + return unix.Close(o.fd) +} + +func (o *oomCollector) start() { + var events [128]unix.EpollEvent + for { + n, err := unix.EpollWait(o.fd, events[:], -1) + if err != nil { + if err == unix.EINTR { + continue + } + logrus.WithError(err).Error("cgroups: epoll wait failed, OOM notifications disabled") + return + } + for i := 0; i < n; i++ { + o.process(uintptr(events[i].Fd), events[i].Events) + } + } +} + +func (o *oomCollector) process(fd uintptr, event uint32) { + // make sure to always flush the fd + flush(fd) + + o.mu.Lock() + info, ok := o.set[fd] + if !ok { + o.mu.Unlock() + return + } + o.mu.Unlock() + // if we received an event but it was caused by the cgroup being deleted and the fd + // being closed make sure we close our copy and remove the container from the set + if info.c.State() == cgroups.Deleted { + o.mu.Lock() + delete(o.set, fd) + o.mu.Unlock() + unix.Close(int(fd)) + return + } + atomic.AddInt64(&info.count, 1) + for _, t := range info.triggers { + t(info.id, info.namespace, info.c) + } +} + +func flush(fd uintptr) error { + var buf [8]byte + _, err := unix.Read(int(fd), buf[:]) + return err +} diff -Nru containerd-1.2.6/metrics/cgroups/v1/pids.go containerd-1.5.9/metrics/cgroups/v1/pids.go --- containerd-1.2.6/metrics/cgroups/v1/pids.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v1/pids.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + v1 "github.com/containerd/containerd/metrics/types/v1" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var pidMetrics = []*metric{ + { + name: "pids", + help: "The limit to the number of pids allowed", + unit: metrics.Unit("limit"), + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Pids == nil { + return nil + } + return []value{ + { + v: float64(stats.Pids.Limit), + }, + } + }, + }, + { + name: "pids", + help: "The current number of pids", + unit: metrics.Unit("current"), + vt: prometheus.GaugeValue, + getValues: func(stats *v1.Metrics) []value { + if stats.Pids == nil { + return nil + } + return []value{ + { + v: float64(stats.Pids.Current), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/cgroups.go containerd-1.5.9/metrics/cgroups/v2/cgroups.go --- containerd-1.2.6/metrics/cgroups/v2/cgroups.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/cgroups.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + + "github.com/containerd/containerd/events" + "github.com/containerd/containerd/runtime" + metrics "github.com/docker/go-metrics" +) + +// NewTaskMonitor returns a new cgroups monitor +func NewTaskMonitor(ctx context.Context, publisher events.Publisher, ns *metrics.Namespace) (runtime.TaskMonitor, error) { + collector := NewCollector(ns) + return &cgroupsMonitor{ + collector: collector, + context: ctx, + publisher: publisher, + }, nil +} + +type cgroupsMonitor struct { + collector *Collector + context context.Context + publisher events.Publisher +} + +func (m *cgroupsMonitor) Monitor(c runtime.Task) error { + if err := m.collector.Add(c); err != nil { + return err + } + return nil +} + +func (m *cgroupsMonitor) Stop(c runtime.Task) error { + m.collector.Remove(c) + return nil +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/cpu.go containerd-1.5.9/metrics/cgroups/v2/cpu.go --- containerd-1.2.6/metrics/cgroups/v2/cpu.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/cpu.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,124 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var cpuMetrics = []*metric{ + { + name: "cpu_usage_usec", + help: "Total cpu usage (cgroup v2)", + unit: metrics.Unit("microseconds"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.UsageUsec), + }, + } + }, + }, + { + name: "cpu_user_usec", + help: "Current cpu usage in user space (cgroup v2)", + unit: metrics.Unit("microseconds"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.UserUsec), + }, + } + }, + }, + { + name: "cpu_system_usec", + help: "Current cpu usage in kernel space (cgroup v2)", + unit: metrics.Unit("microseconds"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.SystemUsec), + }, + } + }, + }, + { + name: "cpu_nr_periods", + help: "Current cpu number of periods (only if controller is enabled)", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.NrPeriods), + }, + } + }, + }, + { + name: "cpu_nr_throttled", + help: "Total number of times tasks have been throttled (only if controller is enabled)", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.NrThrottled), + }, + } + }, + }, + { + name: "cpu_throttled_usec", + help: "Total time duration for which tasks have been throttled. (only if controller is enabled)", + unit: metrics.Unit("microseconds"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.CPU == nil { + return nil + } + return []value{ + { + v: float64(stats.CPU.ThrottledUsec), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/io.go containerd-1.5.9/metrics/cgroups/v2/io.go --- containerd-1.2.6/metrics/cgroups/v2/io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,110 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "strconv" + + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var ioMetrics = []*metric{ + { + name: "io_rbytes", + help: "IO bytes read", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + labels: []string{"major", "minor"}, + getValues: func(stats *v2.Metrics) []value { + if stats.Io == nil { + return nil + } + var out []value + for _, e := range stats.Io.Usage { + out = append(out, value{ + v: float64(e.Rbytes), + l: []string{strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, + }) + } + return out + }, + }, + { + name: "io_wbytes", + help: "IO bytes written", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + labels: []string{"major", "minor"}, + getValues: func(stats *v2.Metrics) []value { + if stats.Io == nil { + return nil + } + var out []value + for _, e := range stats.Io.Usage { + out = append(out, value{ + v: float64(e.Wbytes), + l: []string{strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, + }) + } + return out + }, + }, + { + name: "io_rios", + help: "Number of read IOs", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"major", "minor"}, + getValues: func(stats *v2.Metrics) []value { + if stats.Io == nil { + return nil + } + var out []value + for _, e := range stats.Io.Usage { + out = append(out, value{ + v: float64(e.Rios), + l: []string{strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, + }) + } + return out + }, + }, + { + name: "io_wios", + help: "Number of write IOs", + unit: metrics.Total, + vt: prometheus.GaugeValue, + labels: []string{"major", "minor"}, + getValues: func(stats *v2.Metrics) []value { + if stats.Io == nil { + return nil + } + var out []value + for _, e := range stats.Io.Usage { + out = append(out, value{ + v: float64(e.Wios), + l: []string{strconv.FormatUint(e.Major, 10), strconv.FormatUint(e.Minor, 10)}, + }) + } + return out + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/memory.go containerd-1.5.9/metrics/cgroups/v2/memory.go --- containerd-1.2.6/metrics/cgroups/v2/memory.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/memory.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,605 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var memoryMetrics = []*metric{ + { + name: "memory_usage", + help: "Current memory usage (cgroup v2)", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Usage), + }, + } + }, + }, + { + name: "memory_usage_limit", + help: "Current memory usage limit (cgroup v2)", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.UsageLimit), + }, + } + }, + }, + { + name: "memory_swap_usage", + help: "Current swap usage (cgroup v2)", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SwapUsage), + }, + } + }, + }, + { + name: "memory_swap_limit", + help: "Current swap usage limit (cgroup v2)", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SwapLimit), + }, + } + }, + }, + + { + name: "memory_file_mapped", + help: "The file_mapped amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.FileMapped), + }, + } + }, + }, + { + name: "memory_file_dirty", + help: "The file_dirty amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.FileDirty), + }, + } + }, + }, + { + name: "memory_file_writeback", + help: "The file_writeback amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.FileWriteback), + }, + } + }, + }, + { + name: "memory_pgactivate", + help: "The pgactivate amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgactivate), + }, + } + }, + }, + { + name: "memory_pgdeactivate", + help: "The pgdeactivate amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgdeactivate), + }, + } + }, + }, + { + name: "memory_pgfault", + help: "The pgfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgfault), + }, + } + }, + }, + { + name: "memory_pgmajfault", + help: "The pgmajfault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgmajfault), + }, + } + }, + }, + { + name: "memory_pglazyfree", + help: "The pglazyfree amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pglazyfree), + }, + } + }, + }, + { + name: "memory_pgrefill", + help: "The pgrefill amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgrefill), + }, + } + }, + }, + { + name: "memory_pglazyfreed", + help: "The pglazyfreed amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pglazyfreed), + }, + } + }, + }, + { + name: "memory_pgscan", + help: "The pgscan amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgscan), + }, + } + }, + }, + { + name: "memory_pgsteal", + help: "The pgsteal amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Pgsteal), + }, + } + }, + }, + { + name: "memory_inactive_anon", + help: "The inactive_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.InactiveAnon), + }, + } + }, + }, + { + name: "memory_active_anon", + help: "The active_anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ActiveAnon), + }, + } + }, + }, + { + name: "memory_inactive_file", + help: "The inactive_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.InactiveFile), + }, + } + }, + }, + { + name: "memory_active_file", + help: "The active_file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ActiveFile), + }, + } + }, + }, + { + name: "memory_unevictable", + help: "The unevictable amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Unevictable), + }, + } + }, + }, + { + name: "memory_anon", + help: "The anon amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Anon), + }, + } + }, + }, + { + name: "memory_file", + help: "The file amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.File), + }, + } + }, + }, + { + name: "memory_kernel_stack", + help: "The kernel_stack amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.KernelStack), + }, + } + }, + }, + { + name: "memory_slab", + help: "The slab amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Slab), + }, + } + }, + }, + { + name: "memory_sock", + help: "The sock amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Sock), + }, + } + }, + }, + { + name: "memory_shmem", + help: "The shmem amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.Shmem), + }, + } + }, + }, + { + name: "memory_anon_thp", + help: "The anon_thp amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.AnonThp), + }, + } + }, + }, + { + name: "memory_slab_reclaimable", + help: "The slab_reclaimable amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SlabReclaimable), + }, + } + }, + }, + { + name: "memory_slab_unreclaimable", + help: "The slab_unreclaimable amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.SlabUnreclaimable), + }, + } + }, + }, + { + name: "memory_workingset_refault", + help: "The workingset_refault amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.WorkingsetRefault), + }, + } + }, + }, + { + name: "memory_workingset_activate", + help: "The workingset_activate amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.WorkingsetActivate), + }, + } + }, + }, + { + name: "memory_workingset_nodereclaim", + help: "The workingset_nodereclaim amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.WorkingsetNodereclaim), + }, + } + }, + }, + { + name: "memory_thp_fault_alloc", + help: "The thp_fault_alloc amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ThpFaultAlloc), + }, + } + }, + }, + { + name: "memory_thp_collapse_alloc", + help: "The thp_collapse_alloc amount", + unit: metrics.Bytes, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Memory == nil { + return nil + } + return []value{ + { + v: float64(stats.Memory.ThpCollapseAlloc), + }, + } + }, + }, + { + name: "memory_oom", + help: "The number of times a container has received an oom event", + unit: metrics.Total, + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.MemoryEvents == nil { + return nil + } + return []value{ + { + v: float64(stats.MemoryEvents.Oom), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/metric.go containerd-1.5.9/metrics/cgroups/v2/metric.go --- containerd-1.2.6/metrics/cgroups/v2/metric.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/metric.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,64 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +// IDName is the name that is used to identify the id being collected in the metric +var IDName = "container_id" + +type value struct { + v float64 + l []string +} + +type metric struct { + name string + help string + unit metrics.Unit + vt prometheus.ValueType + labels []string + // getValues returns the value and labels for the data + getValues func(stats *v2.Metrics) []value +} + +func (m *metric) desc(ns *metrics.Namespace) *prometheus.Desc { + // the namespace label is for containerd namespaces + return ns.NewDesc(m.name, m.help, m.unit, append([]string{IDName, "namespace"}, m.labels...)...) +} + +func (m *metric) collect(id, namespace string, stats *v2.Metrics, ns *metrics.Namespace, ch chan<- prometheus.Metric, block bool) { + values := m.getValues(stats) + for _, v := range values { + // block signals to block on the sending the metrics so none are missed + if block { + ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...) + continue + } + // non-blocking metrics can be dropped if the chan is full + select { + case ch <- prometheus.MustNewConstMetric(m.desc(ns), m.vt, v.v, append([]string{id, namespace}, v.l...)...): + default: + } + } +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/metrics.go containerd-1.5.9/metrics/cgroups/v2/metrics.go --- containerd-1.2.6/metrics/cgroups/v2/metrics.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/metrics.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,163 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + "fmt" + "sync" + + "github.com/containerd/containerd/log" + v2 "github.com/containerd/containerd/metrics/types/v2" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/typeurl" + metrics "github.com/docker/go-metrics" + "github.com/gogo/protobuf/types" + "github.com/prometheus/client_golang/prometheus" +) + +// Statable type that returns cgroup metrics +type Statable interface { + ID() string + Namespace() string + Stats(context.Context) (*types.Any, error) +} + +// NewCollector registers the collector with the provided namespace and returns it so +// that cgroups can be added for collection +func NewCollector(ns *metrics.Namespace) *Collector { + if ns == nil { + return &Collector{} + } + c := &Collector{ + ns: ns, + tasks: make(map[string]Statable), + } + c.metrics = append(c.metrics, pidMetrics...) + c.metrics = append(c.metrics, cpuMetrics...) + c.metrics = append(c.metrics, memoryMetrics...) + c.metrics = append(c.metrics, ioMetrics...) + c.storedMetrics = make(chan prometheus.Metric, 100*len(c.metrics)) + ns.Add(c) + return c +} + +func taskID(id, namespace string) string { + return fmt.Sprintf("%s-%s", id, namespace) +} + +// Collector provides the ability to collect container stats and export +// them in the prometheus format +type Collector struct { + mu sync.RWMutex + + tasks map[string]Statable + ns *metrics.Namespace + metrics []*metric + storedMetrics chan prometheus.Metric +} + +// Describe prometheus metrics +func (c *Collector) Describe(ch chan<- *prometheus.Desc) { + for _, m := range c.metrics { + ch <- m.desc(c.ns) + } +} + +// Collect prometheus metrics +func (c *Collector) Collect(ch chan<- prometheus.Metric) { + c.mu.RLock() + wg := &sync.WaitGroup{} + for _, t := range c.tasks { + wg.Add(1) + go c.collect(t, ch, true, wg) + } +storedLoop: + for { + // read stored metrics until the channel is flushed + select { + case m := <-c.storedMetrics: + ch <- m + default: + break storedLoop + } + } + c.mu.RUnlock() + wg.Wait() +} + +func (c *Collector) collect(t Statable, ch chan<- prometheus.Metric, block bool, wg *sync.WaitGroup) { + if wg != nil { + defer wg.Done() + } + ctx := namespaces.WithNamespace(context.Background(), t.Namespace()) + stats, err := t.Stats(ctx) + if err != nil { + log.L.WithError(err).Errorf("stat task %s", t.ID()) + return + } + data, err := typeurl.UnmarshalAny(stats) + if err != nil { + log.L.WithError(err).Errorf("unmarshal stats for %s", t.ID()) + return + } + s, ok := data.(*v2.Metrics) + if !ok { + log.L.WithError(err).Errorf("invalid metric type for %s", t.ID()) + return + } + for _, m := range c.metrics { + m.collect(t.ID(), t.Namespace(), s, c.ns, ch, block) + } +} + +// Add adds the provided cgroup and id so that metrics are collected and exported +func (c *Collector) Add(t Statable) error { + if c.ns == nil { + return nil + } + c.mu.Lock() + defer c.mu.Unlock() + id := taskID(t.ID(), t.Namespace()) + if _, ok := c.tasks[id]; ok { + return nil // requests to collect metrics should be idempotent + } + c.tasks[id] = t + return nil +} + +// Remove removes the provided cgroup by id from the collector +func (c *Collector) Remove(t Statable) { + if c.ns == nil { + return + } + c.mu.Lock() + defer c.mu.Unlock() + delete(c.tasks, taskID(t.ID(), t.Namespace())) +} + +// RemoveAll statable items from the collector +func (c *Collector) RemoveAll() { + if c.ns == nil { + return + } + c.mu.Lock() + c.tasks = make(map[string]Statable) + c.mu.Unlock() +} diff -Nru containerd-1.2.6/metrics/cgroups/v2/pids.go containerd-1.5.9/metrics/cgroups/v2/pids.go --- containerd-1.2.6/metrics/cgroups/v2/pids.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/cgroups/v2/pids.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/containerd/metrics/types/v2" + metrics "github.com/docker/go-metrics" + "github.com/prometheus/client_golang/prometheus" +) + +var pidMetrics = []*metric{ + { + name: "pids", + help: "The limit to the number of pids allowed (cgroup v2)", + unit: metrics.Unit("limit"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Pids == nil { + return nil + } + return []value{ + { + v: float64(stats.Pids.Limit), + }, + } + }, + }, + { + name: "pids", + help: "The current number of pids (cgroup v2)", + unit: metrics.Unit("current"), + vt: prometheus.GaugeValue, + getValues: func(stats *v2.Metrics) []value { + if stats.Pids == nil { + return nil + } + return []value{ + { + v: float64(stats.Pids.Current), + }, + } + }, + }, +} diff -Nru containerd-1.2.6/metrics/types/v1/types.go containerd-1.5.9/metrics/types/v1/types.go --- containerd-1.2.6/metrics/types/v1/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/types/v1/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + v1 "github.com/containerd/cgroups/stats/v1" +) + +type ( + // Metrics alias + Metrics = v1.Metrics + // BlkIOEntry alias + BlkIOEntry = v1.BlkIOEntry + // MemoryStat alias + MemoryStat = v1.MemoryStat + // CPUStat alias + CPUStat = v1.CPUStat + // CPUUsage alias + CPUUsage = v1.CPUUsage + // BlkIOStat alias + BlkIOStat = v1.BlkIOStat + // PidsStat alias + PidsStat = v1.PidsStat + // RdmaStat alias + RdmaStat = v1.RdmaStat + // RdmaEntry alias + RdmaEntry = v1.RdmaEntry + // HugetlbStat alias + HugetlbStat = v1.HugetlbStat +) diff -Nru containerd-1.2.6/metrics/types/v2/types.go containerd-1.5.9/metrics/types/v2/types.go --- containerd-1.2.6/metrics/types/v2/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/metrics/types/v2/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + v2 "github.com/containerd/cgroups/v2/stats" +) + +type ( + // Metrics alias + Metrics = v2.Metrics + // MemoryStat alias + MemoryStat = v2.MemoryStat + // CPUStat alias + CPUStat = v2.CPUStat + // PidsStat alias + PidsStat = v2.PidsStat + // IOStat alias + IOStat = v2.IOStat +) diff -Nru containerd-1.2.6/mount/lookup_linux_test.go containerd-1.5.9/mount/lookup_linux_test.go --- containerd-1.2.6/mount/lookup_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/lookup_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,7 +31,7 @@ // so we use continuity/testutil instead. "github.com/containerd/continuity/testutil" "github.com/containerd/continuity/testutil/loopback" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) func checkLookup(t *testing.T, fsType, mntPoint, dir string) { @@ -50,25 +50,25 @@ } defer os.RemoveAll(mnt) - deviceName, cleanupDevice, err := loopback.New(100 << 20) // 100 MB + loop, err := loopback.New(100 << 20) // 100 MB if err != nil { t.Fatal(err) } - if out, err := exec.Command("mkfs", "-t", fsType, deviceName).CombinedOutput(); err != nil { + if out, err := exec.Command("mkfs", "-t", fsType, loop.Device).CombinedOutput(); err != nil { // not fatal - cleanupDevice() - t.Skipf("could not mkfs (%s) %s: %v (out: %q)", fsType, deviceName, err, string(out)) + loop.Close() + t.Skipf("could not mkfs (%s) %s: %v (out: %q)", fsType, loop.Device, err, string(out)) } - if out, err := exec.Command("mount", deviceName, mnt).CombinedOutput(); err != nil { + if out, err := exec.Command("mount", loop.Device, mnt).CombinedOutput(); err != nil { // not fatal - cleanupDevice() - t.Skipf("could not mount %s: %v (out: %q)", deviceName, err, string(out)) + loop.Close() + t.Skipf("could not mount %s: %v (out: %q)", loop.Device, err, string(out)) } defer func() { testutil.Unmount(t, mnt) - cleanupDevice() + loop.Close() }() - assert.Check(t, strings.HasPrefix(deviceName, "/dev/loop")) + assert.Check(t, strings.HasPrefix(loop.Device, "/dev/loop")) checkLookup(t, fsType, mnt, mnt) newMnt, err := ioutil.TempDir("", "containerd-mountinfo-test-newMnt") diff -Nru containerd-1.2.6/mount/lookup_unix.go containerd-1.5.9/mount/lookup_unix.go --- containerd-1.2.6/mount/lookup_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/lookup_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,9 +20,8 @@ import ( "path/filepath" - "sort" - "strings" + "github.com/moby/sys/mountinfo" "github.com/pkg/errors" ) @@ -30,24 +29,21 @@ func Lookup(dir string) (Info, error) { dir = filepath.Clean(dir) - mounts, err := Self() + m, err := mountinfo.GetMounts(mountinfo.ParentsFilter(dir)) if err != nil { - return Info{}, err + return Info{}, errors.Wrapf(err, "failed to find the mount info for %q", dir) + } + if len(m) == 0 { + return Info{}, errors.Errorf("failed to find the mount info for %q", dir) } - // Sort descending order by Info.Mountpoint - sort.SliceStable(mounts, func(i, j int) bool { - return mounts[j].Mountpoint < mounts[i].Mountpoint - }) - for _, m := range mounts { - // Note that m.{Major, Minor} are generally unreliable for our purpose here - // https://www.spinics.net/lists/linux-btrfs/msg58908.html - // Note that device number is not checked here, because for overlayfs files - // may have different device number with the mountpoint. - if strings.HasPrefix(dir, m.Mountpoint) { - return m, nil + // find the longest matching mount point + var idx, maxlen int + for i := range m { + if len(m[i].Mountpoint) > maxlen { + maxlen = len(m[i].Mountpoint) + idx = i } } - - return Info{}, errors.Errorf("failed to find the mount info for %q", dir) + return *m[idx], nil } diff -Nru containerd-1.2.6/mount/losetup_linux.go containerd-1.5.9/mount/losetup_linux.go --- containerd-1.2.6/mount/losetup_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/mount/losetup_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,208 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package mount + +import ( + "fmt" + "math/rand" + "os" + "strings" + "syscall" + "time" + "unsafe" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const ( + loopControlPath = "/dev/loop-control" + loopDevFormat = "/dev/loop%d" + + ebusyString = "device or resource busy" +) + +// LoopParams parameters to control loop device setup +type LoopParams struct { + // Loop device should forbid write + Readonly bool + // Loop device is automatically cleared by kernel when the + // last opener closes it + Autoclear bool + // Use direct IO to access the loop backing file + Direct bool +} + +func ioctl(fd, req, args uintptr) (uintptr, uintptr, error) { + r1, r2, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, req, args) + if errno != 0 { + return 0, 0, errno + } + + return r1, r2, nil +} + +func getFreeLoopDev() (uint32, error) { + ctrl, err := os.OpenFile(loopControlPath, os.O_RDWR, 0) + if err != nil { + return 0, errors.Errorf("could not open %v: %v", loopControlPath, err) + } + defer ctrl.Close() + num, _, err := ioctl(ctrl.Fd(), unix.LOOP_CTL_GET_FREE, 0) + if err != nil { + return 0, errors.Wrap(err, "could not get free loop device") + } + return uint32(num), nil +} + +// setupLoopDev attaches the backing file to the loop device and returns +// the file handle for the loop device. The caller is responsible for +// closing the file handle. +func setupLoopDev(backingFile, loopDev string, param LoopParams) (_ *os.File, retErr error) { + // 1. Open backing file and loop device + flags := os.O_RDWR + if param.Readonly { + flags = os.O_RDONLY + } + + back, err := os.OpenFile(backingFile, flags, 0) + if err != nil { + return nil, errors.Wrapf(err, "could not open backing file: %s", backingFile) + } + defer back.Close() + + loop, err := os.OpenFile(loopDev, flags, 0) + if err != nil { + return nil, errors.Wrapf(err, "could not open loop device: %s", loopDev) + } + defer func() { + if retErr != nil { + loop.Close() + } + }() + + // 2. Set FD + if _, _, err = ioctl(loop.Fd(), unix.LOOP_SET_FD, back.Fd()); err != nil { + return nil, errors.Wrapf(err, "could not set loop fd for device: %s", loopDev) + } + + // 3. Set Info + info := unix.LoopInfo64{} + copy(info.File_name[:], backingFile) + if param.Readonly { + info.Flags |= unix.LO_FLAGS_READ_ONLY + } + + if param.Autoclear { + info.Flags |= unix.LO_FLAGS_AUTOCLEAR + } + + if param.Direct { + info.Flags |= unix.LO_FLAGS_DIRECT_IO + } + + _, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info))) + if err == nil { + return loop, nil + } + + if param.Direct { + // Retry w/o direct IO flag in case kernel does not support it. The downside is that + // it will suffer from double cache problem. + info.Flags &= ^(uint32(unix.LO_FLAGS_DIRECT_IO)) + _, _, err = ioctl(loop.Fd(), unix.LOOP_SET_STATUS64, uintptr(unsafe.Pointer(&info))) + if err == nil { + return loop, nil + } + } + + _, _, _ = ioctl(loop.Fd(), unix.LOOP_CLR_FD, 0) + return nil, errors.Errorf("failed to set loop device info: %v", err) +} + +// setupLoop looks for (and possibly creates) a free loop device, and +// then attaches backingFile to it. +// +// When autoclear is true, caller should take care to close it when +// done with the loop device. The loop device file handle keeps +// loFlagsAutoclear in effect and we rely on it to clean up the loop +// device. If caller closes the file handle after mounting the device, +// kernel will clear the loop device after it is umounted. Otherwise +// the loop device is cleared when the file handle is closed. +// +// When autoclear is false, caller should be responsible to remove +// the loop device when done with it. +// +// Upon success, the file handle to the loop device is returned. +func setupLoop(backingFile string, param LoopParams) (*os.File, error) { + for retry := 1; retry < 100; retry++ { + num, err := getFreeLoopDev() + if err != nil { + return nil, err + } + + loopDev := fmt.Sprintf(loopDevFormat, num) + file, err := setupLoopDev(backingFile, loopDev, param) + if err != nil { + // Per util-linux/sys-utils/losetup.c:create_loop(), + // free loop device can race and we end up failing + // with EBUSY when trying to set it up. + if strings.Contains(err.Error(), ebusyString) { + // Fallback a bit to avoid live lock + time.Sleep(time.Millisecond * time.Duration(rand.Intn(retry*10))) + continue + } + return nil, err + } + + return file, nil + } + + return nil, errors.New("timeout creating new loopback device") +} + +func removeLoop(loopdev string) error { + file, err := os.Open(loopdev) + if err != nil { + return err + } + defer file.Close() + + _, _, err = ioctl(file.Fd(), unix.LOOP_CLR_FD, 0) + return err +} + +// AttachLoopDevice attaches a specified backing file to a loop device +func AttachLoopDevice(backingFile string) (string, error) { + file, err := setupLoop(backingFile, LoopParams{}) + if err != nil { + return "", err + } + defer file.Close() + return file.Name(), nil +} + +// DetachLoopDevice detaches the provided loop devices +func DetachLoopDevice(devices ...string) error { + for _, dev := range devices { + if err := removeLoop(dev); err != nil { + return errors.Wrapf(err, "failed to remove loop device: %s", dev) + } + } + + return nil +} diff -Nru containerd-1.2.6/mount/losetup_linux_test.go containerd-1.5.9/mount/losetup_linux_test.go --- containerd-1.2.6/mount/losetup_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/mount/losetup_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,117 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package mount + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/containerd/continuity/testutil" +) + +var randomData = []byte("randomdata") + +func createTempFile(t *testing.T) string { + t.Helper() + + f, err := ioutil.TempFile("", "losetup") + if err != nil { + t.Fatal(err) + } + defer f.Close() + + if err = f.Truncate(512); err != nil { + t.Fatal(err) + } + + return f.Name() +} + +func TestNonExistingLoop(t *testing.T) { + testutil.RequiresRoot(t) + + backingFile := "setup-loop-test-no-such-file" + _, err := setupLoop(backingFile, LoopParams{}) + if err == nil { + t.Fatalf("setupLoop with non-existing file should fail") + } +} + +func TestRoLoop(t *testing.T) { + testutil.RequiresRoot(t) + + backingFile := createTempFile(t) + defer func() { + if err := os.Remove(backingFile); err != nil { + t.Fatal(err) + } + }() + + file, err := setupLoop(backingFile, LoopParams{Readonly: true, Autoclear: true}) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + if _, err := file.Write(randomData); err == nil { + t.Fatalf("writing to readonly loop device should fail") + } +} + +func TestRwLoop(t *testing.T) { + testutil.RequiresRoot(t) + + backingFile := createTempFile(t) + defer func() { + if err := os.Remove(backingFile); err != nil { + t.Fatal(err) + } + }() + + file, err := setupLoop(backingFile, LoopParams{Autoclear: false}) + if err != nil { + t.Fatal(err) + } + defer file.Close() + + if _, err := file.Write(randomData); err != nil { + t.Fatal(err) + } +} + +func TestAttachDetachLoopDevice(t *testing.T) { + testutil.RequiresRoot(t) + + path := createTempFile(t) + defer func() { + if err := os.Remove(path); err != nil { + t.Fatal(err) + } + }() + + dev, err := AttachLoopDevice(path) + if err != nil { + t.Fatal(err) + } + + if err = DetachLoopDevice(dev); err != nil { + t.Fatal(err) + } +} diff -Nru containerd-1.2.6/mount/mount_freebsd.go containerd-1.5.9/mount/mount_freebsd.go --- containerd-1.2.6/mount/mount_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/mount/mount_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,137 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package mount + +import ( + "os" + "os/exec" + "time" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +var ( + // ErrNotImplementOnUnix is returned for methods that are not implemented + ErrNotImplementOnUnix = errors.New("not implemented under unix") +) + +// Mount to the provided target path. +func (m *Mount) Mount(target string) error { + // The "syscall" and "golang.org/x/sys/unix" packages do not define a Mount + // function for FreeBSD, so instead we execute mount(8) and trust it to do + // the right thing + return m.mountWithHelper(target) +} + +func (m *Mount) mountWithHelper(target string) error { + // target: "/foo/target" + // command: "mount -o ro -t nullfs /foo/source /foo/merged" + // Note: FreeBSD mount(8) is particular about the order of flags and arguments + var args []string + for _, o := range m.Options { + args = append(args, "-o", o) + } + args = append(args, "-t", m.Type) + args = append(args, m.Source, target) + + infoBeforeMount, err := Lookup(target) + if err != nil { + return err + } + + // cmd.CombinedOutput() may intermittently return ECHILD because of our signal handling in shim. + // See #4387 and wait(2). + const retriesOnECHILD = 10 + for i := 0; i < retriesOnECHILD; i++ { + cmd := exec.Command("mount", args...) + out, err := cmd.CombinedOutput() + if err == nil { + return nil + } + if !errors.Is(err, unix.ECHILD) { + return errors.Wrapf(err, "mount [%v] failed: %q", args, string(out)) + } + // We got ECHILD, we are not sure whether the mount was successful. + // If the mount ID has changed, we are sure we got some new mount, but still not sure it is fully completed. + // So we attempt to unmount the new mount before retrying. + infoAfterMount, err := Lookup(target) + if err != nil { + return err + } + if infoAfterMount.ID != infoBeforeMount.ID { + _ = unmount(target, 0) + } + } + return errors.Errorf("mount [%v] failed with ECHILD (retired %d times)", args, retriesOnECHILD) +} + +// Unmount the provided mount path with the flags +func Unmount(target string, flags int) error { + if err := unmount(target, flags); err != nil && err != unix.EINVAL { + return err + } + return nil +} + +func unmount(target string, flags int) error { + for i := 0; i < 50; i++ { + if err := unix.Unmount(target, flags); err != nil { + switch err { + case unix.EBUSY: + time.Sleep(50 * time.Millisecond) + continue + default: + return err + } + } + return nil + } + return errors.Wrapf(unix.EBUSY, "failed to unmount target %s", target) +} + +// UnmountAll repeatedly unmounts the given mount point until there +// are no mounts remaining (EINVAL is returned by mount), which is +// useful for undoing a stack of mounts on the same mount point. +// UnmountAll all is noop when the first argument is an empty string. +// This is done when the containerd client did not specify any rootfs +// mounts (e.g. because the rootfs is managed outside containerd) +// UnmountAll is noop when the mount path does not exist. +func UnmountAll(mount string, flags int) error { + if mount == "" { + return nil + } + if _, err := os.Stat(mount); os.IsNotExist(err) { + return nil + } + + for { + if err := unmount(mount, flags); err != nil { + // EINVAL is returned if the target is not a + // mount point, indicating that we are + // done. It can also indicate a few other + // things (such as invalid flags) which we + // unfortunately end up squelching here too. + if err == unix.EINVAL { + return nil + } + return err + } + } +} diff -Nru containerd-1.2.6/mount/mountinfo_bsd.go containerd-1.5.9/mount/mountinfo_bsd.go --- containerd-1.2.6/mount/mountinfo_bsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mountinfo_bsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -// +build freebsd openbsd - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package mount - -/* -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "reflect" - "unsafe" -) - -// Self retrieves a list of mounts for the current running process. -func Self() ([]Info, error) { - var rawEntries *C.struct_statfs - - count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) - if count == 0 { - return nil, fmt.Errorf("Failed to call getmntinfo") - } - - var entries []C.struct_statfs - header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) - header.Cap = count - header.Len = count - header.Data = uintptr(unsafe.Pointer(rawEntries)) - - var out []Info - for _, entry := range entries { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) - mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) - mountinfo.FSType = C.GoString(&entry.f_fstypename[0]) - out = append(out, mountinfo) - } - return out, nil -} - -// PID collects the mounts for a specific process ID. -func PID(pid int) ([]Info, error) { - return nil, fmt.Errorf("mountinfo.PID is not implemented on freebsd") -} diff -Nru containerd-1.2.6/mount/mountinfo.go containerd-1.5.9/mount/mountinfo.go --- containerd-1.2.6/mount/mountinfo.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mountinfo.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,41 +16,8 @@ package mount +import "github.com/moby/sys/mountinfo" + // Info reveals information about a particular mounted filesystem. This // struct is populated from the content in the /proc//mountinfo file. -type Info struct { - // ID is a unique identifier of the mount (may be reused after umount). - ID int - - // Parent indicates the ID of the mount parent (or of self for the top of the - // mount tree). - Parent int - - // Major indicates one half of the device ID which identifies the device class. - Major int - - // Minor indicates one half of the device ID which identifies a specific - // instance of device. - Minor int - - // Root of the mount within the filesystem. - Root string - - // Mountpoint indicates the mount point relative to the process's root. - Mountpoint string - - // Options represents mount-specific options. - Options string - - // Optional represents optional fields. - Optional string - - // FSType indicates the type of filesystem, such as EXT3. - FSType string - - // Source indicates filesystem specific information or "none". - Source string - - // VFSOptions represents per super block options. - VFSOptions string -} +type Info = mountinfo.Info diff -Nru containerd-1.2.6/mount/mountinfo_linux.go containerd-1.5.9/mount/mountinfo_linux.go --- containerd-1.2.6/mount/mountinfo_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mountinfo_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package mount - -import ( - "bufio" - "fmt" - "io" - "os" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -// Self retrieves a list of mounts for the current running process. -func Self() ([]Info, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} - -func parseInfoFile(r io.Reader) ([]Info, error) { - s := bufio.NewScanner(r) - out := []Info{} - var err error - for s.Scan() { - if err = s.Err(); err != nil { - return nil, err - } - - /* - See http://man7.org/linux/man-pages/man5/proc.5.html - - 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - (1) mount ID: unique identifier of the mount (may be reused after umount) - (2) parent ID: ID of parent (or of self for the top of the mount tree) - (3) major:minor: value of st_dev for files on filesystem - (4) root: root of the mount within the filesystem - (5) mount point: mount point relative to the process's root - (6) mount options: per mount options - (7) optional fields: zero or more fields of the form "tag[:value]" - (8) separator: marks the end of the optional fields - (9) filesystem type: name of filesystem of the form "type[.subtype]" - (10) mount source: filesystem specific information or "none" - (11) super options: per super block options - */ - - text := s.Text() - fields := strings.Split(text, " ") - numFields := len(fields) - if numFields < 10 { - // should be at least 10 fields - return nil, errors.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields) - } - p := Info{} - // ignore any numbers parsing errors, as there should not be any - p.ID, _ = strconv.Atoi(fields[0]) - p.Parent, _ = strconv.Atoi(fields[1]) - mm := strings.Split(fields[2], ":") - if len(mm) != 2 { - return nil, errors.Errorf("parsing '%s' failed: unexpected minor:major pair %s", text, mm) - } - p.Major, _ = strconv.Atoi(mm[0]) - p.Minor, _ = strconv.Atoi(mm[1]) - - p.Root, err = strconv.Unquote(`"` + fields[3] + `"`) - if err != nil { - return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote root field", fields[3]) - } - p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`) - if err != nil { - return nil, errors.Wrapf(err, "parsing '%s' failed: unable to unquote mount point field", fields[4]) - } - p.Options = fields[5] - - // one or more optional fields, when a separator (-) - i := 6 - for ; i < numFields && fields[i] != "-"; i++ { - switch i { - case 6: - p.Optional = fields[6] - default: - /* NOTE there might be more optional fields before the separator - such as fields[7]...fields[N] (where N < separatorIndex), - although as of Linux kernel 4.15 the only known ones are - mount propagation flags in fields[6]. The correct - behavior is to ignore any unknown optional fields. - */ - } - } - if i == numFields { - return nil, errors.Errorf("parsing '%s' failed: missing separator ('-')", text) - } - // There should be 3 fields after the separator... - if i+4 > numFields { - return nil, errors.Errorf("parsing '%s' failed: not enough fields after a separator", text) - } - // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name - // (like "//serv/My Documents") _may_ end up having a space in the last field - // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs - // option unc= is ignored, so a space should not appear. In here we ignore - // those "extra" fields caused by extra spaces. - p.FSType = fields[i+1] - p.Source = fields[i+2] - p.VFSOptions = fields[i+3] - - out = append(out, p) - } - return out, nil -} - -// PID collects the mounts for a specific process ID. If the process -// ID is unknown, it is better to use `Self` which will inspect -// "/proc/self/mountinfo" instead. -func PID(pid int) ([]Info, error) { - f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} diff -Nru containerd-1.2.6/mount/mountinfo_linux_test.go containerd-1.5.9/mount/mountinfo_linux_test.go --- containerd-1.2.6/mount/mountinfo_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mountinfo_linux_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,540 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package mount - -import ( - "bytes" - "testing" -) - -const ( - fedoraMountinfo = `15 35 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw -16 35 0:14 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel -17 35 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8056484k,nr_inodes=2014121,mode=755 -18 16 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw -19 16 0:13 / /sys/fs/selinux rw,relatime shared:8 - selinuxfs selinuxfs rw -20 17 0:16 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel -21 17 0:10 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000 -22 35 0:17 / /run rw,nosuid,nodev shared:21 - tmpfs tmpfs rw,seclabel,mode=755 -23 16 0:18 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - tmpfs tmpfs rw,seclabel,mode=755 -24 23 0:19 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd -25 16 0:20 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw -26 23 0:21 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuset,clone_children -27 23 0:22 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,cpuacct,cpu,clone_children -28 23 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,memory,clone_children -29 23 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices,clone_children -30 23 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer,clone_children -31 23 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,clone_children -32 23 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,blkio,clone_children -33 23 0:28 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event,clone_children -34 23 0:29 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb,clone_children -35 1 253:2 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root--f20 rw,seclabel,data=ordered -36 15 0:30 / /proc/sys/fs/binfmt_misc rw,relatime shared:22 - autofs systemd-1 rw,fd=38,pgrp=1,timeout=300,minproto=5,maxproto=5,direct -37 17 0:12 / /dev/mqueue rw,relatime shared:23 - mqueue mqueue rw,seclabel -38 35 0:31 / /tmp rw shared:24 - tmpfs tmpfs rw,seclabel -39 17 0:32 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw,seclabel -40 16 0:7 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw -41 16 0:33 / /sys/kernel/config rw,relatime shared:27 - configfs configfs rw -42 35 0:34 / /var/lib/nfs/rpc_pipefs rw,relatime shared:28 - rpc_pipefs sunrpc rw -43 15 0:35 / /proc/fs/nfsd rw,relatime shared:29 - nfsd sunrpc rw -45 35 8:17 / /boot rw,relatime shared:30 - ext4 /dev/sdb1 rw,seclabel,data=ordered -46 35 253:4 / /home rw,relatime shared:31 - ext4 /dev/mapper/ssd-home rw,seclabel,data=ordered -47 35 253:5 / /var/lib/libvirt/images rw,noatime,nodiratime shared:32 - ext4 /dev/mapper/ssd-virt rw,seclabel,discard,data=ordered -48 35 253:12 / /mnt/old rw,relatime shared:33 - ext4 /dev/mapper/HelpDeskRHEL6-FedoraRoot rw,seclabel,data=ordered -121 22 0:36 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:104 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000 -124 16 0:37 / /sys/fs/fuse/connections rw,relatime shared:107 - fusectl fusectl rw -165 38 253:3 / /tmp/mnt rw,relatime shared:147 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered -167 35 253:15 / /var/lib/docker/devicemapper/mnt/aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,relatime shared:149 - ext4 /dev/mapper/docker-253:2-425882-aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,seclabel,discard,stripe=16,data=ordered -171 35 253:16 / /var/lib/docker/devicemapper/mnt/c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,relatime shared:153 - ext4 /dev/mapper/docker-253:2-425882-c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,seclabel,discard,stripe=16,data=ordered -175 35 253:17 / /var/lib/docker/devicemapper/mnt/1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,relatime shared:157 - ext4 /dev/mapper/docker-253:2-425882-1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,seclabel,discard,stripe=16,data=ordered -179 35 253:18 / /var/lib/docker/devicemapper/mnt/d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,relatime shared:161 - ext4 /dev/mapper/docker-253:2-425882-d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,seclabel,discard,stripe=16,data=ordered -183 35 253:19 / /var/lib/docker/devicemapper/mnt/6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,relatime shared:165 - ext4 /dev/mapper/docker-253:2-425882-6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,seclabel,discard,stripe=16,data=ordered -187 35 253:20 / /var/lib/docker/devicemapper/mnt/8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,relatime shared:169 - ext4 /dev/mapper/docker-253:2-425882-8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,seclabel,discard,stripe=16,data=ordered -191 35 253:21 / /var/lib/docker/devicemapper/mnt/c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,relatime shared:173 - ext4 /dev/mapper/docker-253:2-425882-c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,seclabel,discard,stripe=16,data=ordered -195 35 253:22 / /var/lib/docker/devicemapper/mnt/2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,relatime shared:177 - ext4 /dev/mapper/docker-253:2-425882-2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,seclabel,discard,stripe=16,data=ordered -199 35 253:23 / /var/lib/docker/devicemapper/mnt/37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,relatime shared:181 - ext4 /dev/mapper/docker-253:2-425882-37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,seclabel,discard,stripe=16,data=ordered -203 35 253:24 / /var/lib/docker/devicemapper/mnt/aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,relatime shared:185 - ext4 /dev/mapper/docker-253:2-425882-aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,seclabel,discard,stripe=16,data=ordered -207 35 253:25 / /var/lib/docker/devicemapper/mnt/928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,relatime shared:189 - ext4 /dev/mapper/docker-253:2-425882-928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,seclabel,discard,stripe=16,data=ordered -211 35 253:26 / /var/lib/docker/devicemapper/mnt/0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,relatime shared:193 - ext4 /dev/mapper/docker-253:2-425882-0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,seclabel,discard,stripe=16,data=ordered -215 35 253:27 / /var/lib/docker/devicemapper/mnt/d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,relatime shared:197 - ext4 /dev/mapper/docker-253:2-425882-d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,seclabel,discard,stripe=16,data=ordered -219 35 253:28 / /var/lib/docker/devicemapper/mnt/bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,relatime shared:201 - ext4 /dev/mapper/docker-253:2-425882-bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,seclabel,discard,stripe=16,data=ordered -223 35 253:29 / /var/lib/docker/devicemapper/mnt/7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,relatime shared:205 - ext4 /dev/mapper/docker-253:2-425882-7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,seclabel,discard,stripe=16,data=ordered -227 35 253:30 / /var/lib/docker/devicemapper/mnt/c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,relatime shared:209 - ext4 /dev/mapper/docker-253:2-425882-c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,seclabel,discard,stripe=16,data=ordered -231 35 253:31 / /var/lib/docker/devicemapper/mnt/8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,relatime shared:213 - ext4 /dev/mapper/docker-253:2-425882-8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,seclabel,discard,stripe=16,data=ordered -235 35 253:32 / /var/lib/docker/devicemapper/mnt/1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,relatime shared:217 - ext4 /dev/mapper/docker-253:2-425882-1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,seclabel,discard,stripe=16,data=ordered -239 35 253:33 / /var/lib/docker/devicemapper/mnt/e9aa60c60128cad1 rw,relatime shared:221 - ext4 /dev/mapper/docker-253:2-425882-e9aa60c60128cad1 rw,seclabel,discard,stripe=16,data=ordered -243 35 253:34 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,relatime shared:225 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,seclabel,discard,stripe=16,data=ordered -247 35 253:35 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,relatime shared:229 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,seclabel,discard,stripe=16,data=ordered -31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1` - - ubuntuMountInfo = `15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw -16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw -17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=1015140k,nr_inodes=253785,mode=755 -18 17 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 -19 20 0:15 / /run rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=205044k,mode=755 -20 1 253:0 / / rw,relatime - ext4 /dev/disk/by-label/DOROOT rw,errors=remount-ro,data=ordered -21 15 0:16 / /sys/fs/cgroup rw,relatime - tmpfs none rw,size=4k,mode=755 -22 15 0:17 / /sys/fs/fuse/connections rw,relatime - fusectl none rw -23 15 0:6 / /sys/kernel/debug rw,relatime - debugfs none rw -24 15 0:10 / /sys/kernel/security rw,relatime - securityfs none rw -25 19 0:18 / /run/lock rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=5120k -26 21 0:19 / /sys/fs/cgroup/cpuset rw,relatime - cgroup cgroup rw,cpuset,clone_children -27 19 0:20 / /run/shm rw,nosuid,nodev,relatime - tmpfs none rw -28 21 0:21 / /sys/fs/cgroup/cpu rw,relatime - cgroup cgroup rw,cpu -29 19 0:22 / /run/user rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=102400k,mode=755 -30 15 0:23 / /sys/fs/pstore rw,relatime - pstore none rw -31 21 0:24 / /sys/fs/cgroup/cpuacct rw,relatime - cgroup cgroup rw,cpuacct -32 21 0:25 / /sys/fs/cgroup/memory rw,relatime - cgroup cgroup rw,memory -33 21 0:26 / /sys/fs/cgroup/devices rw,relatime - cgroup cgroup rw,devices -34 21 0:27 / /sys/fs/cgroup/freezer rw,relatime - cgroup cgroup rw,freezer -35 21 0:28 / /sys/fs/cgroup/blkio rw,relatime - cgroup cgroup rw,blkio -36 21 0:29 / /sys/fs/cgroup/perf_event rw,relatime - cgroup cgroup rw,perf_event -37 21 0:30 / /sys/fs/cgroup/hugetlb rw,relatime - cgroup cgroup rw,hugetlb -38 21 0:31 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup systemd rw,name=systemd -39 20 0:32 / /var/lib/docker/aufs/mnt/b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc rw,relatime - aufs none rw,si=caafa54fdc06525 -40 20 0:33 / /var/lib/docker/aufs/mnt/2eed44ac7ce7c75af04f088ed6cb4ce9d164801e91d78c6db65d7ef6d572bba8-init rw,relatime - aufs none rw,si=caafa54f882b525 -41 20 0:34 / /var/lib/docker/aufs/mnt/2eed44ac7ce7c75af04f088ed6cb4ce9d164801e91d78c6db65d7ef6d572bba8 rw,relatime - aufs none rw,si=caafa54f8829525 -42 20 0:35 / /var/lib/docker/aufs/mnt/16f4d7e96dd612903f425bfe856762f291ff2e36a8ecd55a2209b7d7cd81c30b rw,relatime - aufs none rw,si=caafa54f882d525 -43 20 0:36 / /var/lib/docker/aufs/mnt/63ca08b75d7438a9469a5954e003f48ffede73541f6286ce1cb4d7dd4811da7e-init rw,relatime - aufs none rw,si=caafa54f882f525 -44 20 0:37 / /var/lib/docker/aufs/mnt/63ca08b75d7438a9469a5954e003f48ffede73541f6286ce1cb4d7dd4811da7e rw,relatime - aufs none rw,si=caafa54f88ba525 -45 20 0:38 / /var/lib/docker/aufs/mnt/283f35a910233c756409313be71ecd8fcfef0df57108b8d740b61b3e88860452 rw,relatime - aufs none rw,si=caafa54f88b8525 -46 20 0:39 / /var/lib/docker/aufs/mnt/2c6c7253d4090faa3886871fb21bd660609daeb0206588c0602007f7d0f254b1-init rw,relatime - aufs none rw,si=caafa54f88be525 -47 20 0:40 / /var/lib/docker/aufs/mnt/2c6c7253d4090faa3886871fb21bd660609daeb0206588c0602007f7d0f254b1 rw,relatime - aufs none rw,si=caafa54f882c525 -48 20 0:41 / /var/lib/docker/aufs/mnt/de2b538c97d6366cc80e8658547c923ea1d042f85580df379846f36a4df7049d rw,relatime - aufs none rw,si=caafa54f85bb525 -49 20 0:42 / /var/lib/docker/aufs/mnt/94a3d8ed7c27e5b0aa71eba46c736bfb2742afda038e74f2dd6035fb28415b49-init rw,relatime - aufs none rw,si=caafa54fdc00525 -50 20 0:43 / /var/lib/docker/aufs/mnt/94a3d8ed7c27e5b0aa71eba46c736bfb2742afda038e74f2dd6035fb28415b49 rw,relatime - aufs none rw,si=caafa54fbaec525 -51 20 0:44 / /var/lib/docker/aufs/mnt/6ac1cace985c9fc9bea32234de8b36dba49bdd5e29a2972b327ff939d78a6274 rw,relatime - aufs none rw,si=caafa54f8e1a525 -52 20 0:45 / /var/lib/docker/aufs/mnt/dff147033e3a0ef061e1de1ad34256b523d4a8c1fa6bba71a0ab538e8628ff0b-init rw,relatime - aufs none rw,si=caafa54f8e1d525 -53 20 0:46 / /var/lib/docker/aufs/mnt/dff147033e3a0ef061e1de1ad34256b523d4a8c1fa6bba71a0ab538e8628ff0b rw,relatime - aufs none rw,si=caafa54f8e1b525 -54 20 0:47 / /var/lib/docker/aufs/mnt/cabb117d997f0f93519185aea58389a9762770b7496ed0b74a3e4a083fa45902 rw,relatime - aufs none rw,si=caafa54f810a525 -55 20 0:48 / /var/lib/docker/aufs/mnt/e1c8a94ffaa9d532bbbdc6ef771ce8a6c2c06757806ecaf8b68e9108fec65f33-init rw,relatime - aufs none rw,si=caafa54f8529525 -56 20 0:49 / /var/lib/docker/aufs/mnt/e1c8a94ffaa9d532bbbdc6ef771ce8a6c2c06757806ecaf8b68e9108fec65f33 rw,relatime - aufs none rw,si=caafa54f852f525 -57 20 0:50 / /var/lib/docker/aufs/mnt/16a1526fa445b84ce84f89506d219e87fa488a814063baf045d88b02f21166b3 rw,relatime - aufs none rw,si=caafa54f9e1d525 -58 20 0:51 / /var/lib/docker/aufs/mnt/57b9c92e1e368fa7dbe5079f7462e917777829caae732828b003c355fe49da9f-init rw,relatime - aufs none rw,si=caafa54f854d525 -59 20 0:52 / /var/lib/docker/aufs/mnt/57b9c92e1e368fa7dbe5079f7462e917777829caae732828b003c355fe49da9f rw,relatime - aufs none rw,si=caafa54f854e525 -60 20 0:53 / /var/lib/docker/aufs/mnt/e370c3e286bea027917baa0e4d251262681a472a87056e880dfd0513516dffd9 rw,relatime - aufs none rw,si=caafa54f840a525 -61 20 0:54 / /var/lib/docker/aufs/mnt/6b00d3b4f32b41997ec07412b5e18204f82fbe643e7122251cdeb3582abd424e-init rw,relatime - aufs none rw,si=caafa54f8408525 -62 20 0:55 / /var/lib/docker/aufs/mnt/6b00d3b4f32b41997ec07412b5e18204f82fbe643e7122251cdeb3582abd424e rw,relatime - aufs none rw,si=caafa54f8409525 -63 20 0:56 / /var/lib/docker/aufs/mnt/abd0b5ea5d355a67f911475e271924a5388ee60c27185fcd60d095afc4a09dc7 rw,relatime - aufs none rw,si=caafa54f9eb1525 -64 20 0:57 / /var/lib/docker/aufs/mnt/336222effc3f7b89867bb39ff7792ae5412c35c749f127c29159d046b6feedd2-init rw,relatime - aufs none rw,si=caafa54f85bf525 -65 20 0:58 / /var/lib/docker/aufs/mnt/336222effc3f7b89867bb39ff7792ae5412c35c749f127c29159d046b6feedd2 rw,relatime - aufs none rw,si=caafa54f85b8525 -66 20 0:59 / /var/lib/docker/aufs/mnt/912e1bf28b80a09644503924a8a1a4fb8ed10b808ca847bda27a369919aa52fa rw,relatime - aufs none rw,si=caafa54fbaea525 -67 20 0:60 / /var/lib/docker/aufs/mnt/386f722875013b4a875118367abc783fc6617a3cb7cf08b2b4dcf550b4b9c576-init rw,relatime - aufs none rw,si=caafa54f8472525 -68 20 0:61 / /var/lib/docker/aufs/mnt/386f722875013b4a875118367abc783fc6617a3cb7cf08b2b4dcf550b4b9c576 rw,relatime - aufs none rw,si=caafa54f8474525 -69 20 0:62 / /var/lib/docker/aufs/mnt/5aaebb79ef3097dfca377889aeb61a0c9d5e3795117d2b08d0751473c671dfb2 rw,relatime - aufs none rw,si=caafa54f8c5e525 -70 20 0:63 / /var/lib/docker/aufs/mnt/5ba3e493279d01277d583600b81c7c079e691b73c3a2bdea8e4b12a35a418be2-init rw,relatime - aufs none rw,si=caafa54f8c3b525 -71 20 0:64 / /var/lib/docker/aufs/mnt/5ba3e493279d01277d583600b81c7c079e691b73c3a2bdea8e4b12a35a418be2 rw,relatime - aufs none rw,si=caafa54f8c3d525 -72 20 0:65 / /var/lib/docker/aufs/mnt/2777f0763da4de93f8bebbe1595cc77f739806a158657b033eca06f827b6028a rw,relatime - aufs none rw,si=caafa54f8c3e525 -73 20 0:66 / /var/lib/docker/aufs/mnt/5d7445562acf73c6f0ae34c3dd0921d7457de1ba92a587d9e06a44fa209eeb3e-init rw,relatime - aufs none rw,si=caafa54f8c39525 -74 20 0:67 / /var/lib/docker/aufs/mnt/5d7445562acf73c6f0ae34c3dd0921d7457de1ba92a587d9e06a44fa209eeb3e rw,relatime - aufs none rw,si=caafa54f854f525 -75 20 0:68 / /var/lib/docker/aufs/mnt/06400b526ec18b66639c96efc41a84f4ae0b117cb28dafd56be420651b4084a0 rw,relatime - aufs none rw,si=caafa54f840b525 -76 20 0:69 / /var/lib/docker/aufs/mnt/e051d45ec42d8e3e1cc57bb39871a40de486dc123522e9c067fbf2ca6a357785-init rw,relatime - aufs none rw,si=caafa54fdddf525 -77 20 0:70 / /var/lib/docker/aufs/mnt/e051d45ec42d8e3e1cc57bb39871a40de486dc123522e9c067fbf2ca6a357785 rw,relatime - aufs none rw,si=caafa54f854b525 -78 20 0:71 / /var/lib/docker/aufs/mnt/1ff414fa93fd61ec81b0ab7b365a841ff6545accae03cceac702833aaeaf718f rw,relatime - aufs none rw,si=caafa54f8d85525 -79 20 0:72 / /var/lib/docker/aufs/mnt/c661b2f871dd5360e46a2aebf8f970f6d39a2ff64e06979aa0361227c88128b8-init rw,relatime - aufs none rw,si=caafa54f8da3525 -80 20 0:73 / /var/lib/docker/aufs/mnt/c661b2f871dd5360e46a2aebf8f970f6d39a2ff64e06979aa0361227c88128b8 rw,relatime - aufs none rw,si=caafa54f8da2525 -81 20 0:74 / /var/lib/docker/aufs/mnt/b68b1d4fe4d30016c552398e78b379a39f651661d8e1fa5f2460c24a5e723420 rw,relatime - aufs none rw,si=caafa54f8d81525 -82 20 0:75 / /var/lib/docker/aufs/mnt/c5c5979c936cd0153a4c626fa9d69ce4fce7d924cc74fa68b025d2f585031739-init rw,relatime - aufs none rw,si=caafa54f8da1525 -83 20 0:76 / /var/lib/docker/aufs/mnt/c5c5979c936cd0153a4c626fa9d69ce4fce7d924cc74fa68b025d2f585031739 rw,relatime - aufs none rw,si=caafa54f8da0525 -84 20 0:77 / /var/lib/docker/aufs/mnt/53e10b0329afc0e0d3322d31efaed4064139dc7027fe6ae445cffd7104bcc94f rw,relatime - aufs none rw,si=caafa54f8c35525 -85 20 0:78 / /var/lib/docker/aufs/mnt/3bfafd09ff2603e2165efacc2215c1f51afabba6c42d04a68cc2df0e8cc31494-init rw,relatime - aufs none rw,si=caafa54f8db8525 -86 20 0:79 / /var/lib/docker/aufs/mnt/3bfafd09ff2603e2165efacc2215c1f51afabba6c42d04a68cc2df0e8cc31494 rw,relatime - aufs none rw,si=caafa54f8dba525 -87 20 0:80 / /var/lib/docker/aufs/mnt/90fdd2c03eeaf65311f88f4200e18aef6d2772482712d9aea01cd793c64781b5 rw,relatime - aufs none rw,si=caafa54f8315525 -88 20 0:81 / /var/lib/docker/aufs/mnt/7bdf2591c06c154ceb23f5e74b1d03b18fbf6fe96e35fbf539b82d446922442f-init rw,relatime - aufs none rw,si=caafa54f8fc6525 -89 20 0:82 / /var/lib/docker/aufs/mnt/7bdf2591c06c154ceb23f5e74b1d03b18fbf6fe96e35fbf539b82d446922442f rw,relatime - aufs none rw,si=caafa54f8468525 -90 20 0:83 / /var/lib/docker/aufs/mnt/8cf9a993f50f3305abad3da268c0fc44ff78a1e7bba595ef9de963497496c3f9 rw,relatime - aufs none rw,si=caafa54f8c59525 -91 20 0:84 / /var/lib/docker/aufs/mnt/ecc896fd74b21840a8d35e8316b92a08b1b9c83d722a12acff847e9f0ff17173-init rw,relatime - aufs none rw,si=caafa54f846a525 -92 20 0:85 / /var/lib/docker/aufs/mnt/ecc896fd74b21840a8d35e8316b92a08b1b9c83d722a12acff847e9f0ff17173 rw,relatime - aufs none rw,si=caafa54f846b525 -93 20 0:86 / /var/lib/docker/aufs/mnt/d8c8288ec920439a48b5796bab5883ee47a019240da65e8d8f33400c31bac5df rw,relatime - aufs none rw,si=caafa54f8dbf525 -94 20 0:87 / /var/lib/docker/aufs/mnt/ecba66710bcd03199b9398e46c005cd6b68d0266ec81dc8b722a29cc417997c6-init rw,relatime - aufs none rw,si=caafa54f810f525 -95 20 0:88 / /var/lib/docker/aufs/mnt/ecba66710bcd03199b9398e46c005cd6b68d0266ec81dc8b722a29cc417997c6 rw,relatime - aufs none rw,si=caafa54fbae9525 -96 20 0:89 / /var/lib/docker/aufs/mnt/befc1c67600df449dddbe796c0d06da7caff1d2bbff64cde1f0ba82d224996b5 rw,relatime - aufs none rw,si=caafa54f8dab525 -97 20 0:90 / /var/lib/docker/aufs/mnt/c9f470e73d2742629cdc4084a1b2c1a8302914f2aa0d0ec4542371df9a050562-init rw,relatime - aufs none rw,si=caafa54fdc02525 -98 20 0:91 / /var/lib/docker/aufs/mnt/c9f470e73d2742629cdc4084a1b2c1a8302914f2aa0d0ec4542371df9a050562 rw,relatime - aufs none rw,si=caafa54f9eb0525 -99 20 0:92 / /var/lib/docker/aufs/mnt/2a31f10029f04ff9d4381167a9b739609853d7220d55a56cb654779a700ee246 rw,relatime - aufs none rw,si=caafa54f8c37525 -100 20 0:93 / /var/lib/docker/aufs/mnt/8c4261b8e3e4b21ebba60389bd64b6261217e7e6b9fd09e201d5a7f6760f6927-init rw,relatime - aufs none rw,si=caafa54fd173525 -101 20 0:94 / /var/lib/docker/aufs/mnt/8c4261b8e3e4b21ebba60389bd64b6261217e7e6b9fd09e201d5a7f6760f6927 rw,relatime - aufs none rw,si=caafa54f8108525 -102 20 0:95 / /var/lib/docker/aufs/mnt/eaa0f57403a3dc685268f91df3fbcd7a8423cee50e1a9ee5c3e1688d9d676bb4 rw,relatime - aufs none rw,si=caafa54f852d525 -103 20 0:96 / /var/lib/docker/aufs/mnt/9cfe69a2cbffd9bfc7f396d4754f6fe5cc457ef417b277797be3762dfe955a6b-init rw,relatime - aufs none rw,si=caafa54f8d80525 -104 20 0:97 / /var/lib/docker/aufs/mnt/9cfe69a2cbffd9bfc7f396d4754f6fe5cc457ef417b277797be3762dfe955a6b rw,relatime - aufs none rw,si=caafa54f8fc3525 -105 20 0:98 / /var/lib/docker/aufs/mnt/d1b322ae17613c6adee84e709641a9244ac56675244a89a64dc0075075fcbb83 rw,relatime - aufs none rw,si=caafa54f8c58525 -106 20 0:99 / /var/lib/docker/aufs/mnt/d46c2a8e9da7e91ab34fd9c192851c246a4e770a46720bda09e55c7554b9dbbd-init rw,relatime - aufs none rw,si=caafa54f8c63525 -107 20 0:100 / /var/lib/docker/aufs/mnt/d46c2a8e9da7e91ab34fd9c192851c246a4e770a46720bda09e55c7554b9dbbd rw,relatime - aufs none rw,si=caafa54f8c67525 -108 20 0:101 / /var/lib/docker/aufs/mnt/bc9d2a264158f83a617a069bf17cbbf2a2ba453db7d3951d9dc63cc1558b1c2b rw,relatime - aufs none rw,si=caafa54f8dbe525 -109 20 0:102 / /var/lib/docker/aufs/mnt/9e6abb8d72bbeb4d5cf24b96018528015ba830ce42b4859965bd482cbd034e99-init rw,relatime - aufs none rw,si=caafa54f9e0d525 -110 20 0:103 / /var/lib/docker/aufs/mnt/9e6abb8d72bbeb4d5cf24b96018528015ba830ce42b4859965bd482cbd034e99 rw,relatime - aufs none rw,si=caafa54f9e1b525 -111 20 0:104 / /var/lib/docker/aufs/mnt/d4dca7b02569c732e740071e1c654d4ad282de5c41edb619af1f0aafa618be26 rw,relatime - aufs none rw,si=caafa54f8dae525 -112 20 0:105 / /var/lib/docker/aufs/mnt/fea63da40fa1c5ffbad430dde0bc64a8fc2edab09a051fff55b673c40a08f6b7-init rw,relatime - aufs none rw,si=caafa54f8c5c525 -113 20 0:106 / /var/lib/docker/aufs/mnt/fea63da40fa1c5ffbad430dde0bc64a8fc2edab09a051fff55b673c40a08f6b7 rw,relatime - aufs none rw,si=caafa54fd172525 -114 20 0:107 / /var/lib/docker/aufs/mnt/e60c57499c0b198a6734f77f660cdbbd950a5b78aa23f470ca4f0cfcc376abef rw,relatime - aufs none rw,si=caafa54909c4525 -115 20 0:108 / /var/lib/docker/aufs/mnt/099c78e7ccd9c8717471bb1bbfff838c0a9913321ba2f214fbeaf92c678e5b35-init rw,relatime - aufs none rw,si=caafa54909c3525 -116 20 0:109 / /var/lib/docker/aufs/mnt/099c78e7ccd9c8717471bb1bbfff838c0a9913321ba2f214fbeaf92c678e5b35 rw,relatime - aufs none rw,si=caafa54909c7525 -117 20 0:110 / /var/lib/docker/aufs/mnt/2997be666d58b9e71469759bcb8bd9608dad0e533a1a7570a896919ba3388825 rw,relatime - aufs none rw,si=caafa54f8557525 -118 20 0:111 / /var/lib/docker/aufs/mnt/730694eff438ef20569df38dfb38a920969d7ff2170cc9aa7cb32a7ed8147a93-init rw,relatime - aufs none rw,si=caafa54c6e88525 -119 20 0:112 / /var/lib/docker/aufs/mnt/730694eff438ef20569df38dfb38a920969d7ff2170cc9aa7cb32a7ed8147a93 rw,relatime - aufs none rw,si=caafa54c6e8e525 -120 20 0:113 / /var/lib/docker/aufs/mnt/a672a1e2f2f051f6e19ed1dfbe80860a2d774174c49f7c476695f5dd1d5b2f67 rw,relatime - aufs none rw,si=caafa54c6e15525 -121 20 0:114 / /var/lib/docker/aufs/mnt/aba3570e17859f76cf29d282d0d150659c6bd80780fdc52a465ba05245c2a420-init rw,relatime - aufs none rw,si=caafa54f8dad525 -122 20 0:115 / /var/lib/docker/aufs/mnt/aba3570e17859f76cf29d282d0d150659c6bd80780fdc52a465ba05245c2a420 rw,relatime - aufs none rw,si=caafa54f8d84525 -123 20 0:116 / /var/lib/docker/aufs/mnt/2abc86007aca46fb4a817a033e2a05ccacae40b78ea4b03f8ea616b9ada40e2e rw,relatime - aufs none rw,si=caafa54c6e8b525 -124 20 0:117 / /var/lib/docker/aufs/mnt/36352f27f7878e648367a135bd1ec3ed497adcb8ac13577ee892a0bd921d2374-init rw,relatime - aufs none rw,si=caafa54c6e8d525 -125 20 0:118 / /var/lib/docker/aufs/mnt/36352f27f7878e648367a135bd1ec3ed497adcb8ac13577ee892a0bd921d2374 rw,relatime - aufs none rw,si=caafa54f8c34525 -126 20 0:119 / /var/lib/docker/aufs/mnt/2f95ca1a629cea8363b829faa727dd52896d5561f2c96ddee4f697ea2fc872c2 rw,relatime - aufs none rw,si=caafa54c6e8a525 -127 20 0:120 / /var/lib/docker/aufs/mnt/f108c8291654f179ef143a3e07de2b5a34adbc0b28194a0ab17742b6db9a7fb2-init rw,relatime - aufs none rw,si=caafa54f8e19525 -128 20 0:121 / /var/lib/docker/aufs/mnt/f108c8291654f179ef143a3e07de2b5a34adbc0b28194a0ab17742b6db9a7fb2 rw,relatime - aufs none rw,si=caafa54fa8c6525 -129 20 0:122 / /var/lib/docker/aufs/mnt/c1d04dfdf8cccb3676d5a91e84e9b0781ce40623d127d038bcfbe4c761b27401 rw,relatime - aufs none rw,si=caafa54f8c30525 -130 20 0:123 / /var/lib/docker/aufs/mnt/3f4898ffd0e1239aeebf1d1412590cdb7254207fa3883663e2c40cf772e5f05a-init rw,relatime - aufs none rw,si=caafa54c6e1a525 -131 20 0:124 / /var/lib/docker/aufs/mnt/3f4898ffd0e1239aeebf1d1412590cdb7254207fa3883663e2c40cf772e5f05a rw,relatime - aufs none rw,si=caafa54c6e1c525 -132 20 0:125 / /var/lib/docker/aufs/mnt/5ae3b6fccb1539fc02d420e86f3e9637bef5b711fed2ca31a2f426c8f5deddbf rw,relatime - aufs none rw,si=caafa54c4fea525 -133 20 0:126 / /var/lib/docker/aufs/mnt/310bfaf80d57020f2e73b06aeffb0b9b0ca2f54895f88bf5e4d1529ccac58fe0-init rw,relatime - aufs none rw,si=caafa54c6e1e525 -134 20 0:127 / /var/lib/docker/aufs/mnt/310bfaf80d57020f2e73b06aeffb0b9b0ca2f54895f88bf5e4d1529ccac58fe0 rw,relatime - aufs none rw,si=caafa54fa8c0525 -135 20 0:128 / /var/lib/docker/aufs/mnt/f382bd5aaccaf2d04a59089ac7cb12ec87efd769fd0c14d623358fbfd2a3f896 rw,relatime - aufs none rw,si=caafa54c4fec525 -136 20 0:129 / /var/lib/docker/aufs/mnt/50d45e9bb2d779bc6362824085564c7578c231af5ae3b3da116acf7e17d00735-init rw,relatime - aufs none rw,si=caafa54c4fef525 -137 20 0:130 / /var/lib/docker/aufs/mnt/50d45e9bb2d779bc6362824085564c7578c231af5ae3b3da116acf7e17d00735 rw,relatime - aufs none rw,si=caafa54c4feb525 -138 20 0:131 / /var/lib/docker/aufs/mnt/a9c5ee0854dc083b6bf62b7eb1e5291aefbb10702289a446471ce73aba0d5d7d rw,relatime - aufs none rw,si=caafa54909c6525 -139 20 0:134 / /var/lib/docker/aufs/mnt/03a613e7bd5078819d1fd92df4e671c0127559a5e0b5a885cc8d5616875162f0-init rw,relatime - aufs none rw,si=caafa54804fe525 -140 20 0:135 / /var/lib/docker/aufs/mnt/03a613e7bd5078819d1fd92df4e671c0127559a5e0b5a885cc8d5616875162f0 rw,relatime - aufs none rw,si=caafa54804fa525 -141 20 0:136 / /var/lib/docker/aufs/mnt/7ec3277e5c04c907051caf9c9c35889f5fcd6463e5485971b25404566830bb70 rw,relatime - aufs none rw,si=caafa54804f9525 -142 20 0:139 / /var/lib/docker/aufs/mnt/26b5b5d71d79a5b2bfcf8bc4b2280ee829f261eb886745dd90997ed410f7e8b8-init rw,relatime - aufs none rw,si=caafa54c6ef6525 -143 20 0:140 / /var/lib/docker/aufs/mnt/26b5b5d71d79a5b2bfcf8bc4b2280ee829f261eb886745dd90997ed410f7e8b8 rw,relatime - aufs none rw,si=caafa54c6ef5525 -144 20 0:356 / /var/lib/docker/aufs/mnt/e6ecde9e2c18cd3c75f424c67b6d89685cfee0fc67abf2cb6bdc0867eb998026 rw,relatime - aufs none rw,si=caafa548068e525` - - gentooMountinfo = `15 1 8:6 / / rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered -16 15 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw -17 15 0:14 / /run rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=3292172k,mode=755 -18 15 0:5 / /dev rw,nosuid,relatime - devtmpfs udev rw,size=10240k,nr_inodes=4106451,mode=755 -19 18 0:12 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw -20 18 0:10 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 -21 18 0:15 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw -22 15 0:16 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw -23 22 0:7 / /sys/kernel/debug rw,nosuid,nodev,noexec,relatime - debugfs debugfs rw -24 22 0:17 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs cgroup_root rw,size=10240k,mode=755 -25 24 0:18 / /sys/fs/cgroup/openrc rw,nosuid,nodev,noexec,relatime - cgroup openrc rw,release_agent=/lib64/rc/sh/cgroup-release-agent.sh,name=openrc -26 24 0:19 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cpuset rw,cpuset,clone_children -27 24 0:20 / /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime - cgroup cpu rw,cpu,clone_children -28 24 0:21 / /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cpuacct rw,cpuacct,clone_children -29 24 0:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup memory rw,memory,clone_children -30 24 0:23 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup devices rw,devices,clone_children -31 24 0:24 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup freezer rw,freezer,clone_children -32 24 0:25 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup blkio rw,blkio,clone_children -33 15 8:1 / /boot rw,noatime,nodiratime - vfat /dev/sda1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -34 15 8:18 / /mnt/xfs rw,noatime,nodiratime - xfs /dev/sdb2 rw,attr2,inode64,noquota -35 15 0:26 / /tmp rw,relatime - tmpfs tmpfs rw -36 16 0:27 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime - binfmt_misc binfmt_misc rw -42 15 0:33 / /var/lib/nfs/rpc_pipefs rw,relatime - rpc_pipefs rpc_pipefs rw -43 16 0:34 / /proc/fs/nfsd rw,nosuid,nodev,noexec,relatime - nfsd nfsd rw -44 15 0:35 / /home/tianon/.gvfs rw,nosuid,nodev,relatime - fuse.gvfs-fuse-daemon gvfs-fuse-daemon rw,user_id=1000,group_id=1000 -68 15 0:3336 / /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd rw,relatime - aufs none rw,si=9b4a7640128db39c -86 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/config.env /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/.dockerenv rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered -87 68 8:6 /etc/resolv.conf /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/resolv.conf rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered -88 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/hostname /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/hostname rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered -89 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/hosts /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/hosts rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered -38 15 0:3384 / /var/lib/docker/aufs/mnt/0292005a9292401bb5197657f2b682d97d8edcb3b72b5e390d2a680139985b55 rw,relatime - aufs none rw,si=9b4a7642b584939c -39 15 0:3385 / /var/lib/docker/aufs/mnt/59db98c889de5f71b70cfb82c40cbe47b64332f0f56042a2987a9e5df6e5e3aa rw,relatime - aufs none rw,si=9b4a7642b584e39c -40 15 0:3386 / /var/lib/docker/aufs/mnt/0545f0f2b6548eb9601d08f35a08f5a0a385407d36027a28f58e06e9f61e0278 rw,relatime - aufs none rw,si=9b4a7642b584b39c -41 15 0:3387 / /var/lib/docker/aufs/mnt/d882cfa16d1aa8fe0331a36e79be3d80b151e49f24fc39a39c3fed1735d5feb5 rw,relatime - aufs none rw,si=9b4a76453040039c -45 15 0:3388 / /var/lib/docker/aufs/mnt/055ca3befcb1626e74f5344b3398724ff05c0de0e20021683d04305c9e70a3f6 rw,relatime - aufs none rw,si=9b4a76453040739c -46 15 0:3389 / /var/lib/docker/aufs/mnt/b899e4567a351745d4285e7f1c18fdece75d877deb3041981cd290be348b7aa6 rw,relatime - aufs none rw,si=9b4a7647def4039c -47 15 0:3390 / /var/lib/docker/aufs/mnt/067ca040292c58954c5129f953219accfae0d40faca26b4d05e76ca76a998f16 rw,relatime - aufs none rw,si=9b4a7647def4239c -48 15 0:3391 / /var/lib/docker/aufs/mnt/8c995e7cb6e5082742daeea720e340b021d288d25d92e0412c03d200df308a11 rw,relatime - aufs none rw,si=9b4a764479c1639c -49 15 0:3392 / /var/lib/docker/aufs/mnt/07cc54dfae5b45300efdacdd53cc72c01b9044956a86ce7bff42d087e426096d rw,relatime - aufs none rw,si=9b4a764479c1739c -50 15 0:3393 / /var/lib/docker/aufs/mnt/0a9c95cf4c589c05b06baa79150b0cc1d8e7102759fe3ce4afaabb8247ca4f85 rw,relatime - aufs none rw,si=9b4a7644059c839c -51 15 0:3394 / /var/lib/docker/aufs/mnt/468fa98cececcf4e226e8370f18f4f848d63faf287fb8321a07f73086441a3a0 rw,relatime - aufs none rw,si=9b4a7644059ca39c -52 15 0:3395 / /var/lib/docker/aufs/mnt/0b826192231c5ce066fffb5beff4397337b5fc19a377aa7c6282c7c0ce7f111f rw,relatime - aufs none rw,si=9b4a764479c1339c -53 15 0:3396 / /var/lib/docker/aufs/mnt/93b8ba1b772fbe79709b909c43ea4b2c30d712e53548f467db1ffdc7a384f196 rw,relatime - aufs none rw,si=9b4a7640798a739c -54 15 0:3397 / /var/lib/docker/aufs/mnt/0c0d0acfb506859b12ef18cdfef9ebed0b43a611482403564224bde9149d373c rw,relatime - aufs none rw,si=9b4a7640798a039c -55 15 0:3398 / /var/lib/docker/aufs/mnt/33648c39ab6c7c74af0243d6d6a81b052e9e25ad1e04b19892eb2dde013e358b rw,relatime - aufs none rw,si=9b4a7644b439b39c -56 15 0:3399 / /var/lib/docker/aufs/mnt/0c12bea97a1c958a3c739fb148536c1c89351d48e885ecda8f0499b5cc44407e rw,relatime - aufs none rw,si=9b4a7640798a239c -57 15 0:3400 / /var/lib/docker/aufs/mnt/ed443988ce125f172d7512e84a4de2627405990fd767a16adefa8ce700c19ce8 rw,relatime - aufs none rw,si=9b4a7644c8ed339c -59 15 0:3402 / /var/lib/docker/aufs/mnt/f61612c324ff3c924d3f7a82fb00a0f8d8f73c248c41897061949e9f5ab7e3b1 rw,relatime - aufs none rw,si=9b4a76442810c39c -60 15 0:3403 / /var/lib/docker/aufs/mnt/0f1ee55c6c4e25027b80de8e64b8b6fb542b3b41aa0caab9261da75752e22bfd rw,relatime - aufs none rw,si=9b4a76442810e39c -61 15 0:3404 / /var/lib/docker/aufs/mnt/956f6cc4af5785cb3ee6963dcbca668219437d9b28f513290b1453ac64a34f97 rw,relatime - aufs none rw,si=9b4a7644303ec39c -62 15 0:3405 / /var/lib/docker/aufs/mnt/1099769158c4b4773e2569e38024e8717e400f87a002c41d8cf47cb81b051ba6 rw,relatime - aufs none rw,si=9b4a7644303ee39c -63 15 0:3406 / /var/lib/docker/aufs/mnt/11890ceb98d4442595b676085cd7b21550ab85c5df841e0fba997ff54e3d522d rw,relatime - aufs none rw,si=9b4a7644303ed39c -64 15 0:3407 / /var/lib/docker/aufs/mnt/acdb90dc378e8ed2420b43a6d291f1c789a081cd1904018780cc038fcd7aae53 rw,relatime - aufs none rw,si=9b4a76434be2139c -65 15 0:3408 / /var/lib/docker/aufs/mnt/120e716f19d4714fbe63cc1ed246204f2c1106eefebc6537ba2587d7e7711959 rw,relatime - aufs none rw,si=9b4a76434be2339c -66 15 0:3409 / /var/lib/docker/aufs/mnt/b197b7fffb61d89e0ba1c40de9a9fc0d912e778b3c1bd828cf981ff37c1963bc rw,relatime - aufs none rw,si=9b4a76434be2039c -70 15 0:3412 / /var/lib/docker/aufs/mnt/1434b69d2e1bb18a9f0b96b9cdac30132b2688f5d1379f68a39a5e120c2f93eb rw,relatime - aufs none rw,si=9b4a76434be2639c -71 15 0:3413 / /var/lib/docker/aufs/mnt/16006e83caf33ab5eb0cd6afc92ea2ee8edeff897496b0bb3ec3a75b767374b3 rw,relatime - aufs none rw,si=9b4a7644d790439c -72 15 0:3414 / /var/lib/docker/aufs/mnt/55bfa5f44e94d27f91f79ba901b118b15098449165c87abf1b53ffff147ff164 rw,relatime - aufs none rw,si=9b4a7644d790239c -73 15 0:3415 / /var/lib/docker/aufs/mnt/1912b97a07ab21ccd98a2a27bc779bf3cf364a3138afa3c3e6f7f169a3c3eab5 rw,relatime - aufs none rw,si=9b4a76441822739c -76 15 0:3418 / /var/lib/docker/aufs/mnt/1a7c3292e8879bd91ffd9282e954f643b1db5683093574c248ff14a9609f2f56 rw,relatime - aufs none rw,si=9b4a76438cb7239c -77 15 0:3419 / /var/lib/docker/aufs/mnt/bb1faaf0d076ddba82c2318305a85f490dafa4e8a8640a8db8ed657c439120cc rw,relatime - aufs none rw,si=9b4a76438cb7339c -78 15 0:3420 / /var/lib/docker/aufs/mnt/1ab869f21d2241a73ac840c7f988490313f909ac642eba71d092204fec66dd7c rw,relatime - aufs none rw,si=9b4a76438cb7639c -79 15 0:3421 / /var/lib/docker/aufs/mnt/fd7245b2cfe3890fa5f5b452260e4edf9e7fb7746532ed9d83f7a0d7dbaa610e rw,relatime - aufs none rw,si=9b4a7644bdc0139c -80 15 0:3422 / /var/lib/docker/aufs/mnt/1e5686c5301f26b9b3cd24e322c608913465cc6c5d0dcd7c5e498d1314747d61 rw,relatime - aufs none rw,si=9b4a7644bdc0639c -81 15 0:3423 / /var/lib/docker/aufs/mnt/52edf6ee6e40bfec1e9301a4d4a92ab83d144e2ae4ce5099e99df6138cb844bf rw,relatime - aufs none rw,si=9b4a7644bdc0239c -82 15 0:3424 / /var/lib/docker/aufs/mnt/1ea10fb7085d28cda4904657dff0454e52598d28e1d77e4f2965bbc3666e808f rw,relatime - aufs none rw,si=9b4a76438cb7139c -83 15 0:3425 / /var/lib/docker/aufs/mnt/9c03e98c3593946dbd4087f8d83f9ca262f4a2efdc952ce60690838b9ba6c526 rw,relatime - aufs none rw,si=9b4a76443020639c -84 15 0:3426 / /var/lib/docker/aufs/mnt/220a2344d67437602c6d2cee9a98c46be13f82c2a8063919dd2fad52bf2fb7dd rw,relatime - aufs none rw,si=9b4a76434bff339c -94 15 0:3427 / /var/lib/docker/aufs/mnt/3b32876c5b200312c50baa476ff342248e88c8ea96e6a1032cd53a88738a1cf2 rw,relatime - aufs none rw,si=9b4a76434bff139c -95 15 0:3428 / /var/lib/docker/aufs/mnt/23ee2b8b0d4ae8db6f6d1e168e2c6f79f8a18f953b09f65e0d22cc1e67a3a6fa rw,relatime - aufs none rw,si=9b4a7646c305c39c -96 15 0:3429 / /var/lib/docker/aufs/mnt/e86e6daa70b61b57945fa178222615f3c3d6bcef12c9f28e9f8623d44dc2d429 rw,relatime - aufs none rw,si=9b4a7646c305f39c -97 15 0:3430 / /var/lib/docker/aufs/mnt/2413d07623e80860bb2e9e306fbdee699afd07525785c025c591231e864aa162 rw,relatime - aufs none rw,si=9b4a76434bff039c -98 15 0:3431 / /var/lib/docker/aufs/mnt/adfd622eb22340fc80b429e5564b125668e260bf9068096c46dd59f1386a4b7d rw,relatime - aufs none rw,si=9b4a7646a7a1039c -102 15 0:3435 / /var/lib/docker/aufs/mnt/27cd92e7a91d02e2d6b44d16679a00fb6d169b19b88822891084e7fd1a84882d rw,relatime - aufs none rw,si=9b4a7646f25ec39c -103 15 0:3436 / /var/lib/docker/aufs/mnt/27dfdaf94cfbf45055c748293c37dd68d9140240bff4c646cb09216015914a88 rw,relatime - aufs none rw,si=9b4a7646732f939c -104 15 0:3437 / /var/lib/docker/aufs/mnt/5ed7524aff68dfbf0fc601cbaeac01bab14391850a973dabf3653282a627920f rw,relatime - aufs none rw,si=9b4a7646732f839c -105 15 0:3438 / /var/lib/docker/aufs/mnt/2a0d4767e536beb5785b60e071e3ac8e5e812613ab143a9627bee77d0c9ab062 rw,relatime - aufs none rw,si=9b4a7646732fe39c -106 15 0:3439 / /var/lib/docker/aufs/mnt/dea3fc045d9f4ae51ba952450b948a822cf85c39411489ca5224f6d9a8d02bad rw,relatime - aufs none rw,si=9b4a764012ad839c -107 15 0:3440 / /var/lib/docker/aufs/mnt/2d140a787160798da60cb67c21b1210054ad4dafecdcf832f015995b9aa99cfd rw,relatime - aufs none rw,si=9b4a764012add39c -108 15 0:3441 / /var/lib/docker/aufs/mnt/cb190b2a8e984475914430fbad2382e0d20b9b659f8ef83ae8d170cc672e519c rw,relatime - aufs none rw,si=9b4a76454d9c239c -109 15 0:3442 / /var/lib/docker/aufs/mnt/2f4a012d5a7ffd90256a6e9aa479054b3dddbc3c6a343f26dafbf3196890223b rw,relatime - aufs none rw,si=9b4a76454d9c439c -110 15 0:3443 / /var/lib/docker/aufs/mnt/63cc77904b80c4ffbf49cb974c5d8733dc52ad7640d3ae87554b325d7312d87f rw,relatime - aufs none rw,si=9b4a76454d9c339c -111 15 0:3444 / /var/lib/docker/aufs/mnt/30333e872c451482ea2d235ff2192e875bd234006b238ae2bdde3b91a86d7522 rw,relatime - aufs none rw,si=9b4a76422cebf39c -112 15 0:3445 / /var/lib/docker/aufs/mnt/6c54fc1125da3925cae65b5c9a98f3be55b0a2c2666082e5094a4ba71beb5bff rw,relatime - aufs none rw,si=9b4a7646dd5a439c -113 15 0:3446 / /var/lib/docker/aufs/mnt/3087d48cb01cda9d0a83a9ca301e6ea40e8593d18c4921be4794c91a420ab9a3 rw,relatime - aufs none rw,si=9b4a7646dd5a739c -114 15 0:3447 / /var/lib/docker/aufs/mnt/cc2607462a8f55b179a749b144c3fdbb50678e1a4f3065ea04e283e9b1f1d8e2 rw,relatime - aufs none rw,si=9b4a7646dd5a239c -117 15 0:3450 / /var/lib/docker/aufs/mnt/310c5e8392b29e8658a22e08d96d63936633b7e2c38e8d220047928b00a03d24 rw,relatime - aufs none rw,si=9b4a7647932d739c -118 15 0:3451 / /var/lib/docker/aufs/mnt/38a1f0029406ba9c3b6058f2f406d8a1d23c855046cf355c91d87d446fcc1460 rw,relatime - aufs none rw,si=9b4a76445abc939c -119 15 0:3452 / /var/lib/docker/aufs/mnt/42e109ab7914ae997a11ccd860fd18e4d488c50c044c3240423ce15774b8b62e rw,relatime - aufs none rw,si=9b4a76445abca39c -120 15 0:3453 / /var/lib/docker/aufs/mnt/365d832af0402d052b389c1e9c0d353b48487533d20cd4351df8e24ec4e4f9d8 rw,relatime - aufs none rw,si=9b4a7644066aa39c -121 15 0:3454 / /var/lib/docker/aufs/mnt/d3fa8a24d695b6cda9b64f96188f701963d28bef0473343f8b212df1a2cf1d2b rw,relatime - aufs none rw,si=9b4a7644066af39c -122 15 0:3455 / /var/lib/docker/aufs/mnt/37d4f491919abc49a15d0c7a7cc8383f087573525d7d288accd14f0b4af9eae0 rw,relatime - aufs none rw,si=9b4a7644066ad39c -123 15 0:3456 / /var/lib/docker/aufs/mnt/93902707fe12cbdd0068ce73f2baad4b3a299189b1b19cb5f8a2025e106ae3f5 rw,relatime - aufs none rw,si=9b4a76444445f39c -126 15 0:3459 / /var/lib/docker/aufs/mnt/3b49291670a625b9bbb329ffba99bf7fa7abff80cefef040f8b89e2b3aad4f9f rw,relatime - aufs none rw,si=9b4a7640798a339c -127 15 0:3460 / /var/lib/docker/aufs/mnt/8d9c7b943cc8f854f4d0d4ec19f7c16c13b0cc4f67a41472a072648610cecb59 rw,relatime - aufs none rw,si=9b4a76427383039c -128 15 0:3461 / /var/lib/docker/aufs/mnt/3b6c90036526c376307df71d49c9f5fce334c01b926faa6a78186842de74beac rw,relatime - aufs none rw,si=9b4a7644badd439c -130 15 0:3463 / /var/lib/docker/aufs/mnt/7b24158eeddfb5d31b7e932e406ea4899fd728344335ff8e0765e89ddeb351dd rw,relatime - aufs none rw,si=9b4a7644badd539c -131 15 0:3464 / /var/lib/docker/aufs/mnt/3ead6dd5773765c74850cf6c769f21fe65c29d622ffa712664f9f5b80364ce27 rw,relatime - aufs none rw,si=9b4a7642f469939c -132 15 0:3465 / /var/lib/docker/aufs/mnt/3f825573b29547744a37b65597a9d6d15a8350be4429b7038d126a4c9a8e178f rw,relatime - aufs none rw,si=9b4a7642f469c39c -133 15 0:3466 / /var/lib/docker/aufs/mnt/f67aaaeb3681e5dcb99a41f847087370bd1c206680cb8c7b6a9819fd6c97a331 rw,relatime - aufs none rw,si=9b4a7647cc25939c -134 15 0:3467 / /var/lib/docker/aufs/mnt/41afe6cfb3c1fc2280b869db07699da88552786e28793f0bc048a265c01bd942 rw,relatime - aufs none rw,si=9b4a7647cc25c39c -135 15 0:3468 / /var/lib/docker/aufs/mnt/b8092ea59da34a40b120e8718c3ae9fa8436996edc4fc50e4b99c72dfd81e1af rw,relatime - aufs none rw,si=9b4a76445abc439c -136 15 0:3469 / /var/lib/docker/aufs/mnt/42c69d2cc179e2684458bb8596a9da6dad182c08eae9b74d5f0e615b399f75a5 rw,relatime - aufs none rw,si=9b4a76455ddbe39c -137 15 0:3470 / /var/lib/docker/aufs/mnt/ea0871954acd2d62a211ac60e05969622044d4c74597870c4f818fbb0c56b09b rw,relatime - aufs none rw,si=9b4a76455ddbf39c -138 15 0:3471 / /var/lib/docker/aufs/mnt/4307906b275ab3fc971786b3841ae3217ac85b6756ddeb7ad4ba09cd044c2597 rw,relatime - aufs none rw,si=9b4a76455ddb839c -139 15 0:3472 / /var/lib/docker/aufs/mnt/4390b872928c53500a5035634f3421622ed6299dc1472b631fc45de9f56dc180 rw,relatime - aufs none rw,si=9b4a76402f2fd39c -140 15 0:3473 / /var/lib/docker/aufs/mnt/6bb41e78863b85e4aa7da89455314855c8c3bda64e52a583bab15dc1fa2e80c2 rw,relatime - aufs none rw,si=9b4a76402f2fa39c -141 15 0:3474 / /var/lib/docker/aufs/mnt/4444f583c2a79c66608f4673a32c9c812154f027045fbd558c2d69920c53f835 rw,relatime - aufs none rw,si=9b4a764479dbd39c -142 15 0:3475 / /var/lib/docker/aufs/mnt/6f11883af4a05ea362e0c54df89058da4859f977efd07b6f539e1f55c1d2a668 rw,relatime - aufs none rw,si=9b4a76402f30b39c -143 15 0:3476 / /var/lib/docker/aufs/mnt/453490dd32e7c2e9ef906f995d8fb3c2753923d1a5e0ba3fd3296e2e4dc238e7 rw,relatime - aufs none rw,si=9b4a76402f30c39c -144 15 0:3477 / /var/lib/docker/aufs/mnt/45e5945735ee102b5e891c91650c57ec4b52bb53017d68f02d50ea8a6e230610 rw,relatime - aufs none rw,si=9b4a76423260739c -147 15 0:3480 / /var/lib/docker/aufs/mnt/4727a64a5553a1125f315b96bed10d3073d6988225a292cce732617c925b56ab rw,relatime - aufs none rw,si=9b4a76443030339c -150 15 0:3483 / /var/lib/docker/aufs/mnt/4e348b5187b9a567059306afc72d42e0ec5c893b0d4abd547526d5f9b6fb4590 rw,relatime - aufs none rw,si=9b4a7644f5d8c39c -151 15 0:3484 / /var/lib/docker/aufs/mnt/4efc616bfbc3f906718b052da22e4335f8e9f91ee9b15866ed3a8029645189ef rw,relatime - aufs none rw,si=9b4a7644f5d8939c -152 15 0:3485 / /var/lib/docker/aufs/mnt/83e730ae9754d5adb853b64735472d98dfa17136b8812ac9cfcd1eba7f4e7d2d rw,relatime - aufs none rw,si=9b4a76469aa7139c -153 15 0:3486 / /var/lib/docker/aufs/mnt/4fc5ba8a5b333be2b7eefacccb626772eeec0ae8a6975112b56c9fb36c0d342f rw,relatime - aufs none rw,si=9b4a7640128dc39c -154 15 0:3487 / /var/lib/docker/aufs/mnt/50200d5edff5dfe8d1ef3c78b0bbd709793ac6e936aa16d74ff66f7ea577b6f9 rw,relatime - aufs none rw,si=9b4a7640128da39c -155 15 0:3488 / /var/lib/docker/aufs/mnt/51e5e51604361448f0b9777f38329f414bc5ba9cf238f26d465ff479bd574b61 rw,relatime - aufs none rw,si=9b4a76444f68939c -156 15 0:3489 / /var/lib/docker/aufs/mnt/52a142149aa98bba83df8766bbb1c629a97b9799944ead90dd206c4bdf0b8385 rw,relatime - aufs none rw,si=9b4a76444f68b39c -157 15 0:3490 / /var/lib/docker/aufs/mnt/52dd21a94a00f58a1ed489312fcfffb91578089c76c5650364476f1d5de031bc rw,relatime - aufs none rw,si=9b4a76444f68f39c -158 15 0:3491 / /var/lib/docker/aufs/mnt/ee562415ddaad353ed22c88d0ca768a0c74bfba6333b6e25c46849ee22d990da rw,relatime - aufs none rw,si=9b4a7640128d839c -159 15 0:3492 / /var/lib/docker/aufs/mnt/db47a9e87173f7554f550c8a01891de79cf12acdd32e01f95c1a527a08bdfb2c rw,relatime - aufs none rw,si=9b4a764405a1d39c -160 15 0:3493 / /var/lib/docker/aufs/mnt/55e827bf6d44d930ec0b827c98356eb8b68c3301e2d60d1429aa72e05b4c17df rw,relatime - aufs none rw,si=9b4a764405a1a39c -162 15 0:3495 / /var/lib/docker/aufs/mnt/578dc4e0a87fc37ec081ca098430499a59639c09f6f12a8f48de29828a091aa6 rw,relatime - aufs none rw,si=9b4a76406d7d439c -163 15 0:3496 / /var/lib/docker/aufs/mnt/728cc1cb04fa4bc6f7bf7a90980beda6d8fc0beb71630874c0747b994efb0798 rw,relatime - aufs none rw,si=9b4a76444f20e39c -164 15 0:3497 / /var/lib/docker/aufs/mnt/5850cc4bd9b55aea46c7ad598f1785117607974084ea643580f58ce3222e683a rw,relatime - aufs none rw,si=9b4a7644a824239c -165 15 0:3498 / /var/lib/docker/aufs/mnt/89443b3f766d5a37bc8b84e29da8b84e6a3ea8486d3cf154e2aae1816516e4a8 rw,relatime - aufs none rw,si=9b4a7644a824139c -166 15 0:3499 / /var/lib/docker/aufs/mnt/f5ae8fd5a41a337907d16515bc3162525154b59c32314c695ecd092c3b47943d rw,relatime - aufs none rw,si=9b4a7644a824439c -167 15 0:3500 / /var/lib/docker/aufs/mnt/5a430854f2a03a9e5f7cbc9f3fb46a8ebca526a5b3f435236d8295e5998798f5 rw,relatime - aufs none rw,si=9b4a7647fc82439c -168 15 0:3501 / /var/lib/docker/aufs/mnt/eda16901ae4cead35070c39845cbf1e10bd6b8cb0ffa7879ae2d8a186e460f91 rw,relatime - aufs none rw,si=9b4a76441e0df39c -169 15 0:3502 / /var/lib/docker/aufs/mnt/5a593721430c2a51b119ff86a7e06ea2b37e3b4131f8f1344d402b61b0c8d868 rw,relatime - aufs none rw,si=9b4a764248bad39c -170 15 0:3503 / /var/lib/docker/aufs/mnt/d662ad0a30fbfa902e0962108685b9330597e1ee2abb16dc9462eb5a67fdd23f rw,relatime - aufs none rw,si=9b4a764248bae39c -171 15 0:3504 / /var/lib/docker/aufs/mnt/5bc9de5c79812843fb36eee96bef1ddba812407861f572e33242f4ee10da2c15 rw,relatime - aufs none rw,si=9b4a764248ba839c -172 15 0:3505 / /var/lib/docker/aufs/mnt/5e763de8e9b0f7d58d2e12a341e029ab4efb3b99788b175090d8209e971156c1 rw,relatime - aufs none rw,si=9b4a764248baa39c -173 15 0:3506 / /var/lib/docker/aufs/mnt/b4431dc2739936f1df6387e337f5a0c99cf051900c896bd7fd46a870ce61c873 rw,relatime - aufs none rw,si=9b4a76401263539c -174 15 0:3507 / /var/lib/docker/aufs/mnt/5f37830e5a02561ab8c67ea3113137ba69f67a60e41c05cb0e7a0edaa1925b24 rw,relatime - aufs none rw,si=9b4a76401263639c -184 15 0:3508 / /var/lib/docker/aufs/mnt/62ea10b957e6533538a4633a1e1d678502f50ddcdd354b2ca275c54dd7a7793a rw,relatime - aufs none rw,si=9b4a76401263039c -187 15 0:3509 / /var/lib/docker/aufs/mnt/d56ee9d44195fe390e042fda75ec15af5132adb6d5c69468fa8792f4e54a6953 rw,relatime - aufs none rw,si=9b4a76401263239c -188 15 0:3510 / /var/lib/docker/aufs/mnt/6a300930673174549c2b62f36c933f0332a20735978c007c805a301f897146c5 rw,relatime - aufs none rw,si=9b4a76455d4c539c -189 15 0:3511 / /var/lib/docker/aufs/mnt/64496c45c84d348c24d410015456d101601c30cab4d1998c395591caf7e57a70 rw,relatime - aufs none rw,si=9b4a76455d4c639c -190 15 0:3512 / /var/lib/docker/aufs/mnt/65a6a645883fe97a7422cd5e71ebe0bc17c8e6302a5361edf52e89747387e908 rw,relatime - aufs none rw,si=9b4a76455d4c039c -191 15 0:3513 / /var/lib/docker/aufs/mnt/672be40695f7b6e13b0a3ed9fc996c73727dede3481f58155950fcfad57ed616 rw,relatime - aufs none rw,si=9b4a76455d4c239c -192 15 0:3514 / /var/lib/docker/aufs/mnt/d42438acb2bfb2169e1c0d8e917fc824f7c85d336dadb0b0af36dfe0f001b3ba rw,relatime - aufs none rw,si=9b4a7642bfded39c -193 15 0:3515 / /var/lib/docker/aufs/mnt/b48a54abf26d01cb2ddd908b1ed6034d17397c1341bf0eb2b251a3e5b79be854 rw,relatime - aufs none rw,si=9b4a7642bfdee39c -194 15 0:3516 / /var/lib/docker/aufs/mnt/76f27134491f052bfb87f59092126e53ef875d6851990e59195a9da16a9412f8 rw,relatime - aufs none rw,si=9b4a7642bfde839c -195 15 0:3517 / /var/lib/docker/aufs/mnt/6bd626a5462b4f8a8e1cc7d10351326dca97a59b2758e5ea549a4f6350ce8a90 rw,relatime - aufs none rw,si=9b4a7642bfdea39c -196 15 0:3518 / /var/lib/docker/aufs/mnt/f1fe3549dbd6f5ca615e9139d9b53f0c83a3b825565df37628eacc13e70cbd6d rw,relatime - aufs none rw,si=9b4a7642bfdf539c -197 15 0:3519 / /var/lib/docker/aufs/mnt/6d0458c8426a9e93d58d0625737e6122e725c9408488ed9e3e649a9984e15c34 rw,relatime - aufs none rw,si=9b4a7642bfdf639c -198 15 0:3520 / /var/lib/docker/aufs/mnt/6e4c97db83aa82145c9cf2bafc20d500c0b5389643b689e3ae84188c270a48c5 rw,relatime - aufs none rw,si=9b4a7642bfdf039c -199 15 0:3521 / /var/lib/docker/aufs/mnt/eb94d6498f2c5969eaa9fa11ac2934f1ab90ef88e2d002258dca08e5ba74ea27 rw,relatime - aufs none rw,si=9b4a7642bfdf239c -200 15 0:3522 / /var/lib/docker/aufs/mnt/fe3f88f0c511608a2eec5f13a98703aa16e55dbf930309723d8a37101f539fe1 rw,relatime - aufs none rw,si=9b4a7642bfc3539c -201 15 0:3523 / /var/lib/docker/aufs/mnt/6f40c229fb9cad85fabf4b64a2640a5403ec03fe5ac1a57d0609fb8b606b9c83 rw,relatime - aufs none rw,si=9b4a7642bfc3639c -202 15 0:3524 / /var/lib/docker/aufs/mnt/7513e9131f7a8acf58ff15248237feb767c78732ca46e159f4d791e6ef031dbc rw,relatime - aufs none rw,si=9b4a7642bfc3039c -203 15 0:3525 / /var/lib/docker/aufs/mnt/79f48b00aa713cdf809c6bb7c7cb911b66e9a8076c81d6c9d2504139984ea2da rw,relatime - aufs none rw,si=9b4a7642bfc3239c -204 15 0:3526 / /var/lib/docker/aufs/mnt/c3680418350d11358f0a96c676bc5aa74fa00a7c89e629ef5909d3557b060300 rw,relatime - aufs none rw,si=9b4a7642f47cd39c -205 15 0:3527 / /var/lib/docker/aufs/mnt/7a1744dd350d7fcc0cccb6f1757ca4cbe5453f203a5888b0f1014d96ad5a5ef9 rw,relatime - aufs none rw,si=9b4a7642f47ce39c -206 15 0:3528 / /var/lib/docker/aufs/mnt/7fa99662db046be9f03c33c35251afda9ccdc0085636bbba1d90592cec3ff68d rw,relatime - aufs none rw,si=9b4a7642f47c839c -207 15 0:3529 / /var/lib/docker/aufs/mnt/f815021ef20da9c9b056bd1d52d8aaf6e2c0c19f11122fc793eb2b04eb995e35 rw,relatime - aufs none rw,si=9b4a7642f47ca39c -208 15 0:3530 / /var/lib/docker/aufs/mnt/801086ae3110192d601dfcebdba2db92e86ce6b6a9dba6678ea04488e4513669 rw,relatime - aufs none rw,si=9b4a7642dc6dd39c -209 15 0:3531 / /var/lib/docker/aufs/mnt/822ba7db69f21daddda87c01cfbfbf73013fc03a879daf96d16cdde6f9b1fbd6 rw,relatime - aufs none rw,si=9b4a7642dc6de39c -210 15 0:3532 / /var/lib/docker/aufs/mnt/834227c1a950fef8cae3827489129d0dd220541e60c6b731caaa765bf2e6a199 rw,relatime - aufs none rw,si=9b4a7642dc6d839c -211 15 0:3533 / /var/lib/docker/aufs/mnt/83dccbc385299bd1c7cf19326e791b33a544eea7b4cdfb6db70ea94eed4389fb rw,relatime - aufs none rw,si=9b4a7642dc6da39c -212 15 0:3534 / /var/lib/docker/aufs/mnt/f1b8e6f0e7c8928b5dcdab944db89306ebcae3e0b32f9ff40d2daa8329f21600 rw,relatime - aufs none rw,si=9b4a7645a126039c -213 15 0:3535 / /var/lib/docker/aufs/mnt/970efb262c7a020c2404cbcc5b3259efba0d110a786079faeef05bc2952abf3a rw,relatime - aufs none rw,si=9b4a7644c8ed139c -214 15 0:3536 / /var/lib/docker/aufs/mnt/84b6d73af7450f3117a77e15a5ca1255871fea6182cd8e8a7be6bc744be18c2c rw,relatime - aufs none rw,si=9b4a76406559139c -215 15 0:3537 / /var/lib/docker/aufs/mnt/88be2716e026bc681b5e63fe7942068773efbd0b6e901ca7ba441412006a96b6 rw,relatime - aufs none rw,si=9b4a76406559339c -216 15 0:3538 / /var/lib/docker/aufs/mnt/c81939aa166ce50cd8bca5cfbbcc420a78e0318dd5cd7c755209b9166a00a752 rw,relatime - aufs none rw,si=9b4a76406559239c -217 15 0:3539 / /var/lib/docker/aufs/mnt/e0f241645d64b7dc5ff6a8414087cca226be08fb54ce987d1d1f6350c57083aa rw,relatime - aufs none rw,si=9b4a7647cfc0f39c -218 15 0:3540 / /var/lib/docker/aufs/mnt/e10e2bf75234ed51d8a6a4bb39e465404fecbe318e54400d3879cdb2b0679c78 rw,relatime - aufs none rw,si=9b4a7647cfc0939c -219 15 0:3541 / /var/lib/docker/aufs/mnt/8f71d74c8cfc3228b82564aa9f09b2e576cff0083ddfb6aa5cb350346063f080 rw,relatime - aufs none rw,si=9b4a7647cfc0a39c -220 15 0:3542 / /var/lib/docker/aufs/mnt/9159f1eba2aef7f5205cc18d015cda7f5933cd29bba3b1b8aed5ccb5824c69ee rw,relatime - aufs none rw,si=9b4a76468cedd39c -221 15 0:3543 / /var/lib/docker/aufs/mnt/932cad71e652e048e500d9fbb5b8ea4fc9a269d42a3134ce527ceef42a2be56b rw,relatime - aufs none rw,si=9b4a76468cede39c -222 15 0:3544 / /var/lib/docker/aufs/mnt/bf1e1b5f529e8943cc0144ee86dbaaa37885c1ddffcef29537e0078ee7dd316a rw,relatime - aufs none rw,si=9b4a76468ced839c -223 15 0:3545 / /var/lib/docker/aufs/mnt/949d93ecf3322e09f858ce81d5f4b434068ec44ff84c375de03104f7b45ee955 rw,relatime - aufs none rw,si=9b4a76468ceda39c -224 15 0:3546 / /var/lib/docker/aufs/mnt/d65c6087f92dc2a3841b5251d2fe9ca07d4c6e5b021597692479740816e4e2a1 rw,relatime - aufs none rw,si=9b4a7645a126239c -225 15 0:3547 / /var/lib/docker/aufs/mnt/98a0153119d0651c193d053d254f6e16a68345a141baa80c87ae487e9d33f290 rw,relatime - aufs none rw,si=9b4a7640787cf39c -226 15 0:3548 / /var/lib/docker/aufs/mnt/99daf7fe5847c017392f6e59aa9706b3dfdd9e6d1ba11dae0f7fffde0a60b5e5 rw,relatime - aufs none rw,si=9b4a7640787c839c -227 15 0:3549 / /var/lib/docker/aufs/mnt/9ad1f2fe8a5599d4e10c5a6effa7f03d932d4e92ee13149031a372087a359079 rw,relatime - aufs none rw,si=9b4a7640787ca39c -228 15 0:3550 / /var/lib/docker/aufs/mnt/c26d64494da782ddac26f8370d86ac93e7c1666d88a7b99110fc86b35ea6a85d rw,relatime - aufs none rw,si=9b4a7642fc6b539c -229 15 0:3551 / /var/lib/docker/aufs/mnt/a49e4a8275133c230ec640997f35f172312eb0ea5bd2bbe10abf34aae98f30eb rw,relatime - aufs none rw,si=9b4a7642fc6b639c -230 15 0:3552 / /var/lib/docker/aufs/mnt/b5e2740c867ed843025f49d84e8d769de9e8e6039b3c8cb0735b5bf358994bc7 rw,relatime - aufs none rw,si=9b4a7642fc6b039c -231 15 0:3553 / /var/lib/docker/aufs/mnt/a826fdcf3a7039b30570054579b65763db605a314275d7aef31b872c13311b4b rw,relatime - aufs none rw,si=9b4a7642fc6b239c -232 15 0:3554 / /var/lib/docker/aufs/mnt/addf3025babf5e43b5a3f4a0da7ad863dda3c01fb8365c58fd8d28bb61dc11bc rw,relatime - aufs none rw,si=9b4a76407871d39c -233 15 0:3555 / /var/lib/docker/aufs/mnt/c5b6c6813ab3e5ebdc6d22cb2a3d3106a62095f2c298be52b07a3b0fa20ff690 rw,relatime - aufs none rw,si=9b4a76407871e39c -234 15 0:3556 / /var/lib/docker/aufs/mnt/af0609eaaf64e2392060cb46f5a9f3d681a219bb4c651d4f015bf573fbe6c4cf rw,relatime - aufs none rw,si=9b4a76407871839c -235 15 0:3557 / /var/lib/docker/aufs/mnt/e7f20e3c37ecad39cd90a97cd3549466d0d106ce4f0a930b8495442634fa4a1f rw,relatime - aufs none rw,si=9b4a76407871a39c -237 15 0:3559 / /var/lib/docker/aufs/mnt/b57a53d440ffd0c1295804fa68cdde35d2fed5409484627e71b9c37e4249fd5c rw,relatime - aufs none rw,si=9b4a76444445a39c -238 15 0:3560 / /var/lib/docker/aufs/mnt/b5e7d7b8f35e47efbba3d80c5d722f5e7bd43e54c824e54b4a4b351714d36d42 rw,relatime - aufs none rw,si=9b4a7647932d439c -239 15 0:3561 / /var/lib/docker/aufs/mnt/f1b136def157e9465640658f277f3347de593c6ae76412a2e79f7002f091cae2 rw,relatime - aufs none rw,si=9b4a76445abcd39c -240 15 0:3562 / /var/lib/docker/aufs/mnt/b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc rw,relatime - aufs none rw,si=9b4a7644403b339c -241 15 0:3563 / /var/lib/docker/aufs/mnt/b89b140cdbc95063761864e0a23346207fa27ee4c5c63a1ae85c9069a9d9cf1d rw,relatime - aufs none rw,si=9b4a7644aa19739c -242 15 0:3564 / /var/lib/docker/aufs/mnt/bc6a69ed51c07f5228f6b4f161c892e6a949c0e7e86a9c3432049d4c0e5cd298 rw,relatime - aufs none rw,si=9b4a7644aa19139c -243 15 0:3565 / /var/lib/docker/aufs/mnt/be4e2ba3f136933e239f7cf3d136f484fb9004f1fbdfee24a62a2c7b0ab30670 rw,relatime - aufs none rw,si=9b4a7644aa19339c -244 15 0:3566 / /var/lib/docker/aufs/mnt/e04ca1a4a5171e30d20f0c92f90a50b8b6f8600af5459c4b4fb25e42e864dfe1 rw,relatime - aufs none rw,si=9b4a7647932d139c -245 15 0:3567 / /var/lib/docker/aufs/mnt/be61576b31db893129aaffcd3dcb5ce35e49c4b71b30c392a78609a45c7323d8 rw,relatime - aufs none rw,si=9b4a7642d85f739c -246 15 0:3568 / /var/lib/docker/aufs/mnt/dda42c191e56becf672327658ab84fcb563322db3764b91c2fefe4aaef04c624 rw,relatime - aufs none rw,si=9b4a7642d85f139c -247 15 0:3569 / /var/lib/docker/aufs/mnt/c0a7995053330f3d88969247a2e72b07e2dd692133f5668a4a35ea3905561072 rw,relatime - aufs none rw,si=9b4a7642d85f339c -249 15 0:3571 / /var/lib/docker/aufs/mnt/c3594b2e5f08c59ff5ed338a1ba1eceeeb1f7fc5d180068338110c00b1eb8502 rw,relatime - aufs none rw,si=9b4a7642738c739c -250 15 0:3572 / /var/lib/docker/aufs/mnt/c58dce03a0ab0a7588393880379dc3bce9f96ec08ed3f99cf1555260ff0031e8 rw,relatime - aufs none rw,si=9b4a7642738c139c -251 15 0:3573 / /var/lib/docker/aufs/mnt/c73e9f1d109c9d14cb36e1c7489df85649be3911116d76c2fd3648ec8fd94e23 rw,relatime - aufs none rw,si=9b4a7642738c339c -252 15 0:3574 / /var/lib/docker/aufs/mnt/c9eef28c344877cd68aa09e543c0710ab2b305a0ff96dbb859bfa7808c3e8d01 rw,relatime - aufs none rw,si=9b4a7642d85f439c -253 15 0:3575 / /var/lib/docker/aufs/mnt/feb67148f548d70cb7484f2aaad2a86051cd6867a561741a2f13b552457d666e rw,relatime - aufs none rw,si=9b4a76468c55739c -254 15 0:3576 / /var/lib/docker/aufs/mnt/cdf1f96c36d35a96041a896bf398ec0f7dc3b0fb0643612a0f4b6ff96e04e1bb rw,relatime - aufs none rw,si=9b4a76468c55139c -255 15 0:3577 / /var/lib/docker/aufs/mnt/ec6e505872353268451ac4bc034c1df00f3bae4a3ea2261c6e48f7bd5417c1b3 rw,relatime - aufs none rw,si=9b4a76468c55339c -256 15 0:3578 / /var/lib/docker/aufs/mnt/d6dc8aca64efd90e0bc10274001882d0efb310d42ccbf5712b99b169053b8b1a rw,relatime - aufs none rw,si=9b4a7642738c439c -257 15 0:3579 / /var/lib/docker/aufs/mnt/d712594e2ff6eaeb895bfd150d694bd1305fb927e7a186b2dab7df2ea95f8f81 rw,relatime - aufs none rw,si=9b4a76401268f39c -259 15 0:3581 / /var/lib/docker/aufs/mnt/dbfa1174cd78cde2d7410eae442af0b416c4a0e6f87ed4ff1e9f169a0029abc0 rw,relatime - aufs none rw,si=9b4a76401268b39c -260 15 0:3582 / /var/lib/docker/aufs/mnt/e883f5a82316d7856fbe93ee8c0af5a920b7079619dd95c4ffd88bbd309d28dd rw,relatime - aufs none rw,si=9b4a76468c55439c -261 15 0:3583 / /var/lib/docker/aufs/mnt/fdec3eff581c4fc2b09f87befa2fa021f3f2d373bea636a87f1fb5b367d6347a rw,relatime - aufs none rw,si=9b4a7644aa1af39c -262 15 0:3584 / /var/lib/docker/aufs/mnt/ef764e26712184653067ecf7afea18a80854c41331ca0f0ef03e1bacf90a6ffc rw,relatime - aufs none rw,si=9b4a7644aa1a939c -263 15 0:3585 / /var/lib/docker/aufs/mnt/f3176b40c41fce8ce6942936359a2001a6f1b5c1bb40ee224186db0789ec2f76 rw,relatime - aufs none rw,si=9b4a7644aa1ab39c -264 15 0:3586 / /var/lib/docker/aufs/mnt/f5daf06785d3565c6dd18ea7d953d9a8b9606107781e63270fe0514508736e6a rw,relatime - aufs none rw,si=9b4a76401268c39c -58 15 0:3587 / /var/lib/docker/aufs/mnt/cde8c40f6524b7361af4f5ad05bb857dc9ee247c20852ba666195c0739e3a2b8-init rw,relatime - aufs none rw,si=9b4a76444445839c -67 15 0:3588 / /var/lib/docker/aufs/mnt/cde8c40f6524b7361af4f5ad05bb857dc9ee247c20852ba666195c0739e3a2b8 rw,relatime - aufs none rw,si=9b4a7644badd339c -265 15 0:3610 / /var/lib/docker/aufs/mnt/e812472cd2c8c4748d1ef71fac4e77e50d661b9349abe66ce3e23511ed44f414 rw,relatime - aufs none rw,si=9b4a76427937d39c -270 15 0:3615 / /var/lib/docker/aufs/mnt/997636e7c5c9d0d1376a217e295c14c205350b62bc12052804fb5f90abe6f183 rw,relatime - aufs none rw,si=9b4a76406540739c -273 15 0:3618 / /var/lib/docker/aufs/mnt/d5794d080417b6e52e69227c3873e0e4c1ff0d5a845ebe3860ec2f89a47a2a1e rw,relatime - aufs none rw,si=9b4a76454814039c -278 15 0:3623 / /var/lib/docker/aufs/mnt/586bdd48baced671bb19bc4d294ec325f26c55545ae267db426424f157d59c48 rw,relatime - aufs none rw,si=9b4a7644b439f39c -281 15 0:3626 / /var/lib/docker/aufs/mnt/69739d022f89f8586908bbd5edbbdd95ea5256356f177f9ffcc6ef9c0ea752d2 rw,relatime - aufs none rw,si=9b4a7644a0f1b39c -286 15 0:3631 / /var/lib/docker/aufs/mnt/ff28c27d5f894363993622de26d5dd352dba072f219e4691d6498c19bbbc15a9 rw,relatime - aufs none rw,si=9b4a7642265b339c -289 15 0:3634 / /var/lib/docker/aufs/mnt/aa128fe0e64fdede333aa48fd9de39530c91a9244a0f0649a3c411c61e372daa rw,relatime - aufs none rw,si=9b4a764012ada39c -99 15 8:33 / /media/REMOVE\040ME rw,nosuid,nodev,relatime - fuseblk /dev/sdc1 rw,user_id=0,group_id=0,allow_other,blksize=4096` - - mountInfoWithSpaces = `486 28 252:1 / /mnt/foo\040bar rw,relatime shared:243 - ext4 /dev/vda1 rw,data=ordered -31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1` -) - -func TestParseFedoraMountinfo(t *testing.T) { - r := bytes.NewBuffer([]byte(fedoraMountinfo)) - _, err := parseInfoFile(r) - if err != nil { - t.Fatal(err) - } -} - -func TestParseUbuntuMountinfo(t *testing.T) { - r := bytes.NewBuffer([]byte(ubuntuMountInfo)) - _, err := parseInfoFile(r) - if err != nil { - t.Fatal(err) - } -} - -func TestParseGentooMountinfo(t *testing.T) { - r := bytes.NewBuffer([]byte(gentooMountinfo)) - _, err := parseInfoFile(r) - if err != nil { - t.Fatal(err) - } -} - -func TestParseFedoraMountinfoFields(t *testing.T) { - r := bytes.NewBuffer([]byte(fedoraMountinfo)) - infos, err := parseInfoFile(r) - if err != nil { - t.Fatal(err) - } - expectedLength := 58 - if len(infos) != expectedLength { - t.Fatalf("Expected %d entries, got %d", expectedLength, len(infos)) - } - mi := Info{ - ID: 15, - Parent: 35, - Major: 0, - Minor: 3, - Root: "/", - Mountpoint: "/proc", - Options: "rw,nosuid,nodev,noexec,relatime", - Optional: "shared:5", - FSType: "proc", - Source: "proc", - VFSOptions: "rw", - } - - if infos[0] != mi { - t.Fatalf("expected %#v, got %#v", mi, infos[0]) - } -} - -func TestParseMountinfoWithSpaces(t *testing.T) { - r := bytes.NewBuffer([]byte(mountInfoWithSpaces)) - infos, err := parseInfoFile(r) - if err != nil { - t.Fatal(err) - } - expected := []Info{ - { - ID: 486, - Parent: 28, - Major: 252, - Minor: 1, - Root: "/", - Mountpoint: "/mnt/foo bar", - Options: "rw,relatime", - Optional: "shared:243", - FSType: "ext4", - Source: "/dev/vda1", - VFSOptions: "rw,data=ordered", - }, - { - ID: 31, - Parent: 21, - Major: 0, - Minor: 23, - Root: "/", - Mountpoint: "/DATA/foo_bla_bla", - Options: "rw,relatime", - Optional: "", - FSType: "cifs", - Source: `//foo/BLA\040BLA\040BLA/`, - VFSOptions: `rw,sec=ntlm,cache=loose,unc=\\foo\BLA`, - }, - } - - if len(infos) != len(expected) { - t.Fatalf("expected %d entries, got %d", len(expected), len(infos)) - } - for i, mi := range expected { - if infos[i] != mi { - t.Fatalf("expected %#v, got %#v", mi, infos[i]) - } - } -} diff -Nru containerd-1.2.6/mount/mountinfo_unsupported.go containerd-1.5.9/mount/mountinfo_unsupported.go --- containerd-1.2.6/mount/mountinfo_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mountinfo_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -// +build !linux,!freebsd,!solaris,!openbsd freebsd,!cgo solaris,!cgo openbsd,!cgo - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package mount - -import ( - "fmt" - "runtime" -) - -// Self retrieves a list of mounts for the current running process. -func Self() ([]Info, error) { - return nil, fmt.Errorf("mountinfo.Self is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} - -// PID collects the mounts for a specific process ID. -func PID(pid int) ([]Info, error) { - return nil, fmt.Errorf("mountinfo.PID is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff -Nru containerd-1.2.6/mount/mount_linux.go containerd-1.5.9/mount/mount_linux.go --- containerd-1.2.6/mount/mount_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mount_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,7 @@ import ( "fmt" "os" + "os/exec" "path" "strings" "time" @@ -28,14 +29,27 @@ "golang.org/x/sys/unix" ) -var pagesize = 4096 +var ( + pagesize = 4096 + allowedHelperBinaries = []string{"mount.fuse", "mount.fuse3"} +) func init() { pagesize = os.Getpagesize() } -// Mount to the provided target path -func (m *Mount) Mount(target string) error { +// Mount to the provided target path. +// +// If m.Type starts with "fuse." or "fuse3.", "mount.fuse" or "mount.fuse3" +// helper binary is called. +func (m *Mount) Mount(target string) (err error) { + for _, helperBinary := range allowedHelperBinaries { + // helperBinary = "mount.fuse", typePrefix = "fuse." + typePrefix := strings.TrimPrefix(helperBinary, "mount.") + "." + if strings.HasPrefix(m.Type, typePrefix) { + return m.mountWithHelper(helperBinary, typePrefix, target) + } + } var ( chdir string options = m.Options @@ -48,7 +62,7 @@ chdir, options = compactLowerdirOption(options) } - flags, data := parseMountOptions(options) + flags, data, losetup := parseMountOptions(options) if len(data) > pagesize { return errors.Errorf("mount options is too long") } @@ -63,7 +77,20 @@ if flags&unix.MS_REMOUNT == 0 || data != "" { // Initial call applying all non-propagation flags for mount // or remount with changed data - if err := mountAt(chdir, m.Source, target, m.Type, uintptr(oflags), data); err != nil { + source := m.Source + if losetup { + loFile, err := setupLoop(m.Source, LoopParams{ + Readonly: oflags&unix.MS_RDONLY == unix.MS_RDONLY, + Autoclear: true}) + if err != nil { + return err + } + defer loFile.Close() + + // Mount the loop device instead + source = loFile.Name() + } + if err := mountAt(chdir, source, target, m.Type, uintptr(oflags), data); err != nil { return err } } @@ -92,7 +119,39 @@ return nil } +// fuseSuperMagic is defined in statfs(2) +const fuseSuperMagic = 0x65735546 + +func isFUSE(dir string) bool { + var st unix.Statfs_t + if err := unix.Statfs(dir, &st); err != nil { + return false + } + return st.Type == fuseSuperMagic +} + +// unmountFUSE attempts to unmount using fusermount/fusermount3 helper binary. +// +// For FUSE mounts, using these helper binaries is preferred, see: +// https://github.com/containerd/containerd/pull/3765#discussion_r342083514 +func unmountFUSE(target string) error { + var err error + for _, helperBinary := range []string{"fusermount3", "fusermount"} { + cmd := exec.Command(helperBinary, "-u", target) + err = cmd.Run() + if err == nil { + return nil + } + } + return err +} + func unmount(target string, flags int) error { + if isFUSE(target) { + if err := unmountFUSE(target); err == nil { + return nil + } + } for i := 0; i < 50; i++ { if err := unix.Unmount(target, flags); err != nil { switch err { @@ -111,7 +170,18 @@ // UnmountAll repeatedly unmounts the given mount point until there // are no mounts remaining (EINVAL is returned by mount), which is // useful for undoing a stack of mounts on the same mount point. +// UnmountAll all is noop when the first argument is an empty string. +// This is done when the containerd client did not specify any rootfs +// mounts (e.g. because the rootfs is managed outside containerd) +// UnmountAll is noop when the mount path does not exist. func UnmountAll(mount string, flags int) error { + if mount == "" { + return nil + } + if _, err := os.Stat(mount); os.IsNotExist(err) { + return nil + } + for { if err := unmount(mount, flags); err != nil { // EINVAL is returned if the target is not a @@ -129,11 +199,13 @@ // parseMountOptions takes fstab style mount options and parses them for // use with a standard mount() syscall -func parseMountOptions(options []string) (int, string) { +func parseMountOptions(options []string) (int, string, bool) { var ( - flag int - data []string + flag int + losetup bool + data []string ) + loopOpt := "loop" flags := map[string]struct { clear bool flag int @@ -174,11 +246,13 @@ } else { flag |= f.flag } + } else if o == loopOpt { + losetup = true } else { data = append(data, o) } } - return flag, strings.Join(data, ",") + return flag, strings.Join(data, ","), losetup } // compactLowerdirOption updates overlay lowdir option and returns the common @@ -306,3 +380,45 @@ } return errors.Wrap(sys.FMountat(f.Fd(), source, target, fstype, flags, data), "failed to mountat") } + +func (m *Mount) mountWithHelper(helperBinary, typePrefix, target string) error { + // helperBinary: "mount.fuse3" + // target: "/foo/merged" + // m.Type: "fuse3.fuse-overlayfs" + // command: "mount.fuse3 overlay /foo/merged -o lowerdir=/foo/lower2:/foo/lower1,upperdir=/foo/upper,workdir=/foo/work -t fuse-overlayfs" + args := []string{m.Source, target} + for _, o := range m.Options { + args = append(args, "-o", o) + } + args = append(args, "-t", strings.TrimPrefix(m.Type, typePrefix)) + + infoBeforeMount, err := Lookup(target) + if err != nil { + return err + } + + // cmd.CombinedOutput() may intermittently return ECHILD because of our signal handling in shim. + // See #4387 and wait(2). + const retriesOnECHILD = 10 + for i := 0; i < retriesOnECHILD; i++ { + cmd := exec.Command(helperBinary, args...) + out, err := cmd.CombinedOutput() + if err == nil { + return nil + } + if !errors.Is(err, unix.ECHILD) { + return errors.Wrapf(err, "mount helper [%s %v] failed: %q", helperBinary, args, string(out)) + } + // We got ECHILD, we are not sure whether the mount was successful. + // If the mount ID has changed, we are sure we got some new mount, but still not sure it is fully completed. + // So we attempt to unmount the new mount before retrying. + infoAfterMount, err := Lookup(target) + if err != nil { + return err + } + if infoAfterMount.ID != infoBeforeMount.ID { + _ = unmount(target, 0) + } + } + return errors.Errorf("mount helper [%s %v] failed with ECHILD (retired %d times)", helperBinary, args, retriesOnECHILD) +} diff -Nru containerd-1.2.6/mount/mount_linux_test.go containerd-1.5.9/mount/mount_linux_test.go --- containerd-1.2.6/mount/mount_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mount_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,8 +19,15 @@ package mount import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "reflect" "testing" + + "github.com/containerd/continuity/testutil" ) func TestLongestCommonPrefix(t *testing.T) { @@ -92,3 +99,41 @@ } } } + +func TestFUSEHelper(t *testing.T) { + testutil.RequiresRoot(t) + const fuseoverlayfsBinary = "fuse-overlayfs" + _, err := exec.LookPath(fuseoverlayfsBinary) + if err != nil { + t.Skip("fuse-overlayfs not installed") + } + td, err := ioutil.TempDir("", "fuse") + if err != nil { + t.Fatal(err) + } + defer func() { + if err := os.RemoveAll(td); err != nil { + t.Fatal(err) + } + }() + + for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { + if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { + t.Fatal(err) + } + } + + opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", filepath.Join(td, "lower2"), filepath.Join(td, "lower1"), filepath.Join(td, "upper"), filepath.Join(td, "work")) + m := Mount{ + Type: "fuse3." + fuseoverlayfsBinary, + Source: "overlay", + Options: []string{opts}, + } + dest := filepath.Join(td, "merged") + if err := m.Mount(dest); err != nil { + t.Fatal(err) + } + if err := UnmountAll(dest, 0); err != nil { + t.Fatal(err) + } +} diff -Nru containerd-1.2.6/mount/mount_unix.go containerd-1.5.9/mount/mount_unix.go --- containerd-1.2.6/mount/mount_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/mount_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build darwin freebsd openbsd +// +build darwin openbsd /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/mount/temp_unix.go containerd-1.5.9/mount/temp_unix.go --- containerd-1.2.6/mount/temp_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/mount/temp_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,7 +22,8 @@ "os" "path/filepath" "sort" - "strings" + + "github.com/moby/sys/mountinfo" ) // SetTempMountLocation sets the temporary mount location @@ -40,23 +41,20 @@ // CleanupTempMounts all temp mounts and remove the directories func CleanupTempMounts(flags int) (warnings []error, err error) { - mounts, err := Self() + mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(tempMountLocation)) if err != nil { return nil, err } - var toUnmount []string - for _, m := range mounts { - if strings.HasPrefix(m.Mountpoint, tempMountLocation) { - toUnmount = append(toUnmount, m.Mountpoint) - } - } - sort.Sort(sort.Reverse(sort.StringSlice(toUnmount))) - for _, path := range toUnmount { - if err := UnmountAll(path, flags); err != nil { + // Make the deepest mount be first + sort.Slice(mounts, func(i, j int) bool { + return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint) + }) + for _, mount := range mounts { + if err := UnmountAll(mount.Mountpoint, flags); err != nil { warnings = append(warnings, err) continue } - if err := os.Remove(path); err != nil { + if err := os.Remove(mount.Mountpoint); err != nil { warnings = append(warnings, err) } } diff -Nru containerd-1.2.6/namespaces/context.go containerd-1.5.9/namespaces/context.go --- containerd-1.2.6/namespaces/context.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/namespaces/context.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "os" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/identifiers" "github.com/pkg/errors" ) @@ -36,10 +37,9 @@ // WithNamespace sets a given namespace on the context func WithNamespace(ctx context.Context, namespace string) context.Context { ctx = context.WithValue(ctx, namespaceKey{}, namespace) // set our key for namespace - - // also store on the grpc headers so it gets picked up by any clients that + // also store on the grpc and ttrpc headers so it gets picked up by any clients that // are using this. - return withGRPCNamespaceHeader(ctx, namespace) + return withTTRPCNamespaceHeader(withGRPCNamespaceHeader(ctx, namespace), namespace) } // NamespaceFromEnv uses the namespace defined in CONTAINERD_NAMESPACE or @@ -58,22 +58,21 @@ func Namespace(ctx context.Context) (string, bool) { namespace, ok := ctx.Value(namespaceKey{}).(string) if !ok { - return fromGRPCHeader(ctx) + if namespace, ok = fromGRPCHeader(ctx); !ok { + return fromTTRPCHeader(ctx) + } } - return namespace, ok } -// NamespaceRequired returns the valid namepace from the context or an error. +// NamespaceRequired returns the valid namespace from the context or an error. func NamespaceRequired(ctx context.Context) (string, error) { namespace, ok := Namespace(ctx) if !ok || namespace == "" { return "", errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace is required") } - - if err := Validate(namespace); err != nil { + if err := identifiers.Validate(namespace); err != nil { return "", errors.Wrap(err, "namespace validation") } - return namespace, nil } diff -Nru containerd-1.2.6/namespaces/store.go containerd-1.5.9/namespaces/store.go --- containerd-1.2.6/namespaces/store.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/namespaces/store.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,5 +33,14 @@ List(ctx context.Context) ([]string, error) // Delete removes the namespace. The namespace must be empty to be deleted. - Delete(ctx context.Context, namespace string) error + Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error } + +// DeleteInfo specifies information for the deletion of a namespace +type DeleteInfo struct { + // Name of the namespace + Name string +} + +// DeleteOpts allows the caller to set options for namespace deletion +type DeleteOpts func(context.Context, *DeleteInfo) error diff -Nru containerd-1.2.6/namespaces/ttrpc.go containerd-1.5.9/namespaces/ttrpc.go --- containerd-1.2.6/namespaces/ttrpc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/namespaces/ttrpc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package namespaces + +import ( + "context" + + "github.com/containerd/ttrpc" +) + +const ( + // TTRPCHeader defines the header name for specifying a containerd namespace + TTRPCHeader = "containerd-namespace-ttrpc" +) + +func copyMetadata(src ttrpc.MD) ttrpc.MD { + md := ttrpc.MD{} + for k, v := range src { + md[k] = append(md[k], v...) + } + return md +} + +func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context { + md, ok := ttrpc.GetMetadata(ctx) + if !ok { + md = ttrpc.MD{} + } else { + md = copyMetadata(md) + } + md.Set(TTRPCHeader, namespace) + return ttrpc.WithMetadata(ctx, md) +} + +func fromTTRPCHeader(ctx context.Context) (string, bool) { + return ttrpc.GetMetadataValue(ctx, TTRPCHeader) +} diff -Nru containerd-1.2.6/namespaces/ttrpc_test.go containerd-1.5.9/namespaces/ttrpc_test.go --- containerd-1.2.6/namespaces/ttrpc_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/namespaces/ttrpc_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package namespaces + +import ( + "context" + "reflect" + "testing" + + "github.com/containerd/ttrpc" +) + +func TestCopyTTRPCMetadata(t *testing.T) { + src := ttrpc.MD{} + src.Set("key", "a", "b", "c", "d") + md := copyMetadata(src) + + if !reflect.DeepEqual(src, md) { + t.Fatalf("metadata is copied incorrectly") + } + + slice, _ := src.Get("key") + slice[0] = "z" + if reflect.DeepEqual(src, md) { + t.Fatalf("metadata is copied incorrectly") + } +} + +func TestTTRPCNamespaceHeader(t *testing.T) { + ctx := context.Background() + namespace := "test-namespace" + ctx = withTTRPCNamespaceHeader(ctx, namespace) + + header, ok := fromTTRPCHeader(ctx) + if !ok || header != namespace { + t.Fatalf("ttrp namespace header is set incorrectly") + } +} diff -Nru containerd-1.2.6/namespaces/validate.go containerd-1.5.9/namespaces/validate.go --- containerd-1.2.6/namespaces/validate.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/namespaces/validate.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Package namespaces provides tools for working with namespaces across -// containerd. -// -// Namespaces collect resources such as containers and images, into a unique -// identifier space. This means that two applications can use the same -// identifiers and not conflict while using containerd. -// -// This package can be used to ensure that client and server functions -// correctly store the namespace on the context. -package namespaces - -import ( - "regexp" - - "github.com/containerd/containerd/errdefs" - "github.com/pkg/errors" -) - -const ( - maxLength = 76 - alpha = `[A-Za-z]` - alphanum = `[A-Za-z0-9]+` - label = alpha + alphanum + `(:?[-]+` + alpha + alphanum + `)*` -) - -var ( - // namespaceRe validates that a namespace matches valid identifiers. - // - // Rules for domains, defined in RFC 1035, section 2.3.1, are used for - // namespaces. - namespaceRe = regexp.MustCompile(reAnchor(label + reGroup("[.]"+reGroup(label)) + "*")) -) - -// Validate returns nil if the string s is a valid namespace. -// -// To allow such namespace identifiers to be used across various contexts -// safely, the character set has been restricted to that defined for domains in -// RFC 1035, section 2.3.1. This will make namespace identifiers safe for use -// across networks, filesystems and other media. -// -// The identifier specification departs from RFC 1035 in that it allows -// "labels" to start with number and only enforces a total length restriction -// of 76 characters. -// -// While the character set may be expanded in the future, namespace identifiers -// are guaranteed to be safely used as filesystem path components. -// -// For the most part, this doesn't need to be called directly when using the -// context-oriented functions. -func Validate(s string) error { - if len(s) > maxLength { - return errors.Wrapf(errdefs.ErrInvalidArgument, "namespace %q greater than maximum length (%d characters)", s, maxLength) - } - - if !namespaceRe.MatchString(s) { - return errors.Wrapf(errdefs.ErrInvalidArgument, "namespace %q must match %v", s, namespaceRe) - } - return nil -} - -func reGroup(s string) string { - return `(?:` + s + `)` -} - -func reAnchor(s string) string { - return `^` + s + `$` -} diff -Nru containerd-1.2.6/namespaces/validate_test.go containerd-1.5.9/namespaces/validate_test.go --- containerd-1.2.6/namespaces/validate_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/namespaces/validate_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package namespaces - -import ( - "strings" - "testing" - - "github.com/containerd/containerd/errdefs" -) - -func TestValidNamespaces(t *testing.T) { - for _, input := range []string{ - "default", - "Default", - t.Name(), - "default-default", - "default--default", - "containerd.io", - "foo.boo", - "swarmkit.docker.io", - "zn--e9.org", // or something like it! - strings.Repeat("a", maxLength), - } { - t.Run(input, func(t *testing.T) { - if err := Validate(input); err != nil { - t.Fatalf("unexpected error: %v != nil", err) - } - }) - } -} - -func TestInvalidNamespaces(t *testing.T) { - for _, input := range []string{ - ".foo..foo", - "foo/foo", - "foo/..", - "foo..foo", - "foo.-boo", - "foo.-boo.bar", - "-foo.boo", - "foo.boo-", - "foo_foo.boo_underscores", // boo-urns? - "0912341234", - "task.0.0123456789", - strings.Repeat("a", maxLength+1), - } { - - t.Run(input, func(t *testing.T) { - if err := Validate(input); err == nil { - t.Fatal("expected invalid error") - } else if !errdefs.IsInvalidArgument(err) { - t.Fatal("error should be an invalid identifier error") - } - }) - } -} diff -Nru containerd-1.2.6/namespaces.go containerd-1.5.9/namespaces.go --- containerd-1.2.6/namespaces.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/namespaces.go 2022-01-05 17:30:58.000000000 +0000 @@ -100,10 +100,18 @@ return namespaces, nil } -func (r *remoteNamespaces) Delete(ctx context.Context, namespace string) error { - var req api.DeleteNamespaceRequest - - req.Name = namespace +func (r *remoteNamespaces) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { + i := namespaces.DeleteInfo{ + Name: namespace, + } + for _, o := range opts { + if err := o(ctx, &i); err != nil { + return err + } + } + req := api.DeleteNamespaceRequest{ + Name: namespace, + } _, err := r.client.Delete(ctx, &req) if err != nil { return errdefs.FromGRPC(err) diff -Nru containerd-1.2.6/oci/spec.go containerd-1.5.9/oci/spec.go --- containerd-1.2.6/oci/spec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/oci/spec.go 2022-01-05 17:30:58.000000000 +0000 @@ -78,7 +78,7 @@ return err } -// ApplyOpts applys the options to the given spec, injecting data from the +// ApplyOpts applies the options to the given spec, injecting data from the // context, client and container instance. func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error { for _, o := range opts { @@ -141,7 +141,6 @@ Path: defaultRootfsPath, }, Process: &specs.Process{ - Env: defaultUnixEnv, Cwd: "/", NoNewPrivileges: true, User: specs.User{ @@ -247,17 +246,8 @@ Root: &specs.Root{}, Process: &specs.Process{ Cwd: `C:\`, - ConsoleSize: &specs.Box{ - Width: 80, - Height: 20, - }, - }, - Windows: &specs.Windows{ - IgnoreFlushesDuringBoot: true, - Network: &specs.WindowsNetwork{ - AllowUnqualifiedDNSQuery: true, - }, }, + Windows: &specs.Windows{}, } return nil } diff -Nru containerd-1.2.6/oci/spec_opts.go containerd-1.5.9/oci/spec_opts.go --- containerd-1.2.6/oci/spec_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package oci import ( + "bufio" "context" "encoding/json" "fmt" @@ -33,11 +34,10 @@ "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/platforms" "github.com/containerd/continuity/fs" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runc/libcontainer/user" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/syndtr/gocapability/capability" ) // SpecOpts sets spec specific information to a newly generated OCI spec @@ -76,6 +76,35 @@ } } +// nolint +func setResources(s *Spec) { + if s.Linux != nil { + if s.Linux.Resources == nil { + s.Linux.Resources = &specs.LinuxResources{} + } + } + if s.Windows != nil { + if s.Windows.Resources == nil { + s.Windows.Resources = &specs.WindowsResources{} + } + } +} + +// nolint +func setCPU(s *Spec) { + setResources(s) + if s.Linux != nil { + if s.Linux.Resources.CPU == nil { + s.Linux.Resources.CPU = &specs.LinuxCPU{} + } + } + if s.Windows != nil { + if s.Windows.Resources.CPU == nil { + s.Windows.Resources.CPU = &specs.WindowsCPUResources{} + } + } +} + // setCapabilities sets Linux Capabilities to empty if unset func setCapabilities(s *Spec) { setProcess(s) @@ -104,7 +133,7 @@ } } -// WithSpecFromBytes loads the the spec from the provided byte slice. +// WithSpecFromBytes loads the spec from the provided byte slice. func WithSpecFromBytes(p []byte) SpecOpts { return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { *s = Spec{} // make sure spec is cleared. @@ -137,12 +166,21 @@ } } +// WithDefaultPathEnv sets the $PATH environment variable to the +// default PATH defined in this package. +func WithDefaultPathEnv(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, defaultUnixEnv) + return nil +} + // replaceOrAppendEnvValues returns the defaults with the overrides either // replaced by env key or appended to the list func replaceOrAppendEnvValues(defaults, overrides []string) []string { cache := make(map[string]int, len(defaults)) + results := make([]string, 0, len(defaults)) for i, e := range defaults { parts := strings.SplitN(e, "=", 2) + results = append(results, e) cache[parts[0]] = i } @@ -150,7 +188,7 @@ // Values w/o = means they want this env to be removed/unset. if !strings.Contains(value, "=") { if i, exists := cache[value]; exists { - defaults[i] = "" // Used to indicate it should be removed + results[i] = "" // Used to indicate it should be removed } continue } @@ -158,21 +196,21 @@ // Just do a normal set/update parts := strings.SplitN(value, "=", 2) if i, exists := cache[parts[0]]; exists { - defaults[i] = value + results[i] = value } else { - defaults = append(defaults, value) + results = append(results, value) } } // Now remove all entries that we want to "unset" - for i := 0; i < len(defaults); i++ { - if defaults[i] == "" { - defaults = append(defaults[:i], defaults[i+1:]...) + for i := 0; i < len(results); i++ { + if results[i] == "" { + results = append(results[:i], results[i+1:]...) i-- } } - return defaults + return results } // WithProcessArgs replaces the args on the generated spec @@ -235,6 +273,28 @@ } } +// WithoutMounts removes mounts +func WithoutMounts(dests ...string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + var ( + mounts []specs.Mount + current = s.Mounts + ) + mLoop: + for _, m := range current { + mDestination := filepath.Clean(m.Destination) + for _, dest := range dests { + if mDestination == dest { + continue mLoop + } + } + mounts = append(mounts, m) + } + s.Mounts = mounts + return nil + } +} + // WithHostNamespace allows a task to run inside the host's linux namespace func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts { return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { @@ -256,10 +316,7 @@ setLinux(s) for i, n := range s.Linux.Namespaces { if n.Type == ns.Type { - before := s.Linux.Namespaces[:i] - after := s.Linux.Namespaces[i+1:] - s.Linux.Namespaces = append(before, ns) - s.Linux.Namespaces = append(s.Linux.Namespaces, after...) + s.Linux.Namespaces[i] = ns return nil } } @@ -310,7 +367,11 @@ setProcess(s) if s.Linux != nil { - s.Process.Env = append(s.Process.Env, config.Env...) + defaults := config.Env + if len(defaults) == 0 { + defaults = defaultUnixEnv + } + s.Process.Env = replaceOrAppendEnvValues(defaults, s.Process.Env) cmd := config.Cmd if len(args) > 0 { cmd = args @@ -332,8 +393,14 @@ // even if there is no specified user in the image config return WithAdditionalGIDs("root")(ctx, client, c, s) } else if s.Windows != nil { - s.Process.Env = config.Env - s.Process.Args = append(config.Entrypoint, config.Cmd...) + s.Process.Env = replaceOrAppendEnvValues(config.Env, s.Process.Env) + cmd := config.Cmd + if len(args) > 0 { + cmd = args + } + s.Process.Args = append(config.Entrypoint, cmd...) + + s.Process.Cwd = config.WorkingDir s.Process.User = specs.User{ Username: config.User, } @@ -405,7 +472,7 @@ // WithUserNamespace sets the uid and gid mappings for the task // this can be called multiple times to add more mappings to the generated spec -func WithUserNamespace(container, host, size uint32) SpecOpts { +func WithUserNamespace(uidMap, gidMap []specs.LinuxIDMapping) SpecOpts { return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { var hasUserns bool setLinux(s) @@ -420,13 +487,8 @@ Type: specs.UserNamespace, }) } - mapping := specs.LinuxIDMapping{ - ContainerID: container, - HostID: host, - Size: size, - } - s.Linux.UIDMappings = append(s.Linux.UIDMappings, mapping) - s.Linux.GIDMappings = append(s.Linux.GIDMappings, mapping) + s.Linux.UIDMappings = append(s.Linux.UIDMappings, uidMap...) + s.Linux.GIDMappings = append(s.Linux.GIDMappings, gidMap...) return nil } } @@ -492,7 +554,7 @@ } f := func(root string) error { if username != "" { - user, err := getUserFromPath(root, func(u user.User) bool { + user, err := UserFromPath(root, func(u user.User) bool { return u.Name == username }) if err != nil { @@ -501,7 +563,7 @@ uid = uint32(user.Uid) } if groupname != "" { - gid, err = getGIDFromPath(root, func(g user.Group) bool { + gid, err = GIDFromPath(root, func(g user.Group) bool { return g.Name == groupname }) if err != nil { @@ -556,11 +618,11 @@ if !isRootfsAbs(s.Root.Path) { return errors.Errorf("rootfs absolute path is required") } - user, err := getUserFromPath(s.Root.Path, func(u user.User) bool { + user, err := UserFromPath(s.Root.Path, func(u user.User) bool { return u.Uid == int(uid) }) if err != nil { - if os.IsNotExist(err) || err == errNoUsersFound { + if os.IsNotExist(err) || err == ErrNoUsersFound { s.Process.User.UID, s.Process.User.GID = uid, 0 return nil } @@ -582,11 +644,11 @@ return err } return mount.WithTempMount(ctx, mounts, func(root string) error { - user, err := getUserFromPath(root, func(u user.User) bool { + user, err := UserFromPath(root, func(u user.User) bool { return u.Uid == int(uid) }) if err != nil { - if os.IsNotExist(err) || err == errNoUsersFound { + if os.IsNotExist(err) || err == ErrNoUsersFound { s.Process.User.UID, s.Process.User.GID = uid, 0 return nil } @@ -599,7 +661,7 @@ } // WithUsername sets the correct UID and GID for the container -// based on the the image's /etc/passwd contents. If /etc/passwd +// based on the image's /etc/passwd contents. If /etc/passwd // does not exist, or the username is not found in /etc/passwd, // it returns error. func WithUsername(username string) SpecOpts { @@ -610,7 +672,7 @@ if !isRootfsAbs(s.Root.Path) { return errors.Errorf("rootfs absolute path is required") } - user, err := getUserFromPath(s.Root.Path, func(u user.User) bool { + user, err := UserFromPath(s.Root.Path, func(u user.User) bool { return u.Name == username }) if err != nil { @@ -631,7 +693,7 @@ return err } return mount.WithTempMount(ctx, mounts, func(root string) error { - user, err := getUserFromPath(root, func(u user.User) bool { + user, err := UserFromPath(root, func(u user.User) bool { return u.Name == username }) if err != nil { @@ -663,11 +725,11 @@ var username string uid, err := strconv.Atoi(userstr) if err == nil { - user, err := getUserFromPath(root, func(u user.User) bool { + user, err := UserFromPath(root, func(u user.User) bool { return u.Uid == uid }) if err != nil { - if os.IsNotExist(err) || err == errNoUsersFound { + if os.IsNotExist(err) || err == ErrNoUsersFound { return nil } return err @@ -732,25 +794,62 @@ } } -// WithAllCapabilities sets all linux capabilities for the process -var WithAllCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { - return WithCapabilities(getAllCapabilities())(ctx, client, c, s) +func capsContain(caps []string, s string) bool { + for _, c := range caps { + if c == s { + return true + } + } + return false } -func getAllCapabilities() []string { - last := capability.CAP_LAST_CAP - // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap - if last == capability.Cap(63) { - last = capability.CAP_BLOCK_SUSPEND - } - var caps []string - for _, cap := range capability.List() { - if cap > last { +func removeCap(caps *[]string, s string) { + var newcaps []string + for _, c := range *caps { + if c == s { continue } - caps = append(caps, "CAP_"+strings.ToUpper(cap.String())) + newcaps = append(newcaps, c) + } + *caps = newcaps +} + +// WithAddedCapabilities adds the provided capabilities +func WithAddedCapabilities(caps []string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setCapabilities(s) + for _, c := range caps { + for _, cl := range []*[]string{ + &s.Process.Capabilities.Bounding, + &s.Process.Capabilities.Effective, + &s.Process.Capabilities.Permitted, + &s.Process.Capabilities.Inheritable, + } { + if !capsContain(*cl, c) { + *cl = append(*cl, c) + } + } + } + return nil + } +} + +// WithDroppedCapabilities removes the provided capabilities +func WithDroppedCapabilities(caps []string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setCapabilities(s) + for _, c := range caps { + for _, cl := range []*[]string{ + &s.Process.Capabilities.Bounding, + &s.Process.Capabilities.Effective, + &s.Process.Capabilities.Permitted, + &s.Process.Capabilities.Inheritable, + } { + removeCap(cl, c) + } + } + return nil } - return caps } // WithAmbientCapabilities set the Linux ambient capabilities for the process @@ -765,9 +864,12 @@ } } -var errNoUsersFound = errors.New("no users found") +// ErrNoUsersFound can be returned from UserFromPath +var ErrNoUsersFound = errors.New("no users found") -func getUserFromPath(root string, filter func(user.User) bool) (user.User, error) { +// UserFromPath inspects the user object using /etc/passwd in the specified rootfs. +// filter can be nil. +func UserFromPath(root string, filter func(user.User) bool) (user.User, error) { ppath, err := fs.RootPath(root, "/etc/passwd") if err != nil { return user.User{}, err @@ -777,14 +879,17 @@ return user.User{}, err } if len(users) == 0 { - return user.User{}, errNoUsersFound + return user.User{}, ErrNoUsersFound } return users[0], nil } -var errNoGroupsFound = errors.New("no groups found") +// ErrNoGroupsFound can be returned from GIDFromPath +var ErrNoGroupsFound = errors.New("no groups found") -func getGIDFromPath(root string, filter func(user.Group) bool) (gid uint32, err error) { +// GIDFromPath inspects the GID using /etc/passwd in the specified rootfs. +// filter can be nil. +func GIDFromPath(root string, filter func(user.Group) bool) (gid uint32, err error) { gpath, err := fs.RootPath(root, "/etc/group") if err != nil { return 0, err @@ -794,7 +899,7 @@ return 0, err } if len(groups) == 0 { - return 0, errNoGroupsFound + return 0, ErrNoGroupsFound } g := groups[0] return uint32(g.Gid), nil @@ -844,16 +949,13 @@ // WithWriteableSysfs makes any sysfs mounts writeable func WithWriteableSysfs(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { - for i, m := range s.Mounts { + for _, m := range s.Mounts { if m.Type == "sysfs" { - var options []string - for _, o := range m.Options { + for i, o := range m.Options { if o == "ro" { - o = "rw" + m.Options[i] = "rw" } - options = append(options, o) } - s.Mounts[i].Options = options } } return nil @@ -861,16 +963,13 @@ // WithWriteableCgroupfs makes any cgroup mounts writeable func WithWriteableCgroupfs(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { - for i, m := range s.Mounts { + for _, m := range s.Mounts { if m.Type == "cgroup" { - var options []string - for _, o := range m.Options { + for i, o := range m.Options { if o == "ro" { - o = "rw" + m.Options[i] = "rw" } - options = append(options, o) } - s.Mounts[i].Options = options } } return nil @@ -912,6 +1011,21 @@ return nil } +// WithAllDevicesAllowed permits READ WRITE MKNOD on all devices nodes for the container +func WithAllDevicesAllowed(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + if s.Linux.Resources == nil { + s.Linux.Resources = &specs.LinuxResources{} + } + s.Linux.Resources.Devices = []specs.LinuxDeviceCgroup{ + { + Allow: true, + Access: rwm, + }, + } + return nil +} + // WithDefaultUnixDevices adds the default devices for unix such as /dev/null, /dev/random to // the container's resource cgroup spec func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { @@ -1006,9 +1120,8 @@ } // WithPrivileged sets up options for a privileged container -// TODO(justincormack) device handling var WithPrivileged = Compose( - WithAllCapabilities, + WithAllCurrentCapabilities, WithMaskedPaths(nil), WithReadonlyPaths(nil), WithWriteableSysfs, @@ -1028,3 +1141,126 @@ } return nil } + +// WithMemoryLimit sets the `Linux.LinuxResources.Memory.Limit` section to the +// `limit` specified if the `Linux` section is not `nil`. Additionally sets the +// `Windows.WindowsResources.Memory.Limit` section if the `Windows` section is +// not `nil`. +func WithMemoryLimit(limit uint64) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + if s.Linux != nil { + if s.Linux.Resources == nil { + s.Linux.Resources = &specs.LinuxResources{} + } + if s.Linux.Resources.Memory == nil { + s.Linux.Resources.Memory = &specs.LinuxMemory{} + } + l := int64(limit) + s.Linux.Resources.Memory.Limit = &l + } + if s.Windows != nil { + if s.Windows.Resources == nil { + s.Windows.Resources = &specs.WindowsResources{} + } + if s.Windows.Resources.Memory == nil { + s.Windows.Resources.Memory = &specs.WindowsMemoryResources{} + } + s.Windows.Resources.Memory.Limit = &limit + } + return nil + } +} + +// WithAnnotations appends or replaces the annotations on the spec with the +// provided annotations +func WithAnnotations(annotations map[string]string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + if s.Annotations == nil { + s.Annotations = make(map[string]string) + } + for k, v := range annotations { + s.Annotations[k] = v + } + return nil + } +} + +// WithLinuxDevices adds the provided linux devices to the spec +func WithLinuxDevices(devices []specs.LinuxDevice) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + s.Linux.Devices = append(s.Linux.Devices, devices...) + return nil + } +} + +// WithLinuxDevice adds the device specified by path to the spec +func WithLinuxDevice(path, permissions string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + setResources(s) + + dev, err := deviceFromPath(path) + if err != nil { + return err + } + + s.Linux.Devices = append(s.Linux.Devices, *dev) + + s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{ + Type: dev.Type, + Allow: true, + Major: &dev.Major, + Minor: &dev.Minor, + Access: permissions, + }) + + return nil + } +} + +// WithEnvFile adds environment variables from a file to the container's spec +func WithEnvFile(path string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + var vars []string + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + sc := bufio.NewScanner(f) + for sc.Scan() { + vars = append(vars, sc.Text()) + } + if err = sc.Err(); err != nil { + return err + } + return WithEnv(vars)(nil, nil, nil, s) + } +} + +// ErrNoShmMount is returned when there is no /dev/shm mount specified in the config +// and an Opts was trying to set a configuration value on the mount. +var ErrNoShmMount = errors.New("no /dev/shm mount specified") + +// WithDevShmSize sets the size of the /dev/shm mount for the container. +// +// The size value is specified in kb, kilobytes. +func WithDevShmSize(kb int64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + for _, m := range s.Mounts { + if m.Source == "shm" && m.Type == "tmpfs" { + for i, o := range m.Options { + if strings.HasPrefix(o, "size=") { + m.Options[i] = fmt.Sprintf("size=%dk", kb) + return nil + } + } + m.Options = append(m.Options, fmt.Sprintf("size=%dk", kb)) + return nil + } + } + return ErrNoShmMount + } +} diff -Nru containerd-1.2.6/oci/spec_opts_linux.go containerd-1.5.9/oci/spec_opts_linux.go --- containerd-1.2.6/oci/spec_opts_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,145 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/pkg/cap" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +// WithHostDevices adds all the hosts device nodes to the container's spec +func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + + devs, err := HostDevices() + if err != nil { + return err + } + s.Linux.Devices = append(s.Linux.Devices, devs...) + return nil +} + +// WithDevices recursively adds devices from the passed in path and associated cgroup rules for that device. +// If devicePath is a dir it traverses the dir to add all devices in that dir. +// If devicePath is not a dir, it attempts to add the single device. +// If containerPath is not set then the device path is used for the container path. +func WithDevices(devicePath, containerPath, permissions string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + devs, err := getDevices(devicePath, containerPath) + if err != nil { + return err + } + for i := range devs { + s.Linux.Devices = append(s.Linux.Devices, devs[i]) + s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, specs.LinuxDeviceCgroup{ + Allow: true, + Type: devs[i].Type, + Major: &devs[i].Major, + Minor: &devs[i].Minor, + Access: permissions, + }) + } + return nil + } +} + +// WithMemorySwap sets the container's swap in bytes +func WithMemorySwap(swap int64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setResources(s) + if s.Linux.Resources.Memory == nil { + s.Linux.Resources.Memory = &specs.LinuxMemory{} + } + s.Linux.Resources.Memory.Swap = &swap + return nil + } +} + +// WithPidsLimit sets the container's pid limit or maximum +func WithPidsLimit(limit int64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setResources(s) + if s.Linux.Resources.Pids == nil { + s.Linux.Resources.Pids = &specs.LinuxPids{} + } + s.Linux.Resources.Pids.Limit = limit + return nil + } +} + +// WithCPUShares sets the container's cpu shares +func WithCPUShares(shares uint64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setCPU(s) + s.Linux.Resources.CPU.Shares = &shares + return nil + } +} + +// WithCPUs sets the container's cpus/cores for use by the container +func WithCPUs(cpus string) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setCPU(s) + s.Linux.Resources.CPU.Cpus = cpus + return nil + } +} + +// WithCPUsMems sets the container's cpu mems for use by the container +func WithCPUsMems(mems string) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setCPU(s) + s.Linux.Resources.CPU.Mems = mems + return nil + } +} + +// WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period +func WithCPUCFS(quota int64, period uint64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + setCPU(s) + s.Linux.Resources.CPU.Quota = "a + s.Linux.Resources.CPU.Period = &period + return nil + } +} + +// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process. +// The capability set may differ from WithAllKnownCapabilities when running in a container. +var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { + caps, err := cap.Current() + if err != nil { + return err + } + return WithCapabilities(caps)(ctx, client, c, s) +} + +// WithAllKnownCapabilities sets all the the known linux capabilities for the container process +var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { + caps := cap.Known() + return WithCapabilities(caps)(ctx, client, c, s) +} + +// WithoutRunMount removes the `/run` inside the spec +func WithoutRunMount(ctx context.Context, client Client, c *containers.Container, s *Spec) error { + return WithoutMounts("/run")(ctx, client, c, s) +} diff -Nru containerd-1.2.6/oci/spec_opts_linux_test.go containerd-1.5.9/oci/spec_opts_linux_test.go --- containerd-1.2.6/oci/spec_opts_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,254 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/containerd/containerd/pkg/testutil" + specs "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/sys/unix" +) + +func TestAddCaps(t *testing.T) { + t.Parallel() + + var s specs.Spec + + if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + for i, cl := range [][]string{ + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, + s.Process.Capabilities.Inheritable, + } { + if !capsContain(cl, "CAP_CHOWN") { + t.Errorf("cap list %d does not contain added cap", i) + } + } +} + +func TestDropCaps(t *testing.T) { + t.Parallel() + + var s specs.Spec + + if err := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + + for i, cl := range [][]string{ + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, + s.Process.Capabilities.Inheritable, + } { + if capsContain(cl, "CAP_CHOWN") { + t.Errorf("cap list %d contains dropped cap", i) + } + } + + // Add all capabilities back and drop a different cap. + if err := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + if err := WithDroppedCapabilities([]string{"CAP_FOWNER"})(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + + for i, cl := range [][]string{ + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, + s.Process.Capabilities.Inheritable, + } { + if capsContain(cl, "CAP_FOWNER") { + t.Errorf("cap list %d contains dropped cap", i) + } + if !capsContain(cl, "CAP_CHOWN") { + t.Errorf("cap list %d doesn't contain non-dropped cap", i) + } + } + + // Drop all duplicated caps. + if err := WithCapabilities([]string{"CAP_CHOWN", "CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil { + t.Fatal(err) + } + for i, cl := range [][]string{ + s.Process.Capabilities.Bounding, + s.Process.Capabilities.Effective, + s.Process.Capabilities.Permitted, + s.Process.Capabilities.Inheritable, + } { + if len(cl) != 0 { + t.Errorf("cap list %d is not empty", i) + } + } +} + +func TestGetDevices(t *testing.T) { + testutil.RequiresRoot(t) + + dir, err := ioutil.TempDir("/dev", t.Name()) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + zero := filepath.Join(dir, "zero") + if err := ioutil.WriteFile(zero, nil, 0600); err != nil { + t.Fatal(err) + } + + if err := unix.Mount("/dev/zero", zero, "", unix.MS_BIND, ""); err != nil { + t.Fatal(err) + } + defer unix.Unmount(filepath.Join(dir, "zero"), unix.MNT_DETACH) + + t.Run("single device", func(t *testing.T) { + t.Run("no container path", func(t *testing.T) { + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + + if len(devices) != 1 { + t.Fatalf("expected one device %v", devices) + } + if devices[0].Path != zero { + t.Fatalf("got unexpected device path %s", devices[0].Path) + } + }) + t.Run("with container path", func(t *testing.T) { + newPath := "/dev/testNew" + devices, err := getDevices(dir, newPath) + if err != nil { + t.Fatal(err) + } + + if len(devices) != 1 { + t.Fatalf("expected one device %v", devices) + } + if devices[0].Path != filepath.Join(newPath, "zero") { + t.Fatalf("got unexpected device path %s", devices[0].Path) + } + }) + }) + t.Run("two devices", func(t *testing.T) { + nullDev := filepath.Join(dir, "null") + if err := ioutil.WriteFile(nullDev, nil, 0600); err != nil { + t.Fatal(err) + } + + if err := unix.Mount("/dev/null", nullDev, "", unix.MS_BIND, ""); err != nil { + t.Fatal(err) + } + defer unix.Unmount(filepath.Join(dir, "null"), unix.MNT_DETACH) + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + + if len(devices) != 2 { + t.Fatalf("expected two devices %v", devices) + } + if devices[0].Path == devices[1].Path { + t.Fatalf("got same path for the two devices %s", devices[0].Path) + } + if devices[0].Path != zero && devices[0].Path != nullDev { + t.Fatalf("got unexpected device path %s", devices[0].Path) + } + if devices[1].Path != zero && devices[1].Path != nullDev { + t.Fatalf("got unexpected device path %s", devices[1].Path) + } + if devices[0].Major == devices[1].Major && devices[0].Minor == devices[1].Minor { + t.Fatalf("got sema mojor and minor on two devices %s %s", devices[0].Path, devices[1].Path) + } + }) + t.Run("With symlink in dir", func(t *testing.T) { + if err := os.Symlink("/dev/zero", filepath.Join(dir, "zerosym")); err != nil { + t.Fatal(err) + } + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + if len(devices) != 1 { + t.Fatalf("expected one device %v", devices) + } + if devices[0].Path != filepath.Join(dir, "zero") { + t.Fatalf("got unexpected device path, expected %q, got %q", filepath.Join(dir, "zero"), devices[0].Path) + } + }) + t.Run("No devices", func(t *testing.T) { + dir := dir + "2" + if err := os.MkdirAll(dir, 0755); err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + t.Run("empty dir", func(T *testing.T) { + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + if len(devices) != 0 { + t.Fatalf("expected no devices, got %+v", devices) + } + }) + t.Run("symlink to device in dir", func(t *testing.T) { + if err := os.Symlink("/dev/zero", filepath.Join(dir, "zerosym")); err != nil { + t.Fatal(err) + } + defer os.Remove(filepath.Join(dir, "zerosym")) + + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + if len(devices) != 0 { + t.Fatalf("expected no devices, got %+v", devices) + } + }) + t.Run("regular file in dir", func(t *testing.T) { + if err := ioutil.WriteFile(filepath.Join(dir, "somefile"), []byte("hello"), 0600); err != nil { + t.Fatal(err) + } + defer os.Remove(filepath.Join(dir, "somefile")) + + devices, err := getDevices(dir, "") + if err != nil { + t.Fatal(err) + } + if len(devices) != 0 { + t.Fatalf("expected no devices, got %+v", devices) + } + }) + }) +} diff -Nru containerd-1.2.6/oci/spec_opts_nonlinux.go containerd-1.5.9/oci/spec_opts_nonlinux.go --- containerd-1.2.6/oci/spec_opts_nonlinux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_nonlinux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + + "github.com/containerd/containerd/containers" +) + +// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process. +// The capability set may differ from WithAllKnownCapabilities when running in a container. +//nolint: deadcode, unused +var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { + return WithCapabilities(nil)(ctx, client, c, s) +} + +// WithAllKnownCapabilities sets all the the known linux capabilities for the container process +//nolint: deadcode, unused +var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error { + return WithCapabilities(nil)(ctx, client, c, s) +} diff -Nru containerd-1.2.6/oci/spec_opts_test.go containerd-1.5.9/oci/spec_opts_test.go --- containerd-1.2.6/oci/spec_opts_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,18 +19,208 @@ import ( "context" "encoding/json" + "errors" + "fmt" + "io" "io/ioutil" "log" "os" + "path/filepath" "reflect" "runtime" + "strings" "testing" + "github.com/containerd/containerd/content" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containerd/containerd/containers" "github.com/containerd/containerd/namespaces" - specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-spec/specs-go" ) +type blob []byte + +func (b blob) ReadAt(p []byte, off int64) (int, error) { + if off >= int64(len(b)) { + return 0, io.EOF + } + return copy(p, b[off:]), nil +} + +func (b blob) Close() error { + return nil +} + +func (b blob) Size() int64 { + return int64(len(b)) +} + +type fakeImage struct { + config ocispec.Descriptor + blobs map[string]blob +} + +func newFakeImage(config ocispec.Image) (Image, error) { + configBlob, err := json.Marshal(config) + if err != nil { + return nil, err + } + configDescriptor := ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageConfig, + Digest: digest.NewDigestFromBytes(digest.SHA256, configBlob), + } + + return fakeImage{ + config: configDescriptor, + blobs: map[string]blob{ + configDescriptor.Digest.String(): configBlob, + }, + }, nil +} + +func (i fakeImage) Config(ctx context.Context) (ocispec.Descriptor, error) { + return i.config, nil +} + +func (i fakeImage) ContentStore() content.Store { + return i +} + +func (i fakeImage) ReaderAt(ctx context.Context, dec ocispec.Descriptor) (content.ReaderAt, error) { + blob, found := i.blobs[dec.Digest.String()] + if !found { + return nil, errors.New("not found") + } + return blob, nil +} + +func (i fakeImage) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { + return content.Info{}, errors.New("not implemented") +} + +func (i fakeImage) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) { + return content.Info{}, errors.New("not implemented") +} + +func (i fakeImage) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error { + return errors.New("not implemented") +} + +func (i fakeImage) Delete(ctx context.Context, dgst digest.Digest) error { + return errors.New("not implemented") +} + +func (i fakeImage) Status(ctx context.Context, ref string) (content.Status, error) { + return content.Status{}, errors.New("not implemented") +} + +func (i fakeImage) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) { + return nil, errors.New("not implemented") +} + +func (i fakeImage) Abort(ctx context.Context, ref string) error { + return errors.New("not implemented") +} + +func (i fakeImage) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) { + return nil, errors.New("not implemented") +} + +func TestReplaceOrAppendEnvValues(t *testing.T) { + t.Parallel() + + defaults := []string{ + "o=ups", "p=$e", "x=foo", "y=boo", "z", "t=", + } + overrides := []string{ + "x=bar", "y", "a=42", "o=", "e", "s=", + } + expected := []string{ + "o=", "p=$e", "x=bar", "z", "t=", "a=42", "s=", + } + + defaultsOrig := make([]string, len(defaults)) + copy(defaultsOrig, defaults) + overridesOrig := make([]string, len(overrides)) + copy(overridesOrig, overrides) + + results := replaceOrAppendEnvValues(defaults, overrides) + + if err := assertEqualsStringArrays(defaults, defaultsOrig); err != nil { + t.Fatal(err) + } + if err := assertEqualsStringArrays(overrides, overridesOrig); err != nil { + t.Fatal(err) + } + + if err := assertEqualsStringArrays(results, expected); err != nil { + t.Fatal(err) + } +} + +func TestWithDefaultSpecForPlatform(t *testing.T) { + t.Parallel() + var ( + s Spec + c = containers.Container{ID: "TestWithDefaultSpecForPlatform"} + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + + platforms := []string{"linux/amd64", "windows/amd64"} + for _, p := range platforms { + if err := ApplyOpts(ctx, nil, &c, &s, WithDefaultSpecForPlatform(p)); err != nil { + t.Fatal(err) + } + } + +} + +func Contains(a []string, x string) bool { + for _, n := range a { + if x == n { + return true + } + } + return false +} + +func TestWithDefaultPathEnv(t *testing.T) { + t.Parallel() + s := Spec{} + s.Process = &specs.Process{ + Env: []string{}, + } + var ( + defaultUnixEnv = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + WithDefaultPathEnv(ctx, nil, nil, &s) + if !Contains(s.Process.Env, defaultUnixEnv) { + t.Fatal("default Unix Env not found") + } +} + +func TestWithProcessCwd(t *testing.T) { + t.Parallel() + s := Spec{} + opts := []SpecOpts{ + WithProcessCwd("testCwd"), + } + var expectedCwd = "testCwd" + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + if s.Process.Cwd != expectedCwd { + t.Fatal("Process has a wrong current working directory") + } + +} + func TestWithEnv(t *testing.T) { t.Parallel() @@ -174,3 +364,297 @@ t.Fatalf("spec from option differs from default: \n%#v != \n%#v", &s, expected) } } + +func TestWithMemoryLimit(t *testing.T) { + var ( + ctx = namespaces.WithNamespace(context.Background(), "testing") + c = containers.Container{ID: t.Name()} + m = uint64(768 * 1024 * 1024) + o = WithMemoryLimit(m) + ) + // Test with all three supported scenarios + platforms := []string{"", "linux/amd64", "windows/amd64"} + for _, p := range platforms { + var spec *Spec + var err error + if p == "" { + t.Log("Testing GenerateSpec default platform") + spec, err = GenerateSpec(ctx, nil, &c, o) + + // Convert the platform to the default based on GOOS like + // GenerateSpec does. + switch runtime.GOOS { + case "linux": + p = "linux/amd64" + case "windows": + p = "windows/amd64" + } + } else { + t.Logf("Testing GenerateSpecWithPlatform with platform: '%s'", p) + spec, err = GenerateSpecWithPlatform(ctx, nil, p, &c, o) + } + if err != nil { + t.Fatalf("failed to generate spec with: %v", err) + } + switch p { + case "linux/amd64": + if *spec.Linux.Resources.Memory.Limit != int64(m) { + t.Fatalf("spec.Linux.Resources.Memory.Limit expected: %v, got: %v", m, *spec.Linux.Resources.Memory.Limit) + } + // If we are linux/amd64 on Windows GOOS it is LCOW + if runtime.GOOS == "windows" { + // Verify that we also set the Windows section. + if *spec.Windows.Resources.Memory.Limit != m { + t.Fatalf("for LCOW spec.Windows.Resources.Memory.Limit is also expected: %v, got: %v", m, *spec.Windows.Resources.Memory.Limit) + } + } else { + if spec.Windows != nil { + t.Fatalf("spec.Windows section should not be set for linux/amd64 spec on non-windows platform") + } + } + case "windows/amd64": + if *spec.Windows.Resources.Memory.Limit != m { + t.Fatalf("spec.Windows.Resources.Memory.Limit expected: %v, got: %v", m, *spec.Windows.Resources.Memory.Limit) + } + if spec.Linux != nil { + t.Fatalf("spec.Linux section should not be set for windows/amd64 spec ever") + } + } + } +} + +func isEqualStringArrays(values, expected []string) bool { + if len(values) != len(expected) { + return false + } + + for i, x := range expected { + if values[i] != x { + return false + } + } + return true +} + +func assertEqualsStringArrays(values, expected []string) error { + if !isEqualStringArrays(values, expected) { + return fmt.Errorf("expected %s, but found %s", expected, values) + } + return nil +} + +func TestWithTTYSize(t *testing.T) { + t.Parallel() + s := Spec{} + opts := []SpecOpts{ + WithTTYSize(10, 20), + } + var ( + expectedWidth = uint(10) + expectedHeight = uint(20) + ) + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + if s.Process.ConsoleSize.Height != expectedWidth && s.Process.ConsoleSize.Height != expectedHeight { + t.Fatal("Process Console has invalid size") + } + +} + +func TestWithUserNamespace(t *testing.T) { + t.Parallel() + s := Spec{} + + opts := []SpecOpts{ + WithUserNamespace([]specs.LinuxIDMapping{ + { + ContainerID: 1, + HostID: 2, + Size: 10000, + }, + }, []specs.LinuxIDMapping{ + { + ContainerID: 2, + HostID: 3, + Size: 20000, + }, + }), + } + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + + expectedUIDMapping := specs.LinuxIDMapping{ + ContainerID: 1, + HostID: 2, + Size: 10000, + } + expectedGIDMapping := specs.LinuxIDMapping{ + ContainerID: 2, + HostID: 3, + Size: 20000, + } + + if !(len(s.Linux.UIDMappings) == 1 && s.Linux.UIDMappings[0] == expectedUIDMapping) || !(len(s.Linux.GIDMappings) == 1 && s.Linux.GIDMappings[0] == expectedGIDMapping) { + t.Fatal("WithUserNamespace Cannot set the uid/gid mappings for the task") + } + +} +func TestWithImageConfigArgs(t *testing.T) { + t.Parallel() + + img, err := newFakeImage(ocispec.Image{ + Config: ocispec.ImageConfig{ + Env: []string{"z=bar", "y=baz"}, + Entrypoint: []string{"create", "--namespace=test"}, + Cmd: []string{"", "--debug"}, + }, + }) + if err != nil { + t.Fatal(err) + } + + s := Spec{ + Version: specs.Version, + Root: &specs.Root{}, + Windows: &specs.Windows{}, + } + + opts := []SpecOpts{ + WithEnv([]string{"x=foo", "y=boo"}), + WithProcessArgs("run", "--foo", "xyz", "--bar"), + WithImageConfigArgs(img, []string{"--boo", "bar"}), + } + + expectedEnv := []string{"z=bar", "y=boo", "x=foo"} + expectedArgs := []string{"create", "--namespace=test", "--boo", "bar"} + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + + if err := assertEqualsStringArrays(s.Process.Env, expectedEnv); err != nil { + t.Fatal(err) + } + if err := assertEqualsStringArrays(s.Process.Args, expectedArgs); err != nil { + t.Fatal(err) + } +} + +func TestDevShmSize(t *testing.T) { + t.Parallel() + var ( + s Spec + c = containers.Container{ID: t.Name()} + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + + err := populateDefaultUnixSpec(ctx, &s, c.ID) + if err != nil { + t.Fatal(err) + } + + expected := "1024k" + if err := WithDevShmSize(1024)(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + m := getShmMount(&s) + if m == nil { + t.Fatal("no shm mount found") + } + o := getShmSize(m.Options) + if o == "" { + t.Fatal("shm size not specified") + } + parts := strings.Split(o, "=") + if len(parts) != 2 { + t.Fatal("invalid size format") + } + size := parts[1] + if size != expected { + t.Fatalf("size %s not equal %s", size, expected) + } +} + +func getShmMount(s *Spec) *specs.Mount { + for _, m := range s.Mounts { + if m.Source == "shm" && m.Type == "tmpfs" { + return &m + } + } + return nil +} + +func getShmSize(opts []string) string { + for _, o := range opts { + if strings.HasPrefix(o, "size=") { + return o + } + } + return "" +} + +func TestWithoutMounts(t *testing.T) { + t.Parallel() + var s Spec + + x := func(s string) string { + if runtime.GOOS == "windows" { + return filepath.Join("C:\\", filepath.Clean(s)) + } + return s + } + opts := []SpecOpts{ + WithMounts([]specs.Mount{ + { + Destination: x("/dst1"), + Source: x("/src1"), + }, + { + Destination: x("/dst2"), + Source: x("/src2"), + }, + { + Destination: x("/dst3"), + Source: x("/src3"), + }, + }), + WithoutMounts(x("/dst2"), x("/dst3")), + WithMounts([]specs.Mount{ + { + Destination: x("/dst4"), + Source: x("/src4"), + }, + }), + } + + expected := []specs.Mount{ + { + Destination: x("/dst1"), + Source: x("/src1"), + }, + { + Destination: x("/dst4"), + Source: x("/src4"), + }, + } + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + + if !reflect.DeepEqual(expected, s.Mounts) { + t.Fatalf("expected %+v, got %+v", expected, s.Mounts) + } +} diff -Nru containerd-1.2.6/oci/spec_opts_unix.go containerd-1.5.9/oci/spec_opts_unix.go --- containerd-1.2.6/oci/spec_opts_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,58 @@ +// +build !linux,!windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + + "github.com/containerd/containerd/containers" +) + +// WithHostDevices adds all the hosts device nodes to the container's spec +func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + setLinux(s) + + devs, err := HostDevices() + if err != nil { + return err + } + s.Linux.Devices = append(s.Linux.Devices, devs...) + return nil +} + +// WithDevices recursively adds devices from the passed in path and associated cgroup rules for that device. +// If devicePath is a dir it traverses the dir to add all devices in that dir. +// If devicePath is not a dir, it attempts to add the single device. +func WithDevices(devicePath, containerPath, permissions string) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + devs, err := getDevices(devicePath, containerPath) + if err != nil { + return err + } + s.Linux.Devices = append(s.Linux.Devices, devs...) + return nil + } +} + +// WithCPUCFS sets the container's Completely fair scheduling (CFS) quota and period +func WithCPUCFS(quota int64, period uint64) SpecOpts { + return func(ctx context.Context, _ Client, c *containers.Container, s *Spec) error { + return nil + } +} diff -Nru containerd-1.2.6/oci/spec_opts_unix_test.go containerd-1.5.9/oci/spec_opts_unix_test.go --- containerd-1.2.6/oci/spec_opts_unix_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,72 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + "testing" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/namespaces" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +func TestWithImageConfigNoEnv(t *testing.T) { + t.Parallel() + var ( + s Spec + c = containers.Container{ID: t.Name()} + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + + err := populateDefaultUnixSpec(ctx, &s, c.ID) + if err != nil { + t.Fatal(err) + } + // test hack: we don't want to test the WithAdditionalGIDs portion of the image config code + s.Windows = &specs.Windows{} + + img, err := newFakeImage(ocispec.Image{ + Config: ocispec.ImageConfig{ + Entrypoint: []string{"create", "--namespace=test"}, + Cmd: []string{"", "--debug"}, + }, + }) + if err != nil { + t.Fatal(err) + } + + opts := []SpecOpts{ + WithImageConfigArgs(img, []string{"--boo", "bar"}), + } + + // verify that if an image has no environment that we get a default Unix path + expectedEnv := []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"} + + for _, opt := range opts { + if err := opt(nil, nil, nil, &s); err != nil { + t.Fatal(err) + } + } + + if err := assertEqualsStringArrays(s.Process.Env, expectedEnv); err != nil { + t.Fatal(err) + } +} diff -Nru containerd-1.2.6/oci/spec_opts_windows.go containerd-1.5.9/oci/spec_opts_windows.go --- containerd-1.2.6/oci/spec_opts_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,79 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + + "github.com/containerd/containerd/containers" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +// WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the +// `count` specified. +func WithWindowsCPUCount(count uint64) SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + if s.Windows.Resources == nil { + s.Windows.Resources = &specs.WindowsResources{} + } + if s.Windows.Resources.CPU == nil { + s.Windows.Resources.CPU = &specs.WindowsCPUResources{} + } + s.Windows.Resources.CPU.Count = &count + return nil + } +} + +// WithWindowsIgnoreFlushesDuringBoot sets `Windows.IgnoreFlushesDuringBoot`. +func WithWindowsIgnoreFlushesDuringBoot() SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + if s.Windows == nil { + s.Windows = &specs.Windows{} + } + s.Windows.IgnoreFlushesDuringBoot = true + return nil + } +} + +// WithWindowNetworksAllowUnqualifiedDNSQuery sets `Windows.Network.AllowUnqualifiedDNSQuery`. +func WithWindowNetworksAllowUnqualifiedDNSQuery() SpecOpts { + return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + if s.Windows == nil { + s.Windows = &specs.Windows{} + } + if s.Windows.Network == nil { + s.Windows.Network = &specs.WindowsNetwork{} + } + + s.Windows.Network.AllowUnqualifiedDNSQuery = true + return nil + } +} + +// WithHostDevices adds all the hosts device nodes to the container's spec +// +// Not supported on windows +func WithHostDevices(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { + return nil +} + +func deviceFromPath(path string) (*specs.LinuxDevice, error) { + return nil, errors.New("device from path not supported on Windows") +} diff -Nru containerd-1.2.6/oci/spec_opts_windows_test.go containerd-1.5.9/oci/spec_opts_windows_test.go --- containerd-1.2.6/oci/spec_opts_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/spec_opts_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,112 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "context" + "testing" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/namespaces" +) + +func TestWithCPUCount(t *testing.T) { + var ( + ctx = namespaces.WithNamespace(context.Background(), "testing") + c = containers.Container{ID: t.Name()} + cpu = uint64(8) + o = WithWindowsCPUCount(cpu) + ) + // Test with all three supported scenarios + platforms := []string{"", "linux/amd64", "windows/amd64"} + for _, p := range platforms { + var spec *Spec + var err error + if p == "" { + t.Log("Testing GenerateSpec default platform") + spec, err = GenerateSpec(ctx, nil, &c, o) + } else { + t.Logf("Testing GenerateSpecWithPlatform with platform: '%s'", p) + spec, err = GenerateSpecWithPlatform(ctx, nil, p, &c, o) + } + if err != nil { + t.Fatalf("failed to generate spec with: %v", err) + } + if *spec.Windows.Resources.CPU.Count != cpu { + t.Fatalf("spec.Windows.Resources.CPU.Count expected: %v, got: %v", cpu, *spec.Windows.Resources.CPU.Count) + } + if spec.Linux != nil && spec.Linux.Resources != nil && spec.Linux.Resources.CPU != nil { + t.Fatalf("spec.Linux.Resources.CPU section should not be set on GOOS=windows") + } + } +} + +func TestWithWindowsIgnoreFlushesDuringBoot(t *testing.T) { + var ( + ctx = namespaces.WithNamespace(context.Background(), "testing") + c = containers.Container{ID: t.Name()} + o = WithWindowsIgnoreFlushesDuringBoot() + ) + // Test with all supported scenarios + platforms := []string{"", "windows/amd64"} + for _, p := range platforms { + var spec *Spec + var err error + if p == "" { + t.Log("Testing GenerateSpec default platform") + spec, err = GenerateSpec(ctx, nil, &c, o) + } else { + t.Logf("Testing GenerateSpecWithPlatform with platform: '%s'", p) + spec, err = GenerateSpecWithPlatform(ctx, nil, p, &c, o) + } + if err != nil { + t.Fatalf("failed to generate spec with: %v", err) + } + if spec.Windows.IgnoreFlushesDuringBoot != true { + t.Fatalf("spec.Windows.IgnoreFlushesDuringBoot expected: true") + } + } +} + +func TestWithWindowNetworksAllowUnqualifiedDNSQuery(t *testing.T) { + var ( + ctx = namespaces.WithNamespace(context.Background(), "testing") + c = containers.Container{ID: t.Name()} + o = WithWindowNetworksAllowUnqualifiedDNSQuery() + ) + // Test with all supported scenarios + platforms := []string{"", "windows/amd64"} + for _, p := range platforms { + var spec *Spec + var err error + if p == "" { + t.Log("Testing GenerateSpec default platform") + spec, err = GenerateSpec(ctx, nil, &c, o) + } else { + t.Logf("Testing GenerateSpecWithPlatform with platform: '%s'", p) + spec, err = GenerateSpecWithPlatform(ctx, nil, p, &c, o) + } + if err != nil { + t.Fatalf("failed to generate spec with: %v", err) + } + if spec.Windows.Network.AllowUnqualifiedDNSQuery != true { + t.Fatalf("spec.Windows.Network.AllowUnqualifiedDNSQuery expected: true") + } + } +} diff -Nru containerd-1.2.6/oci/spec_test.go containerd-1.5.9/oci/spec_test.go --- containerd-1.2.6/oci/spec_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/oci/spec_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,6 +23,7 @@ "github.com/containerd/containerd/containers" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/testutil" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -63,7 +64,7 @@ } } else { if s.Windows == nil { - t.Fatal("Windows section of spec not filled on on Windows platform") + t.Fatal("Windows section of spec not filled in on Windows platform") } } @@ -223,8 +224,38 @@ } } +func TestPopulateDefaultWindowsSpec(t *testing.T) { + var ( + c = containers.Container{ID: "TestWithDefaultSpec"} + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + var expected Spec + + populateDefaultWindowsSpec(ctx, &expected, c.ID) + if expected.Windows == nil { + t.Error("Cannot populate windows Spec") + } +} + +func TestPopulateDefaultUnixSpec(t *testing.T) { + var ( + c = containers.Container{ID: "TestWithDefaultSpec"} + ctx = namespaces.WithNamespace(context.Background(), "test") + ) + var expected Spec + + populateDefaultUnixSpec(ctx, &expected, c.ID) + if expected.Linux == nil { + t.Error("Cannot populate Unix Spec") + } +} + func TestWithPrivileged(t *testing.T) { t.Parallel() + if runtime.GOOS == "linux" { + // because WithPrivileged depends on CapEff in /proc/self/status + testutil.RequiresRoot(t) + } ctx := namespaces.WithNamespace(context.Background(), "testing") @@ -246,6 +277,10 @@ t.Fatal(err) } + if runtime.GOOS != "linux" { + return + } + if len(s.Process.Capabilities.Bounding) == 0 { t.Error("Expected capabilities to be set with privileged") } diff -Nru containerd-1.2.6/oci/utils_unix.go containerd-1.5.9/oci/utils_unix.go --- containerd-1.2.6/oci/utils_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/oci/utils_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,137 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oci + +import ( + "io/ioutil" + "os" + "path/filepath" + + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +var errNotADevice = errors.New("not a device node") + +// HostDevices returns all devices that can be found under /dev directory. +func HostDevices() ([]specs.LinuxDevice, error) { + return getDevices("/dev", "") +} + +func getDevices(path, containerPath string) ([]specs.LinuxDevice, error) { + stat, err := os.Stat(path) + if err != nil { + return nil, errors.Wrap(err, "error stating device path") + } + + if !stat.IsDir() { + dev, err := deviceFromPath(path) + if err != nil { + return nil, err + } + if containerPath != "" { + dev.Path = containerPath + } + return []specs.LinuxDevice{*dev}, nil + } + + files, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + var out []specs.LinuxDevice + for _, f := range files { + switch { + case f.IsDir(): + switch f.Name() { + // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825 + // ".udev" added to address https://github.com/opencontainers/runc/issues/2093 + case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev": + continue + default: + var cp string + if containerPath != "" { + cp = filepath.Join(containerPath, filepath.Base(f.Name())) + } + sub, err := getDevices(filepath.Join(path, f.Name()), cp) + if err != nil { + return nil, err + } + + out = append(out, sub...) + continue + } + case f.Name() == "console": + continue + } + device, err := deviceFromPath(filepath.Join(path, f.Name())) + if err != nil { + if err == errNotADevice { + continue + } + if os.IsNotExist(err) { + continue + } + return nil, err + } + if containerPath != "" { + device.Path = filepath.Join(containerPath, filepath.Base(f.Name())) + } + out = append(out, *device) + } + return out, nil +} + +func deviceFromPath(path string) (*specs.LinuxDevice, error) { + var stat unix.Stat_t + if err := unix.Lstat(path, &stat); err != nil { + return nil, err + } + + var ( + devNumber = uint64(stat.Rdev) //nolint: unconvert // the type is 32bit on mips. + major = unix.Major(devNumber) + minor = unix.Minor(devNumber) + ) + if major == 0 { + return nil, errNotADevice + } + + var ( + devType string + mode = stat.Mode + ) + switch { + case mode&unix.S_IFBLK == unix.S_IFBLK: + devType = "b" + case mode&unix.S_IFCHR == unix.S_IFCHR: + devType = "c" + } + fm := os.FileMode(mode &^ unix.S_IFMT) + return &specs.LinuxDevice{ + Type: devType, + Path: path, + Major: int64(major), + Minor: int64(minor), + FileMode: &fm, + UID: &stat.Uid, + GID: &stat.Gid, + }, nil +} diff -Nru containerd-1.2.6/pkg/apparmor/apparmor.go containerd-1.5.9/pkg/apparmor/apparmor.go --- containerd-1.2.6/pkg/apparmor/apparmor.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/apparmor/apparmor.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +// HostSupports returns true if apparmor is enabled for the host, // On non-Linux returns false +// On Linux returns true if apparmor_parser is enabled, and if we +// are not running docker-in-docker. +// +// It is a modified version of libcontainer/apparmor.IsEnabled(), which does not +// check for apparmor_parser to be present, or if we're running docker-in-docker. +func HostSupports() bool { + return hostSupports() +} diff -Nru containerd-1.2.6/pkg/apparmor/apparmor_linux.go containerd-1.5.9/pkg/apparmor/apparmor_linux.go --- containerd-1.2.6/pkg/apparmor/apparmor_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/apparmor/apparmor_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +import ( + "io/ioutil" + "os" + "sync" +) + +var ( + appArmorSupported bool + checkAppArmor sync.Once +) + +// hostSupports returns true if apparmor is enabled for the host, if +// apparmor_parser is enabled, and if we are not running docker-in-docker. +// +// It is a modified version of libcontainer/apparmor.IsEnabled(), which does not +// check for apparmor_parser to be present, or if we're running docker-in-docker. +func hostSupports() bool { + checkAppArmor.Do(func() { + // see https://github.com/docker/docker/commit/de191e86321f7d3136ff42ff75826b8107399497 + if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" { + if _, err = os.Stat("/sbin/apparmor_parser"); err == nil { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + appArmorSupported = err == nil && len(buf) > 1 && buf[0] == 'Y' + } + } + }) + return appArmorSupported +} diff -Nru containerd-1.2.6/pkg/apparmor/apparmor_unsupported.go containerd-1.5.9/pkg/apparmor/apparmor_unsupported.go --- containerd-1.2.6/pkg/apparmor/apparmor_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/apparmor/apparmor_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +func hostSupports() bool { + return false +} diff -Nru containerd-1.2.6/pkg/atomic/atomic_boolean.go containerd-1.5.9/pkg/atomic/atomic_boolean.go --- containerd-1.2.6/pkg/atomic/atomic_boolean.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/atomic/atomic_boolean.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package atomic + +import "sync/atomic" + +// Bool is an atomic Boolean, +// Its methods are all atomic, thus safe to be called by +// multiple goroutines simultaneously. +type Bool interface { + Set() + Unset() + IsSet() bool +} + +// NewBool creates an Bool with given default value +func NewBool(ok bool) Bool { + ab := new(atomicBool) + if ok { + ab.Set() + } + return ab +} + +type atomicBool int32 + +// Set sets the Boolean to true +func (ab *atomicBool) Set() { + atomic.StoreInt32((*int32)(ab), 1) +} + +// Unset sets the Boolean to false +func (ab *atomicBool) Unset() { + atomic.StoreInt32((*int32)(ab), 0) +} + +// IsSet returns whether the Boolean is true +func (ab *atomicBool) IsSet() bool { + return atomic.LoadInt32((*int32)(ab)) == 1 +} diff -Nru containerd-1.2.6/pkg/atomic/atomic_boolean_test.go containerd-1.5.9/pkg/atomic/atomic_boolean_test.go --- containerd-1.2.6/pkg/atomic/atomic_boolean_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/atomic/atomic_boolean_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,32 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package atomic + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBoolean(t *testing.T) { + ab := NewBool(true) + assert.True(t, ab.IsSet()) + ab.Unset() + assert.False(t, ab.IsSet()) + ab.Set() + assert.True(t, ab.IsSet()) +} diff -Nru containerd-1.2.6/pkg/cap/cap_linux.go containerd-1.5.9/pkg/cap/cap_linux.go --- containerd-1.2.6/pkg/cap/cap_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cap/cap_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,192 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package cap provides Linux capability utility +package cap + +import ( + "bufio" + "io" + "os" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +// FromNumber returns a cap string like "CAP_SYS_ADMIN" +// that corresponds to the given number like 21. +// +// FromNumber returns an empty string for unknown cap number. +func FromNumber(num int) string { + if num < 0 || num > len(capsLatest)-1 { + return "" + } + return capsLatest[num] +} + +// FromBitmap parses an uint64 bitmap into string slice like +// []{"CAP_SYS_ADMIN", ...}. +// +// Unknown cap numbers are returned as []int. +func FromBitmap(v uint64) ([]string, []int) { + var ( + res []string + unknown []int + ) + for i := 0; i <= 63; i++ { + if b := (v >> i) & 0x1; b == 0x1 { + if s := FromNumber(i); s != "" { + res = append(res, s) + } else { + unknown = append(unknown, i) + } + } + } + return res, unknown +} + +// Type is the type of capability +type Type int + +const ( + // Effective is CapEff + Effective Type = 1 << iota + // Permitted is CapPrm + Permitted + // Inheritable is CapInh + Inheritable + // Bounding is CapBnd + Bounding + // Ambient is CapAmb + Ambient +) + +// ParseProcPIDStatus returns uint64 bitmap value from /proc//status file +func ParseProcPIDStatus(r io.Reader) (map[Type]uint64, error) { + res := make(map[Type]uint64) + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := scanner.Text() + pair := strings.SplitN(line, ":", 2) + if len(pair) != 2 { + continue + } + k := strings.TrimSpace(pair[0]) + v := strings.TrimSpace(pair[1]) + switch k { + case "CapInh", "CapPrm", "CapEff", "CapBnd", "CapAmb": + ui64, err := strconv.ParseUint(v, 16, 64) + if err != nil { + return nil, errors.Errorf("failed to parse line %q", line) + } + switch k { + case "CapInh": + res[Inheritable] = ui64 + case "CapPrm": + res[Permitted] = ui64 + case "CapEff": + res[Effective] = ui64 + case "CapBnd": + res[Bounding] = ui64 + case "CapAmb": + res[Ambient] = ui64 + } + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + return res, nil +} + +// Current returns the list of the effective and the known caps of +// the current process. +// +// The result is like []string{"CAP_SYS_ADMIN", ...}. +// +// The result does not contain caps that are not recognized by +// the "github.com/syndtr/gocapability" library. +func Current() ([]string, error) { + f, err := os.Open("/proc/self/status") + if err != nil { + return nil, err + } + defer f.Close() + caps, err := ParseProcPIDStatus(f) + if err != nil { + return nil, err + } + capEff := caps[Effective] + names, _ := FromBitmap(capEff) + return names, nil +} + +var ( + // caps35 is the caps of kernel 3.5 (37 entries) + caps35 = []string{ + "CAP_CHOWN", // 2.2 + "CAP_DAC_OVERRIDE", // 2.2 + "CAP_DAC_READ_SEARCH", // 2.2 + "CAP_FOWNER", // 2.2 + "CAP_FSETID", // 2.2 + "CAP_KILL", // 2.2 + "CAP_SETGID", // 2.2 + "CAP_SETUID", // 2.2 + "CAP_SETPCAP", // 2.2 + "CAP_LINUX_IMMUTABLE", // 2.2 + "CAP_NET_BIND_SERVICE", // 2.2 + "CAP_NET_BROADCAST", // 2.2 + "CAP_NET_ADMIN", // 2.2 + "CAP_NET_RAW", // 2.2 + "CAP_IPC_LOCK", // 2.2 + "CAP_IPC_OWNER", // 2.2 + "CAP_SYS_MODULE", // 2.2 + "CAP_SYS_RAWIO", // 2.2 + "CAP_SYS_CHROOT", // 2.2 + "CAP_SYS_PTRACE", // 2.2 + "CAP_SYS_PACCT", // 2.2 + "CAP_SYS_ADMIN", // 2.2 + "CAP_SYS_BOOT", // 2.2 + "CAP_SYS_NICE", // 2.2 + "CAP_SYS_RESOURCE", // 2.2 + "CAP_SYS_TIME", // 2.2 + "CAP_SYS_TTY_CONFIG", // 2.2 + "CAP_MKNOD", // 2.4 + "CAP_LEASE", // 2.4 + "CAP_AUDIT_WRITE", // 2.6.11 + "CAP_AUDIT_CONTROL", // 2.6.11 + "CAP_SETFCAP", // 2.6.24 + "CAP_MAC_OVERRIDE", // 2.6.25 + "CAP_MAC_ADMIN", // 2.6.25 + "CAP_SYSLOG", // 2.6.37 + "CAP_WAKE_ALARM", // 3.0 + "CAP_BLOCK_SUSPEND", // 3.5 + } + // caps316 is the caps of kernel 3.16 (38 entries) + caps316 = append(caps35, "CAP_AUDIT_READ") + // caps58 is the caps of kernel 5.8 (40 entries) + caps58 = append(caps316, []string{"CAP_PERFMON", "CAP_BPF"}...) + // caps59 is the caps of kernel 5.9 (41 entries) + caps59 = append(caps58, "CAP_CHECKPOINT_RESTORE") + capsLatest = caps59 +) + +// Known returns the known cap strings of the latest kernel. +// The current latest kernel is 5.9. +func Known() []string { + return capsLatest +} diff -Nru containerd-1.2.6/pkg/cap/cap_linux_test.go containerd-1.5.9/pkg/cap/cap_linux_test.go --- containerd-1.2.6/pkg/cap/cap_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cap/cap_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,169 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cap + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCapsList(t *testing.T) { + assert.Len(t, caps316, 38) + assert.Len(t, caps58, 40) + assert.Len(t, caps59, 41) +} + +func TestFromNumber(t *testing.T) { + assert.Equal(t, "CAP_CHOWN", FromNumber(0)) + assert.Equal(t, "CAP_SYS_ADMIN", FromNumber(21)) + assert.Equal(t, "CAP_CHECKPOINT_RESTORE", FromNumber(40)) + assert.Equal(t, "", FromNumber(-1)) + assert.Equal(t, "", FromNumber(63)) + assert.Equal(t, "", FromNumber(255)) +} + +func TestFromBitmap(t *testing.T) { + type testCase struct { + comment string + v uint64 + knownNames []string + unknown []int + } + testCases := []testCase{ + { + comment: "No cap", + v: 0x0000000000000000, + }, + { + // 3.10 (same caps as 3.5) is the oldest kernel version we want to support + comment: "All caps on kernel 3.5 (last = CAP_BLOCK_SUSPEND)", + v: 0x0000001fffffffff, + knownNames: caps35, + }, + { + comment: "All caps on kernel 3.16 (last = CAP_AUDIT_READ)", + v: 0x0000003fffffffff, + knownNames: caps316, + }, + { + comment: "All caps on kernel 5.8 (last = CAP_BPF)", + v: 0x000000ffffffffff, + knownNames: caps58, + }, + { + comment: "All caps on kernel 5.9 (last = CAP_CHECKPOINT_RESTORE)", + v: 0x000001ffffffffff, + knownNames: caps59, + }, + { + comment: "Unknown caps", + v: 0xf00001ffffffffff, + knownNames: caps59, + unknown: []int{60, 61, 62, 63}, + }, + } + + for _, tc := range testCases { + knownNames, unknown := FromBitmap(tc.v) + t.Logf("[%s] v=0x%x, got=%+v (%d entries), unknown=%v", + tc.comment, tc.v, knownNames, len(knownNames), unknown) + assert.Equal(t, tc.knownNames, knownNames) + assert.Equal(t, tc.unknown, unknown) + } +} + +func TestParseProcPIDStatus(t *testing.T) { + procPIDStatus := `Name: cat +Umask: 0022 +State: R (running) +Tgid: 170065 +Ngid: 0 +Pid: 170065 +PPid: 170064 +TracerPid: 0 +Uid: 0 0 0 0 +Gid: 0 0 0 0 +FDSize: 64 +Groups: 0 +NStgid: 170065 +NSpid: 170065 +NSpgid: 170064 +NSsid: 3784 +VmPeak: 8216 kB +VmSize: 8216 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 676 kB +VmRSS: 676 kB +RssAnon: 72 kB +RssFile: 604 kB +RssShmem: 0 kB +VmData: 324 kB +VmStk: 132 kB +VmExe: 20 kB +VmLib: 1612 kB +VmPTE: 56 kB +VmSwap: 0 kB +HugetlbPages: 0 kB +CoreDumping: 0 +THP_enabled: 1 +Threads: 1 +SigQ: 0/63692 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 000000ffffffffff +CapEff: 000000ffffffffff +CapBnd: 000000ffffffffff +CapAmb: 0000000000000000 +NoNewPrivs: 0 +Seccomp: 0 +Speculation_Store_Bypass: thread vulnerable +Cpus_allowed: 00000000,00000000,00000000,0000000f +Cpus_allowed_list: 0-3 +Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001 +Mems_allowed_list: 0 +voluntary_ctxt_switches: 0 +nonvoluntary_ctxt_switches: 0 +` + res, err := ParseProcPIDStatus(strings.NewReader(procPIDStatus)) + assert.NoError(t, err) + expected := map[Type]uint64{ + Inheritable: 0, + Permitted: 0xffffffffff, + Effective: 0xffffffffff, + Bounding: 0xffffffffff, + Ambient: 0, + } + assert.EqualValues(t, expected, res) +} + +func TestCurrent(t *testing.T) { + caps, err := Current() + assert.NoError(t, err) + t.Logf("verify the result manually: %+v", caps) +} + +func TestKnown(t *testing.T) { + caps := Known() + assert.EqualValues(t, caps59, caps) +} diff -Nru containerd-1.2.6/pkg/cri/annotations/annotations.go containerd-1.5.9/pkg/cri/annotations/annotations.go --- containerd-1.2.6/pkg/cri/annotations/annotations.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/annotations/annotations.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package annotations + +// ContainerType values +// Following OCI annotations are used by katacontainers now. +// We'll switch to standard secure pod API after it is defined in CRI. +const ( + // ContainerTypeSandbox represents a pod sandbox container + ContainerTypeSandbox = "sandbox" + + // ContainerTypeContainer represents a container running within a pod + ContainerTypeContainer = "container" + + // ContainerType is the container type (sandbox or container) annotation + ContainerType = "io.kubernetes.cri.container-type" + + // SandboxID is the sandbox ID annotation + SandboxID = "io.kubernetes.cri.sandbox-id" + + // SandboxLogDir is the pod log directory annotation. + // If the sandbox needs to generate any log, it will put it into this directory. + // Kubelet will be responsible for: + // 1) Monitoring the disk usage of the log, and including it as part of the pod + // ephemeral storage usage. + // 2) Cleaning up the logs when the pod is deleted. + // NOTE: Kubelet is not responsible for rotating the logs. + SandboxLogDir = "io.kubernetes.cri.sandbox-log-directory" + + // UntrustedWorkload is the sandbox annotation for untrusted workload. Untrusted + // workload can only run on dedicated runtime for untrusted workload. + UntrustedWorkload = "io.kubernetes.cri.untrusted-workload" + + // SandboxNamespace is the name of the namespace of the sandbox (pod) + SandboxNamespace = "io.kubernetes.cri.sandbox-namespace" + + // SandboxName is the name of the sandbox (pod) + SandboxName = "io.kubernetes.cri.sandbox-name" + + // ContainerName is the name of the container in the pod + ContainerName = "io.kubernetes.cri.container-name" + + // ImageName is the name of the image used to create the container + ImageName = "io.kubernetes.cri.image-name" + + // PodAnnotations are the annotations of the pod + PodAnnotations = "io.kubernetes.cri.pod-annotations" +) diff -Nru containerd-1.2.6/pkg/cri/config/config.go containerd-1.5.9/pkg/cri/config/config.go --- containerd-1.2.6/pkg/cri/config/config.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/config/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,413 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "context" + "net/url" + "time" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/plugin" + "github.com/pkg/errors" +) + +// Runtime struct to contain the type(ID), engine, and root variables for a default runtime +// and a runtime for untrusted worload. +type Runtime struct { + // Type is the runtime type to use in containerd e.g. io.containerd.runtime.v1.linux + Type string `toml:"runtime_type" json:"runtimeType"` + // Engine is the name of the runtime engine used by containerd. + // This only works for runtime type "io.containerd.runtime.v1.linux". + // DEPRECATED: use Options instead. Remove when shim v1 is deprecated. + Engine string `toml:"runtime_engine" json:"runtimeEngine"` + // PodAnnotations is a list of pod annotations passed to both pod sandbox as well as + // container OCI annotations. + PodAnnotations []string `toml:"pod_annotations" json:"PodAnnotations"` + // ContainerAnnotations is a list of container annotations passed through to the OCI config of the containers. + // Container annotations in CRI are usually generated by other Kubernetes node components (i.e., not users). + // Currently, only device plugins populate the annotations. + ContainerAnnotations []string `toml:"container_annotations" json:"ContainerAnnotations"` + // Root is the directory used by containerd for runtime state. + // DEPRECATED: use Options instead. Remove when shim v1 is deprecated. + // This only works for runtime type "io.containerd.runtime.v1.linux". + Root string `toml:"runtime_root" json:"runtimeRoot"` + // Options are config options for the runtime. + // If options is loaded from toml config, it will be map[string]interface{}. + // Options can be converted into toml.Tree using toml.TreeFromMap(). + // Using options type as map[string]interface{} helps in correctly marshaling options from Go to JSON. + Options map[string]interface{} `toml:"options" json:"options"` + // PrivilegedWithoutHostDevices overloads the default behaviour for adding host devices to the + // runtime spec when the container is privileged. Defaults to false. + PrivilegedWithoutHostDevices bool `toml:"privileged_without_host_devices" json:"privileged_without_host_devices"` + // BaseRuntimeSpec is a json file with OCI spec to use as base spec that all container's will be created from. + BaseRuntimeSpec string `toml:"base_runtime_spec" json:"baseRuntimeSpec"` +} + +// ContainerdConfig contains toml config related to containerd +type ContainerdConfig struct { + // Snapshotter is the snapshotter used by containerd. + Snapshotter string `toml:"snapshotter" json:"snapshotter"` + // DefaultRuntimeName is the default runtime name to use from the runtimes table. + DefaultRuntimeName string `toml:"default_runtime_name" json:"defaultRuntimeName"` + // DefaultRuntime is the default runtime to use in containerd. + // This runtime is used when no runtime handler (or the empty string) is provided. + // DEPRECATED: use DefaultRuntimeName instead. Remove in containerd 1.4. + DefaultRuntime Runtime `toml:"default_runtime" json:"defaultRuntime"` + // UntrustedWorkloadRuntime is a runtime to run untrusted workloads on it. + // DEPRECATED: use `untrusted` runtime in Runtimes instead. Remove in containerd 1.4. + UntrustedWorkloadRuntime Runtime `toml:"untrusted_workload_runtime" json:"untrustedWorkloadRuntime"` + // Runtimes is a map from CRI RuntimeHandler strings, which specify types of runtime + // configurations, to the matching configurations. + Runtimes map[string]Runtime `toml:"runtimes" json:"runtimes"` + // NoPivot disables pivot-root (linux only), required when running a container in a RamDisk with runc + // This only works for runtime type "io.containerd.runtime.v1.linux". + NoPivot bool `toml:"no_pivot" json:"noPivot"` + + // DisableSnapshotAnnotations disables to pass additional annotations (image + // related information) to snapshotters. These annotations are required by + // stargz snapshotter (https://github.com/containerd/stargz-snapshotter). + DisableSnapshotAnnotations bool `toml:"disable_snapshot_annotations" json:"disableSnapshotAnnotations"` + + // DiscardUnpackedLayers is a boolean flag to specify whether to allow GC to + // remove layers from the content store after successfully unpacking these + // layers to the snapshotter. + DiscardUnpackedLayers bool `toml:"discard_unpacked_layers" json:"discardUnpackedLayers"` +} + +// CniConfig contains toml config related to cni +type CniConfig struct { + // NetworkPluginBinDir is the directory in which the binaries for the plugin is kept. + NetworkPluginBinDir string `toml:"bin_dir" json:"binDir"` + // NetworkPluginConfDir is the directory in which the admin places a CNI conf. + NetworkPluginConfDir string `toml:"conf_dir" json:"confDir"` + // NetworkPluginMaxConfNum is the max number of plugin config files that will + // be loaded from the cni config directory by go-cni. Set the value to 0 to + // load all config files (no arbitrary limit). The legacy default value is 1. + NetworkPluginMaxConfNum int `toml:"max_conf_num" json:"maxConfNum"` + // NetworkPluginConfTemplate is the file path of golang template used to generate + // cni config. + // When it is set, containerd will get cidr(s) from kubelet to replace {{.PodCIDR}}, + // {{.PodCIDRRanges}} or {{.Routes}} in the template, and write the config into + // NetworkPluginConfDir. + // Ideally the cni config should be placed by system admin or cni daemon like calico, + // weaveworks etc. However, there are still users using kubenet + // (https://kubernetes.io/docs/concepts/cluster-administration/network-plugins/#kubenet) + // today, who don't have a cni daemonset in production. NetworkPluginConfTemplate is + // a temporary backward-compatible solution for them. + // TODO(random-liu): Deprecate this option when kubenet is deprecated. + NetworkPluginConfTemplate string `toml:"conf_template" json:"confTemplate"` +} + +// Mirror contains the config related to the registry mirror +type Mirror struct { + // Endpoints are endpoints for a namespace. CRI plugin will try the endpoints + // one by one until a working one is found. The endpoint must be a valid url + // with host specified. + // The scheme, host and path from the endpoint URL will be used. + Endpoints []string `toml:"endpoint" json:"endpoint"` +} + +// AuthConfig contains the config related to authentication to a specific registry +type AuthConfig struct { + // Username is the username to login the registry. + Username string `toml:"username" json:"username"` + // Password is the password to login the registry. + Password string `toml:"password" json:"password"` + // Auth is a base64 encoded string from the concatenation of the username, + // a colon, and the password. + Auth string `toml:"auth" json:"auth"` + // IdentityToken is used to authenticate the user and get + // an access token for the registry. + IdentityToken string `toml:"identitytoken" json:"identitytoken"` +} + +// TLSConfig contains the CA/Cert/Key used for a registry +type TLSConfig struct { + InsecureSkipVerify bool `toml:"insecure_skip_verify" json:"insecure_skip_verify"` + CAFile string `toml:"ca_file" json:"caFile"` + CertFile string `toml:"cert_file" json:"certFile"` + KeyFile string `toml:"key_file" json:"keyFile"` +} + +// Registry is registry settings configured +type Registry struct { + // ConfigPath is a path to the root directory containing registry-specific + // configurations. + // If ConfigPath is set, the rest of the registry specific options are ignored. + ConfigPath string `toml:"config_path" json:"configPath"` + // Mirrors are namespace to mirror mapping for all namespaces. + // This option will not be used when ConfigPath is provided. + // DEPRECATED: Use ConfigPath instead. Remove in containerd 1.7. + Mirrors map[string]Mirror `toml:"mirrors" json:"mirrors"` + // Configs are configs for each registry. + // The key is the domain name or IP of the registry. + // This option will be fully deprecated for ConfigPath in the future. + Configs map[string]RegistryConfig `toml:"configs" json:"configs"` + // Auths are registry endpoint to auth config mapping. The registry endpoint must + // be a valid url with host specified. + // DEPRECATED: Use ConfigPath instead. Remove in containerd 1.6. + Auths map[string]AuthConfig `toml:"auths" json:"auths"` + // Headers adds additional HTTP headers that get sent to all registries + Headers map[string][]string `toml:"headers" json:"headers"` +} + +// RegistryConfig contains configuration used to communicate with the registry. +type RegistryConfig struct { + // Auth contains information to authenticate to the registry. + Auth *AuthConfig `toml:"auth" json:"auth"` + // TLS is a pair of CA/Cert/Key which then are used when creating the transport + // that communicates with the registry. + // This field will not be used when ConfigPath is provided. + // DEPRECATED: Use ConfigPath instead. Remove in containerd 1.7. + TLS *TLSConfig `toml:"tls" json:"tls"` +} + +// ImageDecryption contains configuration to handling decryption of encrypted container images. +type ImageDecryption struct { + // KeyModel specifies the trust model of where keys should reside. + // + // Details of field usage can be found in: + // https://github.com/containerd/cri/tree/master/docs/config.md + // + // Details of key models can be found in: + // https://github.com/containerd/cri/tree/master/docs/decryption.md + KeyModel string `toml:"key_model" json:"keyModel"` +} + +// PluginConfig contains toml config related to CRI plugin, +// it is a subset of Config. +type PluginConfig struct { + // ContainerdConfig contains config related to containerd + ContainerdConfig `toml:"containerd" json:"containerd"` + // CniConfig contains config related to cni + CniConfig `toml:"cni" json:"cni"` + // Registry contains config related to the registry + Registry Registry `toml:"registry" json:"registry"` + // ImageDecryption contains config related to handling decryption of encrypted container images + ImageDecryption `toml:"image_decryption" json:"imageDecryption"` + // DisableTCPService disables serving CRI on the TCP server. + DisableTCPService bool `toml:"disable_tcp_service" json:"disableTCPService"` + // StreamServerAddress is the ip address streaming server is listening on. + StreamServerAddress string `toml:"stream_server_address" json:"streamServerAddress"` + // StreamServerPort is the port streaming server is listening on. + StreamServerPort string `toml:"stream_server_port" json:"streamServerPort"` + // StreamIdleTimeout is the maximum time a streaming connection + // can be idle before the connection is automatically closed. + // The string is in the golang duration format, see: + // https://golang.org/pkg/time/#ParseDuration + StreamIdleTimeout string `toml:"stream_idle_timeout" json:"streamIdleTimeout"` + // EnableSelinux indicates to enable the selinux support. + EnableSelinux bool `toml:"enable_selinux" json:"enableSelinux"` + // SelinuxCategoryRange allows the upper bound on the category range to be set. + // If not specified or set to 0, defaults to 1024 from the selinux package. + SelinuxCategoryRange int `toml:"selinux_category_range" json:"selinuxCategoryRange"` + // SandboxImage is the image used by sandbox container. + SandboxImage string `toml:"sandbox_image" json:"sandboxImage"` + // StatsCollectPeriod is the period (in seconds) of snapshots stats collection. + StatsCollectPeriod int `toml:"stats_collect_period" json:"statsCollectPeriod"` + // SystemdCgroup enables systemd cgroup support. + // This only works for runtime type "io.containerd.runtime.v1.linux". + // DEPRECATED: config runc runtime handler instead. Remove when shim v1 is deprecated. + SystemdCgroup bool `toml:"systemd_cgroup" json:"systemdCgroup"` + // EnableTLSStreaming indicates to enable the TLS streaming support. + EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"` + // X509KeyPairStreaming is a x509 key pair used for TLS streaming + X509KeyPairStreaming `toml:"x509_key_pair_streaming" json:"x509KeyPairStreaming"` + // MaxContainerLogLineSize is the maximum log line size in bytes for a container. + // Log line longer than the limit will be split into multiple lines. Non-positive + // value means no limit. + 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"` + // MaxConcurrentDownloads restricts the number of concurrent downloads for each image. + MaxConcurrentDownloads int `toml:"max_concurrent_downloads" json:"maxConcurrentDownloads"` + // DisableProcMount disables Kubernetes ProcMount support. This MUST be set to `true` + // when using containerd with Kubernetes <=1.11. + DisableProcMount bool `toml:"disable_proc_mount" json:"disableProcMount"` + // UnsetSeccompProfile is the profile containerd/cri will use If the provided seccomp profile is + // unset (`""`) for a container (default is `unconfined`) + UnsetSeccompProfile string `toml:"unset_seccomp_profile" json:"unsetSeccompProfile"` + // TolerateMissingHugetlbController if set to false will error out on create/update + // container requests with huge page limits if the cgroup controller for hugepages is not present. + // This helps with supporting Kubernetes <=1.18 out of the box. (default is `true`) + TolerateMissingHugetlbController bool `toml:"tolerate_missing_hugetlb_controller" json:"tolerateMissingHugetlbController"` + // DisableHugetlbController indicates to silently disable the hugetlb controller, even when it is + // present in /sys/fs/cgroup/cgroup.controllers. + // This helps with running rootless mode + cgroup v2 + systemd but without hugetlb delegation. + DisableHugetlbController bool `toml:"disable_hugetlb_controller" json:"disableHugetlbController"` + // IgnoreImageDefinedVolumes ignores volumes defined by the image. Useful for better resource + // isolation, security and early detection of issues in the mount configuration when using + // ReadOnlyRootFilesystem since containers won't silently mount a temporary volume. + IgnoreImageDefinedVolumes bool `toml:"ignore_image_defined_volumes" json:"ignoreImageDefinedVolumes"` + // NetNSMountsUnderStateDir places all mounts for network namespaces under StateDir/netns instead + // of being placed under the hardcoded directory /var/run/netns. Changing this setting requires + // that all containers are deleted. + NetNSMountsUnderStateDir bool `toml:"netns_mounts_under_state_dir" json:"netnsMountsUnderStateDir"` +} + +// X509KeyPairStreaming contains the x509 configuration for streaming +type X509KeyPairStreaming struct { + // TLSCertFile is the path to a certificate file + TLSCertFile string `toml:"tls_cert_file" json:"tlsCertFile"` + // TLSKeyFile is the path to a private key file + TLSKeyFile string `toml:"tls_key_file" json:"tlsKeyFile"` +} + +// Config contains all configurations for cri server. +type Config struct { + // PluginConfig is the config for CRI plugin. + PluginConfig + // ContainerdRootDir is the root directory path for containerd. + ContainerdRootDir string `json:"containerdRootDir"` + // ContainerdEndpoint is the containerd endpoint path. + ContainerdEndpoint string `json:"containerdEndpoint"` + // RootDir is the root directory path for managing cri plugin files + // (metadata checkpoint etc.) + RootDir string `json:"rootDir"` + // StateDir is the root directory path for managing volatile pod/container data + StateDir string `json:"stateDir"` +} + +const ( + // RuntimeUntrusted is the implicit runtime defined for ContainerdConfig.UntrustedWorkloadRuntime + RuntimeUntrusted = "untrusted" + // RuntimeDefault is the implicit runtime defined for ContainerdConfig.DefaultRuntime + RuntimeDefault = "default" + // KeyModelNode is the key model where key for encrypted images reside + // on the worker nodes + KeyModelNode = "node" +) + +// ValidatePluginConfig validates the given plugin configuration. +func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { + if c.ContainerdConfig.Runtimes == nil { + c.ContainerdConfig.Runtimes = make(map[string]Runtime) + } + + // Validation for deprecated untrusted_workload_runtime. + if c.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { + log.G(ctx).Warning("`untrusted_workload_runtime` is deprecated, please use `untrusted` runtime in `runtimes` instead") + if _, ok := c.ContainerdConfig.Runtimes[RuntimeUntrusted]; ok { + return errors.Errorf("conflicting definitions: configuration includes both `untrusted_workload_runtime` and `runtimes[%q]`", RuntimeUntrusted) + } + c.ContainerdConfig.Runtimes[RuntimeUntrusted] = c.ContainerdConfig.UntrustedWorkloadRuntime + } + + // Validation for deprecated default_runtime field. + if c.ContainerdConfig.DefaultRuntime.Type != "" { + log.G(ctx).Warning("`default_runtime` is deprecated, please use `default_runtime_name` to reference the default configuration you have defined in `runtimes`") + c.ContainerdConfig.DefaultRuntimeName = RuntimeDefault + c.ContainerdConfig.Runtimes[RuntimeDefault] = c.ContainerdConfig.DefaultRuntime + } + + // Validation for default_runtime_name + if c.ContainerdConfig.DefaultRuntimeName == "" { + return errors.New("`default_runtime_name` is empty") + } + if _, ok := c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName]; !ok { + return errors.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName) + } + + // Validation for deprecated runtime options. + if c.SystemdCgroup { + if c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName].Type != plugin.RuntimeLinuxV1 { + return errors.Errorf("`systemd_cgroup` only works for runtime %s", plugin.RuntimeLinuxV1) + } + log.G(ctx).Warning("`systemd_cgroup` is deprecated, please use runtime `options` instead") + } + if c.NoPivot { + if c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName].Type != plugin.RuntimeLinuxV1 { + return errors.Errorf("`no_pivot` only works for runtime %s", plugin.RuntimeLinuxV1) + } + // NoPivot can't be deprecated yet, because there is no alternative config option + // for `io.containerd.runtime.v1.linux`. + } + for _, r := range c.ContainerdConfig.Runtimes { + if r.Engine != "" { + if r.Type != plugin.RuntimeLinuxV1 { + return errors.Errorf("`runtime_engine` only works for runtime %s", plugin.RuntimeLinuxV1) + } + log.G(ctx).Warning("`runtime_engine` is deprecated, please use runtime `options` instead") + } + if r.Root != "" { + if r.Type != plugin.RuntimeLinuxV1 { + return errors.Errorf("`runtime_root` only works for runtime %s", plugin.RuntimeLinuxV1) + } + log.G(ctx).Warning("`runtime_root` is deprecated, please use runtime `options` instead") + } + } + + useConfigPath := c.Registry.ConfigPath != "" + if len(c.Registry.Mirrors) > 0 { + if useConfigPath { + return errors.Errorf("`mirrors` cannot be set when `config_path` is provided") + } + log.G(ctx).Warning("`mirrors` is deprecated, please use `config_path` instead") + } + var hasDeprecatedTLS bool + for _, r := range c.Registry.Configs { + if r.TLS != nil { + hasDeprecatedTLS = true + break + } + } + if hasDeprecatedTLS { + if useConfigPath { + return errors.Errorf("`configs.tls` cannot be set when `config_path` is provided") + } + log.G(ctx).Warning("`configs.tls` is deprecated, please use `config_path` instead") + } + + // Validation for deprecated auths options and mapping it to configs. + if len(c.Registry.Auths) != 0 { + if c.Registry.Configs == nil { + c.Registry.Configs = make(map[string]RegistryConfig) + } + for endpoint, auth := range c.Registry.Auths { + auth := auth + u, err := url.Parse(endpoint) + if err != nil { + return errors.Wrapf(err, "failed to parse registry url %q from `registry.auths`", endpoint) + } + if u.Scheme != "" { + // Do not include the scheme in the new registry config. + endpoint = u.Host + } + config := c.Registry.Configs[endpoint] + config.Auth = &auth + c.Registry.Configs[endpoint] = config + } + log.G(ctx).Warning("`auths` is deprecated, please use `configs` instead") + } + + // Validation for stream_idle_timeout + if c.StreamIdleTimeout != "" { + if _, err := time.ParseDuration(c.StreamIdleTimeout); err != nil { + return errors.Wrap(err, "invalid stream idle timeout") + } + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/config/config_test.go containerd-1.5.9/pkg/cri/config/config_test.go --- containerd-1.2.6/pkg/cri/config/config_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/config/config_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,374 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "context" + "fmt" + "testing" + + "github.com/containerd/containerd/plugin" + "github.com/stretchr/testify/assert" +) + +func TestValidateConfig(t *testing.T) { + for desc, test := range map[string]struct { + config *PluginConfig + expectedErr string + expected *PluginConfig + }{ + "deprecated untrusted_workload_runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + UntrustedWorkloadRuntime: Runtime{ + Type: "untrusted", + }, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: "default", + }, + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + UntrustedWorkloadRuntime: Runtime{ + Type: "untrusted", + }, + Runtimes: map[string]Runtime{ + RuntimeUntrusted: { + Type: "untrusted", + }, + RuntimeDefault: { + Type: "default", + }, + }, + }, + }, + }, + "both untrusted_workload_runtime and runtime[untrusted]": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + UntrustedWorkloadRuntime: Runtime{ + Type: "untrusted-1", + }, + Runtimes: map[string]Runtime{ + RuntimeUntrusted: { + Type: "untrusted-2", + }, + RuntimeDefault: { + Type: "default", + }, + }, + }, + }, + expectedErr: fmt.Sprintf("conflicting definitions: configuration includes both `untrusted_workload_runtime` and `runtimes[%q]`", RuntimeUntrusted), + }, + "deprecated default_runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntime: Runtime{ + Type: "default", + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntime: Runtime{ + Type: "default", + }, + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: "default", + }, + }, + }, + }, + }, + "no default_runtime_name": { + config: &PluginConfig{}, + expectedErr: "`default_runtime_name` is empty", + }, + "no runtime[default_runtime_name]": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + }, + }, + expectedErr: "no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"default\"", + }, + "deprecated systemd_cgroup for v1 runtime": { + config: &PluginConfig{ + SystemdCgroup: true, + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + expected: &PluginConfig{ + SystemdCgroup: true, + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + }, + "deprecated systemd_cgroup for v2 runtime": { + config: &PluginConfig{ + SystemdCgroup: true, + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeRuncV1, + }, + }, + }, + }, + expectedErr: fmt.Sprintf("`systemd_cgroup` only works for runtime %s", plugin.RuntimeLinuxV1), + }, + "no_pivot for v1 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + NoPivot: true, + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + NoPivot: true, + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + }, + "no_pivot for v2 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + NoPivot: true, + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeRuncV1, + }, + }, + }, + }, + expectedErr: fmt.Sprintf("`no_pivot` only works for runtime %s", plugin.RuntimeLinuxV1), + }, + "deprecated runtime_engine for v1 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Engine: "runc", + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Engine: "runc", + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + }, + "deprecated runtime_engine for v2 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Engine: "runc", + Type: plugin.RuntimeRuncV1, + }, + }, + }, + }, + expectedErr: fmt.Sprintf("`runtime_engine` only works for runtime %s", plugin.RuntimeLinuxV1), + }, + "deprecated runtime_root for v1 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Root: "/run/containerd/runc", + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Root: "/run/containerd/runc", + Type: plugin.RuntimeLinuxV1, + }, + }, + }, + }, + }, + "deprecated runtime_root for v2 runtime": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Root: "/run/containerd/runc", + Type: plugin.RuntimeRuncV1, + }, + }, + }, + }, + expectedErr: fmt.Sprintf("`runtime_root` only works for runtime %s", plugin.RuntimeLinuxV1), + }, + "deprecated auths": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeRuncV1, + }, + }, + }, + Registry: Registry{ + Auths: map[string]AuthConfig{ + "https://gcr.io": {Username: "test"}, + }, + }, + }, + expected: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: plugin.RuntimeRuncV1, + }, + }, + }, + Registry: Registry{ + Configs: map[string]RegistryConfig{ + "gcr.io": { + Auth: &AuthConfig{ + Username: "test", + }, + }, + }, + Auths: map[string]AuthConfig{ + "https://gcr.io": {Username: "test"}, + }, + }, + }, + }, + "invalid stream_idle_timeout": { + config: &PluginConfig{ + StreamIdleTimeout: "invalid", + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: "default", + }, + }, + }, + }, + expectedErr: "invalid stream idle timeout", + }, + "conflicting mirror registry config": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: "default", + }, + }, + }, + Registry: Registry{ + ConfigPath: "/etc/containerd/conf.d", + Mirrors: map[string]Mirror{ + "something.io": {}, + }, + }, + }, + expectedErr: "`mirrors` cannot be set when `config_path` is provided", + }, + "conflicting tls registry config": { + config: &PluginConfig{ + ContainerdConfig: ContainerdConfig{ + DefaultRuntimeName: RuntimeDefault, + Runtimes: map[string]Runtime{ + RuntimeDefault: { + Type: "default", + }, + }, + }, + Registry: Registry{ + ConfigPath: "/etc/containerd/conf.d", + Configs: map[string]RegistryConfig{ + "something.io": { + TLS: &TLSConfig{}, + }, + }, + }, + }, + expectedErr: "`configs.tls` cannot be set when `config_path` is provided", + }, + } { + t.Run(desc, func(t *testing.T) { + err := ValidatePluginConfig(context.Background(), test.config) + if test.expectedErr != "" { + assert.Contains(t, err.Error(), test.expectedErr) + } else { + assert.NoError(t, err) + assert.Equal(t, test.expected, test.config) + } + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/config/config_unix.go containerd-1.5.9/pkg/cri/config/config_unix.go --- containerd-1.2.6/pkg/cri/config/config_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/config/config_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/pkg/cri/streaming" + "github.com/pelletier/go-toml" +) + +// DefaultConfig returns default configurations of cri plugin. +func DefaultConfig() PluginConfig { + defaultRuncV2Opts := ` + # NoPivotRoot disables pivot root when creating a container. + NoPivotRoot = false + + # NoNewKeyring disables new keyring for the container. + NoNewKeyring = false + + # ShimCgroup places the shim in a cgroup. + ShimCgroup = "" + + # IoUid sets the I/O's pipes uid. + IoUid = 0 + + # IoGid sets the I/O's pipes gid. + IoGid = 0 + + # BinaryName is the binary name of the runc binary. + BinaryName = "" + + # Root is the runc root directory. + Root = "" + + # CriuPath is the criu binary path. + CriuPath = "" + + # SystemdCgroup enables systemd cgroups. + SystemdCgroup = false + + # CriuImagePath is the criu image path + CriuImagePath = "" + + # CriuWorkPath is the criu work path. + CriuWorkPath = "" +` + tree, _ := toml.Load(defaultRuncV2Opts) + return PluginConfig{ + CniConfig: CniConfig{ + NetworkPluginBinDir: "/opt/cni/bin", + NetworkPluginConfDir: "/etc/cni/net.d", + NetworkPluginMaxConfNum: 1, // only one CNI plugin config file will be loaded + NetworkPluginConfTemplate: "", + }, + ContainerdConfig: ContainerdConfig{ + Snapshotter: containerd.DefaultSnapshotter, + DefaultRuntimeName: "runc", + NoPivot: false, + Runtimes: map[string]Runtime{ + "runc": { + Type: "io.containerd.runc.v2", + Options: tree.ToMap(), + }, + }, + DisableSnapshotAnnotations: true, + }, + DisableTCPService: true, + StreamServerAddress: "127.0.0.1", + StreamServerPort: "0", + StreamIdleTimeout: streaming.DefaultConfig.StreamIdleTimeout.String(), // 4 hour + EnableSelinux: false, + SelinuxCategoryRange: 1024, + EnableTLSStreaming: false, + X509KeyPairStreaming: X509KeyPairStreaming{ + TLSKeyFile: "", + TLSCertFile: "", + }, + SandboxImage: "k8s.gcr.io/pause:3.5", + StatsCollectPeriod: 10, + SystemdCgroup: false, + MaxContainerLogLineSize: 16 * 1024, + MaxConcurrentDownloads: 3, + DisableProcMount: false, + TolerateMissingHugetlbController: true, + DisableHugetlbController: true, + IgnoreImageDefinedVolumes: false, + ImageDecryption: ImageDecryption{ + KeyModel: KeyModelNode, + }, + } +} diff -Nru containerd-1.2.6/pkg/cri/config/config_windows.go containerd-1.5.9/pkg/cri/config/config_windows.go --- containerd-1.2.6/pkg/cri/config/config_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/config/config_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,68 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "os" + "path/filepath" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/pkg/cri/streaming" +) + +// DefaultConfig returns default configurations of cri plugin. +func DefaultConfig() PluginConfig { + return PluginConfig{ + CniConfig: CniConfig{ + NetworkPluginBinDir: filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "bin"), + NetworkPluginConfDir: filepath.Join(os.Getenv("ProgramFiles"), "containerd", "cni", "conf"), + NetworkPluginMaxConfNum: 1, + NetworkPluginConfTemplate: "", + }, + ContainerdConfig: ContainerdConfig{ + Snapshotter: containerd.DefaultSnapshotter, + DefaultRuntimeName: "runhcs-wcow-process", + NoPivot: false, + Runtimes: map[string]Runtime{ + "runhcs-wcow-process": { + Type: "io.containerd.runhcs.v1", + }, + }, + }, + DisableTCPService: true, + StreamServerAddress: "127.0.0.1", + StreamServerPort: "0", + StreamIdleTimeout: streaming.DefaultConfig.StreamIdleTimeout.String(), // 4 hour + EnableTLSStreaming: false, + X509KeyPairStreaming: X509KeyPairStreaming{ + TLSKeyFile: "", + TLSCertFile: "", + }, + SandboxImage: "k8s.gcr.io/pause:3.5", + StatsCollectPeriod: 10, + MaxContainerLogLineSize: 16 * 1024, + MaxConcurrentDownloads: 3, + IgnoreImageDefinedVolumes: false, + // TODO(windows): Add platform specific config, so that most common defaults can be shared. + + ImageDecryption: ImageDecryption{ + KeyModel: KeyModelNode, + }, + } +} diff -Nru containerd-1.2.6/pkg/cri/constants/constants.go containerd-1.5.9/pkg/cri/constants/constants.go --- containerd-1.2.6/pkg/cri/constants/constants.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/constants/constants.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package constants + +// TODO(random-liu): Merge annotations package into this package. + +const ( + // K8sContainerdNamespace is the namespace we use to connect containerd. + K8sContainerdNamespace = "k8s.io" + // CRIVersion is the CRI version supported by the CRI plugin. + CRIVersion = "v1alpha2" +) diff -Nru containerd-1.2.6/pkg/cri/cri.go containerd-1.5.9/pkg/cri/cri.go --- containerd-1.2.6/pkg/cri/cri.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/cri.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,192 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cri + +import ( + "flag" + "path/filepath" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/api/services/containers/v1" + "github.com/containerd/containerd/api/services/diff/v1" + "github.com/containerd/containerd/api/services/images/v1" + introspectionapi "github.com/containerd/containerd/api/services/introspection/v1" + "github.com/containerd/containerd/api/services/namespaces/v1" + "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/services" + "github.com/containerd/containerd/snapshots" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "k8s.io/klog/v2" + + criconfig "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/constants" + criplatforms "github.com/containerd/containerd/pkg/cri/platforms" + "github.com/containerd/containerd/pkg/cri/server" +) + +// TODO(random-liu): Use github.com/pkg/errors for our errors. +// Register CRI service plugin +func init() { + config := criconfig.DefaultConfig() + plugin.Register(&plugin.Registration{ + Type: plugin.GRPCPlugin, + ID: "cri", + Config: &config, + Requires: []plugin.Type{ + plugin.ServicePlugin, + }, + InitFn: initCRIService, + }) +} + +func initCRIService(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = []imagespec.Platform{platforms.DefaultSpec()} + ic.Meta.Exports = map[string]string{"CRIVersion": constants.CRIVersion} + ctx := ic.Context + pluginConfig := ic.Config.(*criconfig.PluginConfig) + if err := criconfig.ValidatePluginConfig(ctx, pluginConfig); err != nil { + return nil, errors.Wrap(err, "invalid plugin config") + } + + c := criconfig.Config{ + PluginConfig: *pluginConfig, + ContainerdRootDir: filepath.Dir(ic.Root), + ContainerdEndpoint: ic.Address, + RootDir: ic.Root, + StateDir: ic.State, + } + log.G(ctx).Infof("Start cri plugin with config %+v", c) + + if err := setGLogLevel(); err != nil { + return nil, errors.Wrap(err, "failed to set glog level") + } + + servicesOpts, err := getServicesOpts(ic) + if err != nil { + return nil, errors.Wrap(err, "failed to get services") + } + + log.G(ctx).Info("Connect containerd service") + client, err := containerd.New( + "", + containerd.WithDefaultNamespace(constants.K8sContainerdNamespace), + containerd.WithDefaultPlatform(criplatforms.Default()), + containerd.WithServices(servicesOpts...), + ) + if err != nil { + return nil, errors.Wrap(err, "failed to create containerd client") + } + + s, err := server.NewCRIService(c, client) + if err != nil { + return nil, errors.Wrap(err, "failed to create CRI service") + } + + go func() { + if err := s.Run(); err != nil { + log.G(ctx).WithError(err).Fatal("Failed to run CRI service") + } + // TODO(random-liu): Whether and how we can stop containerd. + }() + return s, nil +} + +// getServicesOpts get service options from plugin context. +func getServicesOpts(ic *plugin.InitContext) ([]containerd.ServicesOpt, error) { + plugins, err := ic.GetByType(plugin.ServicePlugin) + if err != nil { + return nil, errors.Wrap(err, "failed to get service plugin") + } + + opts := []containerd.ServicesOpt{ + containerd.WithEventService(ic.Events), + } + for s, fn := range map[string]func(interface{}) containerd.ServicesOpt{ + services.ContentService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithContentStore(s.(content.Store)) + }, + services.ImagesService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithImageService(s.(images.ImagesClient)) + }, + services.SnapshotsService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithSnapshotters(s.(map[string]snapshots.Snapshotter)) + }, + services.ContainersService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithContainerService(s.(containers.ContainersClient)) + }, + services.TasksService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithTaskService(s.(tasks.TasksClient)) + }, + services.DiffService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithDiffService(s.(diff.DiffClient)) + }, + services.NamespacesService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithNamespaceService(s.(namespaces.NamespacesClient)) + }, + services.LeasesService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithLeasesService(s.(leases.Manager)) + }, + services.IntrospectionService: func(s interface{}) containerd.ServicesOpt { + return containerd.WithIntrospectionService(s.(introspectionapi.IntrospectionClient)) + }, + } { + p := plugins[s] + if p == nil { + return nil, errors.Errorf("service %q not found", s) + } + i, err := p.Instance() + if err != nil { + return nil, errors.Wrapf(err, "failed to get instance of service %q", s) + } + if i == nil { + return nil, errors.Errorf("instance of service %q not found", s) + } + opts = append(opts, fn(i)) + } + return opts, nil +} + +// Set glog level. +func setGLogLevel() error { + l := logrus.GetLevel() + fs := flag.NewFlagSet("klog", flag.PanicOnError) + klog.InitFlags(fs) + if err := fs.Set("logtostderr", "true"); err != nil { + return err + } + switch l { + case logrus.TraceLevel: + return fs.Set("v", "5") + case logrus.DebugLevel: + return fs.Set("v", "4") + case logrus.InfoLevel: + return fs.Set("v", "2") + // glog doesn't support following filters. Defaults to v=0. + case logrus.WarnLevel: + case logrus.ErrorLevel: + case logrus.FatalLevel: + case logrus.PanicLevel: + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/io/container_io.go containerd-1.5.9/pkg/cri/io/container_io.go --- containerd-1.2.6/pkg/cri/io/container_io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/container_io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,236 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "errors" + "io" + "strings" + "sync" + + "github.com/containerd/containerd/cio" + "github.com/sirupsen/logrus" + + "github.com/containerd/containerd/pkg/cri/util" + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +// streamKey generates a key for the stream. +func streamKey(id, name string, stream StreamType) string { + return strings.Join([]string{id, name, string(stream)}, "-") +} + +// ContainerIO holds the container io. +type ContainerIO struct { + id string + + fifos *cio.FIFOSet + *stdioPipes + + stdoutGroup *cioutil.WriterGroup + stderrGroup *cioutil.WriterGroup + + closer *wgCloser +} + +var _ cio.IO = &ContainerIO{} + +// ContainerIOOpts sets specific information to newly created ContainerIO. +type ContainerIOOpts func(*ContainerIO) error + +// WithFIFOs specifies existing fifos for the container io. +func WithFIFOs(fifos *cio.FIFOSet) ContainerIOOpts { + return func(c *ContainerIO) error { + c.fifos = fifos + return nil + } +} + +// WithNewFIFOs creates new fifos for the container io. +func WithNewFIFOs(root string, tty, stdin bool) ContainerIOOpts { + return func(c *ContainerIO) error { + fifos, err := newFifos(root, c.id, tty, stdin) + if err != nil { + return err + } + return WithFIFOs(fifos)(c) + } +} + +// NewContainerIO creates container io. +func NewContainerIO(id string, opts ...ContainerIOOpts) (_ *ContainerIO, err error) { + c := &ContainerIO{ + id: id, + stdoutGroup: cioutil.NewWriterGroup(), + stderrGroup: cioutil.NewWriterGroup(), + } + for _, opt := range opts { + if err := opt(c); err != nil { + return nil, err + } + } + if c.fifos == nil { + return nil, errors.New("fifos are not set") + } + // Create actual fifos. + stdio, closer, err := newStdioPipes(c.fifos) + if err != nil { + return nil, err + } + c.stdioPipes = stdio + c.closer = closer + return c, nil +} + +// Config returns io config. +func (c *ContainerIO) Config() cio.Config { + return c.fifos.Config +} + +// Pipe creates container fifos and pipe container output +// to output stream. +func (c *ContainerIO) Pipe() { + wg := c.closer.wg + if c.stdout != nil { + wg.Add(1) + go func() { + if _, err := io.Copy(c.stdoutGroup, c.stdout); err != nil { + logrus.WithError(err).Errorf("Failed to pipe stdout of container %q", c.id) + } + c.stdout.Close() + c.stdoutGroup.Close() + wg.Done() + logrus.Debugf("Finish piping stdout of container %q", c.id) + }() + } + + if !c.fifos.Terminal && c.stderr != nil { + wg.Add(1) + go func() { + if _, err := io.Copy(c.stderrGroup, c.stderr); err != nil { + logrus.WithError(err).Errorf("Failed to pipe stderr of container %q", c.id) + } + c.stderr.Close() + c.stderrGroup.Close() + wg.Done() + logrus.Debugf("Finish piping stderr of container %q", c.id) + }() + } +} + +// Attach attaches container stdio. +// TODO(random-liu): Use pools.Copy in docker to reduce memory usage? +func (c *ContainerIO) Attach(opts AttachOptions) { + var wg sync.WaitGroup + key := util.GenerateID() + stdinKey := streamKey(c.id, "attach-"+key, Stdin) + stdoutKey := streamKey(c.id, "attach-"+key, Stdout) + stderrKey := streamKey(c.id, "attach-"+key, Stderr) + + var stdinStreamRC io.ReadCloser + if c.stdin != nil && opts.Stdin != nil { + // Create a wrapper of stdin which could be closed. Note that the + // wrapper doesn't close the actual stdin, it only stops io.Copy. + // The actual stdin will be closed by stream server. + stdinStreamRC = cioutil.NewWrapReadCloser(opts.Stdin) + wg.Add(1) + go func() { + if _, err := io.Copy(c.stdin, stdinStreamRC); err != nil { + logrus.WithError(err).Errorf("Failed to pipe stdin for container attach %q", c.id) + } + logrus.Infof("Attach stream %q closed", stdinKey) + if opts.StdinOnce && !opts.Tty { + // Due to kubectl requirements and current docker behavior, when (opts.StdinOnce && + // opts.Tty) we have to close container stdin and keep stdout and stderr open until + // container stops. + c.stdin.Close() + // Also closes the containerd side. + if err := opts.CloseStdin(); err != nil { + logrus.WithError(err).Errorf("Failed to close stdin for container %q", c.id) + } + } else { + if opts.Stdout != nil { + c.stdoutGroup.Remove(stdoutKey) + } + if opts.Stderr != nil { + c.stderrGroup.Remove(stderrKey) + } + } + wg.Done() + }() + } + + attachStream := func(key string, close <-chan struct{}) { + <-close + logrus.Infof("Attach stream %q closed", key) + // Make sure stdin gets closed. + if stdinStreamRC != nil { + stdinStreamRC.Close() + } + wg.Done() + } + + if opts.Stdout != nil { + wg.Add(1) + wc, close := cioutil.NewWriteCloseInformer(opts.Stdout) + c.stdoutGroup.Add(stdoutKey, wc) + go attachStream(stdoutKey, close) + } + if !opts.Tty && opts.Stderr != nil { + wg.Add(1) + wc, close := cioutil.NewWriteCloseInformer(opts.Stderr) + c.stderrGroup.Add(stderrKey, wc) + go attachStream(stderrKey, close) + } + wg.Wait() +} + +// AddOutput adds new write closers to the container stream, and returns existing +// write closers if there are any. +func (c *ContainerIO) AddOutput(name string, stdout, stderr io.WriteCloser) (io.WriteCloser, io.WriteCloser) { + var oldStdout, oldStderr io.WriteCloser + if stdout != nil { + key := streamKey(c.id, name, Stdout) + oldStdout = c.stdoutGroup.Get(key) + c.stdoutGroup.Add(key, stdout) + } + if stderr != nil { + key := streamKey(c.id, name, Stderr) + oldStderr = c.stderrGroup.Get(key) + c.stderrGroup.Add(key, stderr) + } + return oldStdout, oldStderr +} + +// Cancel cancels container io. +func (c *ContainerIO) Cancel() { + c.closer.Cancel() +} + +// Wait waits container io to finish. +func (c *ContainerIO) Wait() { + c.closer.Wait() +} + +// Close closes all FIFOs. +func (c *ContainerIO) Close() error { + c.closer.Close() + if c.fifos != nil { + return c.fifos.Close() + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/io/exec_io.go containerd-1.5.9/pkg/cri/io/exec_io.go --- containerd-1.2.6/pkg/cri/io/exec_io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/exec_io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,146 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "io" + "sync" + + "github.com/containerd/containerd/cio" + "github.com/sirupsen/logrus" + + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +// ExecIO holds the exec io. +type ExecIO struct { + id string + fifos *cio.FIFOSet + *stdioPipes + closer *wgCloser +} + +var _ cio.IO = &ExecIO{} + +// NewExecIO creates exec io. +func NewExecIO(id, root string, tty, stdin bool) (*ExecIO, error) { + fifos, err := newFifos(root, id, tty, stdin) + if err != nil { + return nil, err + } + stdio, closer, err := newStdioPipes(fifos) + if err != nil { + return nil, err + } + return &ExecIO{ + id: id, + fifos: fifos, + stdioPipes: stdio, + closer: closer, + }, nil +} + +// Config returns io config. +func (e *ExecIO) Config() cio.Config { + return e.fifos.Config +} + +// Attach attaches exec stdio. The logic is similar with container io attach. +func (e *ExecIO) Attach(opts AttachOptions) <-chan struct{} { + var wg sync.WaitGroup + var stdinStreamRC io.ReadCloser + if e.stdin != nil && opts.Stdin != nil { + stdinStreamRC = cioutil.NewWrapReadCloser(opts.Stdin) + wg.Add(1) + go func() { + if _, err := io.Copy(e.stdin, stdinStreamRC); err != nil { + logrus.WithError(err).Errorf("Failed to redirect stdin for container exec %q", e.id) + } + logrus.Infof("Container exec %q stdin closed", e.id) + if opts.StdinOnce && !opts.Tty { + e.stdin.Close() + if err := opts.CloseStdin(); err != nil { + logrus.WithError(err).Errorf("Failed to close stdin for container exec %q", e.id) + } + } else { + if e.stdout != nil { + e.stdout.Close() + } + if e.stderr != nil { + e.stderr.Close() + } + } + wg.Done() + }() + } + + attachOutput := func(t StreamType, stream io.WriteCloser, out io.ReadCloser) { + if _, err := io.Copy(stream, out); err != nil { + logrus.WithError(err).Errorf("Failed to pipe %q for container exec %q", t, e.id) + } + out.Close() + stream.Close() + if stdinStreamRC != nil { + stdinStreamRC.Close() + } + e.closer.wg.Done() + wg.Done() + logrus.Debugf("Finish piping %q of container exec %q", t, e.id) + } + + if opts.Stdout != nil { + wg.Add(1) + // Closer should wait for this routine to be over. + e.closer.wg.Add(1) + go attachOutput(Stdout, opts.Stdout, e.stdout) + } + + if !opts.Tty && opts.Stderr != nil { + wg.Add(1) + // Closer should wait for this routine to be over. + e.closer.wg.Add(1) + go attachOutput(Stderr, opts.Stderr, e.stderr) + } + + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + return done +} + +// Cancel cancels exec io. +func (e *ExecIO) Cancel() { + e.closer.Cancel() +} + +// Wait waits exec io to finish. +func (e *ExecIO) Wait() { + e.closer.Wait() +} + +// Close closes all FIFOs. +func (e *ExecIO) Close() error { + if e.closer != nil { + e.closer.Close() + } + if e.fifos != nil { + return e.fifos.Close() + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/io/helpers.go containerd-1.5.9/pkg/cri/io/helpers.go --- containerd-1.2.6/pkg/cri/io/helpers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,144 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "io" + "os" + "path/filepath" + "sync" + "syscall" + + "github.com/containerd/containerd/cio" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// AttachOptions specifies how to attach to a container. +type AttachOptions struct { + Stdin io.Reader + Stdout io.WriteCloser + Stderr io.WriteCloser + Tty bool + StdinOnce bool + // CloseStdin is the function to close container stdin. + CloseStdin func() error +} + +// StreamType is the type of the stream, stdout/stderr. +type StreamType string + +const ( + // Stdin stream type. + Stdin StreamType = "stdin" + // Stdout stream type. + Stdout StreamType = StreamType(runtime.Stdout) + // Stderr stream type. + Stderr StreamType = StreamType(runtime.Stderr) +) + +type wgCloser struct { + ctx context.Context + wg *sync.WaitGroup + set []io.Closer + cancel context.CancelFunc +} + +func (g *wgCloser) Wait() { + g.wg.Wait() +} + +func (g *wgCloser) Close() { + for _, f := range g.set { + f.Close() + } +} + +func (g *wgCloser) Cancel() { + g.cancel() +} + +// newFifos creates fifos directory for a container. +func newFifos(root, id string, tty, stdin bool) (*cio.FIFOSet, error) { + root = filepath.Join(root, "io") + if err := os.MkdirAll(root, 0700); err != nil { + return nil, err + } + fifos, err := cio.NewFIFOSetInDir(root, id, tty) + if err != nil { + return nil, err + } + if !stdin { + fifos.Stdin = "" + } + return fifos, nil +} + +type stdioPipes struct { + stdin io.WriteCloser + stdout io.ReadCloser + stderr io.ReadCloser +} + +// newStdioPipes creates actual fifos for stdio. +func newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, _ *wgCloser, err error) { + var ( + f io.ReadWriteCloser + set []io.Closer + ctx, cancel = context.WithCancel(context.Background()) + p = &stdioPipes{} + ) + defer func() { + if err != nil { + for _, f := range set { + f.Close() + } + cancel() + } + }() + + if fifos.Stdin != "" { + if f, err = openPipe(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { + return nil, nil, err + } + p.stdin = f + set = append(set, f) + } + + if fifos.Stdout != "" { + if f, err = openPipe(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { + return nil, nil, err + } + p.stdout = f + set = append(set, f) + } + + if fifos.Stderr != "" { + if f, err = openPipe(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { + return nil, nil, err + } + p.stderr = f + set = append(set, f) + } + + return p, &wgCloser{ + wg: &sync.WaitGroup{}, + set: set, + ctx: ctx, + cancel: cancel, + }, nil +} diff -Nru containerd-1.2.6/pkg/cri/io/helpers_unix.go containerd-1.5.9/pkg/cri/io/helpers_unix.go --- containerd-1.2.6/pkg/cri/io/helpers_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/helpers_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "io" + "os" + + "github.com/containerd/fifo" + "golang.org/x/net/context" +) + +func openPipe(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) { + return fifo.OpenFifo(ctx, fn, flag, perm) +} diff -Nru containerd-1.2.6/pkg/cri/io/helpers_windows.go containerd-1.5.9/pkg/cri/io/helpers_windows.go --- containerd-1.2.6/pkg/cri/io/helpers_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/helpers_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,85 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "io" + "net" + "os" + "sync" + + winio "github.com/Microsoft/go-winio" + "github.com/pkg/errors" + "golang.org/x/net/context" +) + +type pipe struct { + l net.Listener + con net.Conn + conErr error + conWg sync.WaitGroup +} + +func openPipe(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) { + l, err := winio.ListenPipe(fn, nil) + if err != nil { + return nil, err + } + p := &pipe{l: l} + p.conWg.Add(1) + go func() { + defer p.conWg.Done() + c, err := l.Accept() + if err != nil { + p.conErr = err + return + } + p.con = c + }() + go func() { + <-ctx.Done() + p.Close() + }() + return p, nil +} + +func (p *pipe) Write(b []byte) (int, error) { + p.conWg.Wait() + if p.conErr != nil { + return 0, errors.Wrap(p.conErr, "connection error") + } + return p.con.Write(b) +} + +func (p *pipe) Read(b []byte) (int, error) { + p.conWg.Wait() + if p.conErr != nil { + return 0, errors.Wrap(p.conErr, "connection error") + } + return p.con.Read(b) +} + +func (p *pipe) Close() error { + p.l.Close() + p.conWg.Wait() + if p.con != nil { + return p.con.Close() + } + return p.conErr +} diff -Nru containerd-1.2.6/pkg/cri/io/logger.go containerd-1.5.9/pkg/cri/io/logger.go --- containerd-1.2.6/pkg/cri/io/logger.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/logger.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,208 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "time" + + "github.com/sirupsen/logrus" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +const ( + // delimiter used in CRI logging format. + delimiter = ' ' + // eof is end-of-line. + eol = '\n' + // timestampFormat is the timestamp format used in CRI logging format. + timestampFormat = time.RFC3339Nano + // defaultBufSize is the default size of the read buffer in bytes. + defaultBufSize = 4096 +) + +// NewDiscardLogger creates logger which discards all the input. +func NewDiscardLogger() io.WriteCloser { + return cioutil.NewNopWriteCloser(ioutil.Discard) +} + +// NewCRILogger returns a write closer which redirect container log into +// log file, and decorate the log line into CRI defined format. It also +// returns a channel which indicates whether the logger is stopped. +// maxLen is the max length limit of a line. A line longer than the +// limit will be cut into multiple lines. +func NewCRILogger(path string, w io.Writer, stream StreamType, maxLen int) (io.WriteCloser, <-chan struct{}) { + logrus.Debugf("Start writing stream %q to log file %q", stream, path) + prc, pwc := io.Pipe() + stop := make(chan struct{}) + go func() { + redirectLogs(path, prc, w, stream, maxLen) + close(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) { + defer rc.Close() + var ( + stream = []byte(s) + delimiter = []byte{delimiter} + partial = []byte(runtime.LogTagPartial) + full = []byte(runtime.LogTagFull) + buf [][]byte + length int + bufSize = defaultBufSize + + timeBuffer = make([]byte, len(timestampFormat)) + lineBuffer = bytes.Buffer{} + ) + // Make sure bufSize <= maxLen + if maxLen > 0 && maxLen < bufSize { + bufSize = maxLen + } + r := bufio.NewReaderSize(rc, bufSize) + writeLineBuffer := func(tag []byte, lineBytes [][]byte) { + timeBuffer = time.Now().AppendFormat(timeBuffer[:0], timestampFormat) + headers := [][]byte{timeBuffer, stream, tag} + + lineBuffer.Reset() + for _, h := range headers { + lineBuffer.Write(h) + lineBuffer.Write(delimiter) + } + for _, l := range lineBytes { + lineBuffer.Write(l) + } + lineBuffer.WriteByte(eol) + if _, err := lineBuffer.WriteTo(w); err != nil { + logrus.WithError(err).Errorf("Fail to write %q log to log file %q", s, path) + // Continue on write error to drain the container output. + } + } + for { + var stop bool + 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 == io.EOF { + logrus.Debugf("Getting EOF from stream %q while redirecting to log file %q", s, path) + } else { + logrus.WithError(err).Errorf("An error occurred when redirecting stream %q to log file %q", s, path) + } + if length == 0 { + // No content left to write, break. + break + } + // Stop after writing the content left in buffer. + stop = true + } + if maxLen > 0 && length > maxLen { + exceedLen := length - maxLen + last := buf[len(buf)-1] + if exceedLen > len(last) { + // exceedLen must <= len(last), or else the buffer + // should have be written in the previous iteration. + panic("exceed length should <= last buffer size") + } + buf[len(buf)-1] = last[:len(last)-exceedLen] + writeLineBuffer(partial, buf) + buf = [][]byte{last[len(last)-exceedLen:]} + length = exceedLen + } + if isPrefix { + 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. + writeLineBuffer(partial, buf) + } else { + writeLineBuffer(full, buf) + } + buf = nil + length = 0 + if stop { + break + } + } + logrus.Debugf("Finish redirecting stream %q to log file %q", s, path) +} diff -Nru containerd-1.2.6/pkg/cri/io/logger_test.go containerd-1.5.9/pkg/cri/io/logger_test.go --- containerd-1.2.6/pkg/cri/io/logger_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/io/logger_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,258 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package io + +import ( + "bytes" + "io/ioutil" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +func TestRedirectLogs(t *testing.T) { + // defaultBufSize is even number + const maxLen = defaultBufSize * 4 + for desc, test := range map[string]struct { + input string + stream StreamType + maxLen int + tag []runtime.LogTag + content []string + }{ + "stdout log": { + input: "test stdout log 1\ntest stdout log 2\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + "test stdout log 1", + "test stdout log 2", + }, + }, + "stderr log": { + input: "test stderr log 1\ntest stderr log 2\n", + stream: Stderr, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + "test stderr log 1", + "test stderr log 2", + }, + }, + "log ends without newline": { + input: "test stderr log 1\ntest stderr log 2", + stream: Stderr, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagPartial, + }, + content: []string{ + "test stderr log 1", + "test stderr log 2", + }, + }, + "log length equal to buffer size": { + input: strings.Repeat("a", defaultBufSize) + "\n" + strings.Repeat("a", defaultBufSize) + "\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize), + strings.Repeat("a", defaultBufSize), + }, + }, + "log length longer than buffer size": { + input: strings.Repeat("a", defaultBufSize*2+10) + "\n" + strings.Repeat("a", defaultBufSize*2+20) + "\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize*2+10), + strings.Repeat("a", defaultBufSize*2+20), + }, + }, + "log length equal to max length": { + input: strings.Repeat("a", maxLen) + "\n" + strings.Repeat("a", maxLen) + "\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", maxLen), + strings.Repeat("a", maxLen), + }, + }, + "log length exceed max length by 1": { + input: strings.Repeat("a", maxLen+1) + "\n" + strings.Repeat("a", maxLen+1) + "\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagPartial, + runtime.LogTagFull, + runtime.LogTagPartial, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", maxLen), + "a", + strings.Repeat("a", maxLen), + "a", + }, + }, + "log length longer than max length": { + input: strings.Repeat("a", maxLen*2) + "\n" + strings.Repeat("a", maxLen*2+1) + "\n", + stream: Stdout, + maxLen: maxLen, + tag: []runtime.LogTag{ + runtime.LogTagPartial, + runtime.LogTagFull, + runtime.LogTagPartial, + runtime.LogTagPartial, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", maxLen), + strings.Repeat("a", maxLen), + strings.Repeat("a", maxLen), + strings.Repeat("a", maxLen), + "a", + }, + }, + "max length shorter than buffer size": { + input: strings.Repeat("a", defaultBufSize*3/2+10) + "\n" + strings.Repeat("a", defaultBufSize*3/2+20) + "\n", + stream: Stdout, + maxLen: defaultBufSize / 2, + tag: []runtime.LogTag{ + runtime.LogTagPartial, + runtime.LogTagPartial, + runtime.LogTagPartial, + runtime.LogTagFull, + runtime.LogTagPartial, + runtime.LogTagPartial, + runtime.LogTagPartial, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", 10), + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", defaultBufSize*1/2), + strings.Repeat("a", 20), + }, + }, + "log length longer than max length, and (maxLen % defaultBufSize != 0)": { + input: strings.Repeat("a", defaultBufSize*2+10) + "\n" + strings.Repeat("a", defaultBufSize*2+20) + "\n", + stream: Stdout, + maxLen: defaultBufSize * 3 / 2, + tag: []runtime.LogTag{ + runtime.LogTagPartial, + runtime.LogTagFull, + runtime.LogTagPartial, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize*3/2), + strings.Repeat("a", defaultBufSize*1/2+10), + strings.Repeat("a", defaultBufSize*3/2), + strings.Repeat("a", defaultBufSize*1/2+20), + }, + }, + "no limit if max length is 0": { + input: strings.Repeat("a", defaultBufSize*10+10) + "\n" + strings.Repeat("a", defaultBufSize*10+20) + "\n", + stream: Stdout, + maxLen: 0, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize*10+10), + strings.Repeat("a", defaultBufSize*10+20), + }, + }, + "no limit if max length is negative": { + input: strings.Repeat("a", defaultBufSize*10+10) + "\n" + strings.Repeat("a", defaultBufSize*10+20) + "\n", + stream: Stdout, + maxLen: -1, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize*10+10), + strings.Repeat("a", defaultBufSize*10+20), + }, + }, + "log length longer than buffer size with tailing \\r\\n": { + input: strings.Repeat("a", defaultBufSize-1) + "\r\n" + strings.Repeat("a", defaultBufSize-1) + "\r\n", + stream: Stdout, + maxLen: -1, + tag: []runtime.LogTag{ + runtime.LogTagFull, + runtime.LogTagFull, + }, + content: []string{ + strings.Repeat("a", defaultBufSize-1), + strings.Repeat("a", defaultBufSize-1), + }, + }, + } { + t.Logf("TestCase %q", desc) + rc := ioutil.NopCloser(strings.NewReader(test.input)) + buf := bytes.NewBuffer(nil) + wc := cioutil.NewNopWriteCloser(buf) + redirectLogs("test-path", rc, wc, test.stream, test.maxLen) + output := buf.String() + lines := strings.Split(output, "\n") + lines = lines[:len(lines)-1] // Discard empty string after last \n + assert.Len(t, lines, len(test.content)) + for i := range lines { + fields := strings.SplitN(lines[i], string([]byte{delimiter}), 4) + require.Len(t, fields, 4) + _, err := time.Parse(timestampFormat, fields[0]) + assert.NoError(t, err) + assert.EqualValues(t, test.stream, fields[1]) + assert.Equal(t, string(test.tag[i]), fields[2]) + assert.Equal(t, test.content[i], fields[3]) + } + } +} diff -Nru containerd-1.2.6/pkg/cri/opts/container.go containerd-1.5.9/pkg/cri/opts/container.go --- containerd-1.2.6/pkg/cri/opts/container.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/container.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,119 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/snapshots" + "github.com/containerd/continuity/fs" + "github.com/pkg/errors" +) + +// WithNewSnapshot wraps `containerd.WithNewSnapshot` so that if creating the +// snapshot fails we make sure the image is actually unpacked and and retry. +func WithNewSnapshot(id string, i containerd.Image, opts ...snapshots.Opt) containerd.NewContainerOpts { + f := containerd.WithNewSnapshot(id, i, opts...) + return func(ctx context.Context, client *containerd.Client, c *containers.Container) error { + if err := f(ctx, client, c); err != nil { + if !errdefs.IsNotFound(err) { + return err + } + + if err := i.Unpack(ctx, c.Snapshotter); err != nil { + return errors.Wrap(err, "error unpacking image") + } + return f(ctx, client, c) + } + return nil + } +} + +// WithVolumes copies ownership of volume in rootfs to its corresponding host path. +// It doesn't update runtime spec. +// The passed in map is a host path to container path map for all volumes. +func WithVolumes(volumeMounts map[string]string) containerd.NewContainerOpts { + return func(ctx context.Context, client *containerd.Client, c *containers.Container) (err error) { + if c.Snapshotter == "" { + return errors.New("no snapshotter set for container") + } + if c.SnapshotKey == "" { + return errors.New("rootfs not created for container") + } + snapshotter := client.SnapshotService(c.Snapshotter) + mounts, err := snapshotter.Mounts(ctx, c.SnapshotKey) + if err != nil { + return err + } + root, err := ioutil.TempDir("", "ctd-volume") + if err != nil { + return err + } + // We change RemoveAll to Remove so that we either leak a temp dir + // if it fails but not RM snapshot data. + // refer to https://github.com/containerd/containerd/pull/1868 + // https://github.com/containerd/containerd/pull/1785 + defer os.Remove(root) // nolint: errcheck + if err := mount.All(mounts, root); err != nil { + return errors.Wrap(err, "failed to mount") + } + defer func() { + if uerr := mount.Unmount(root, 0); uerr != nil { + log.G(ctx).WithError(uerr).Errorf("Failed to unmount snapshot %q", c.SnapshotKey) + if err == nil { + err = uerr + } + } + }() + + for host, volume := range volumeMounts { + src := filepath.Join(root, volume) + if _, err := os.Stat(src); err != nil { + if os.IsNotExist(err) { + // Skip copying directory if it does not exist. + continue + } + return errors.Wrap(err, "stat volume in rootfs") + } + if err := copyExistingContents(src, host); err != nil { + return errors.Wrap(err, "taking runtime copy of volume") + } + } + return nil + } +} + +// copyExistingContents copies from the source to the destination and +// ensures the ownership is appropriately set. +func copyExistingContents(source, destination string) error { + dstList, err := ioutil.ReadDir(destination) + if err != nil { + return err + } + if len(dstList) != 0 { + return errors.Errorf("volume at %q is not initially empty", destination) + } + return fs.CopyDir(destination, source, fs.WithXAttrExclude("security.selinux")) +} diff -Nru containerd-1.2.6/pkg/cri/opts/spec.go containerd-1.5.9/pkg/cri/opts/spec.go --- containerd-1.2.6/pkg/cri/opts/spec.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/spec.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,113 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + "os" + "path/filepath" + "strings" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// DefaultSandboxCPUshares is default cpu shares for sandbox container. +// TODO(windows): Revisit cpu shares for windows (https://github.com/containerd/cri/issues/1297) +const DefaultSandboxCPUshares = 2 + +// WithRelativeRoot sets the root for the container +func WithRelativeRoot(root string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + if s.Root == nil { + s.Root = &runtimespec.Root{} + } + s.Root.Path = root + return nil + } +} + +// WithoutRoot sets the root to nil for the container. +func WithoutRoot(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + s.Root = nil + return nil +} + +// WithProcessArgs sets the process args on the spec based on the image and runtime config +func WithProcessArgs(config *runtime.ContainerConfig, image *imagespec.ImageConfig) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + command, args := config.GetCommand(), config.GetArgs() + // The following logic is migrated from https://github.com/moby/moby/blob/master/daemon/commit.go + // TODO(random-liu): Clearly define the commands overwrite behavior. + if len(command) == 0 { + // Copy array to avoid data race. + if len(args) == 0 { + args = append([]string{}, image.Cmd...) + } + if command == nil { + command = append([]string{}, image.Entrypoint...) + } + } + if len(command) == 0 && len(args) == 0 { + return errors.New("no command specified") + } + return oci.WithProcessArgs(append(command, args...)...)(ctx, client, c, s) + } +} + +// mounts defines how to sort runtime.Mount. +// This is the same with the Docker implementation: +// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26 +type orderedMounts []*runtime.Mount + +// Len returns the number of mounts. Used in sorting. +func (m orderedMounts) Len() int { + return len(m) +} + +// Less returns true if the number of parts (a/b/c would be 3 parts) in the +// mount indexed by parameter 1 is less than that of the mount indexed by +// parameter 2. Used in sorting. +func (m orderedMounts) Less(i, j int) bool { + return m.parts(i) < m.parts(j) +} + +// Swap swaps two items in an array of mounts. Used in sorting +func (m orderedMounts) Swap(i, j int) { + m[i], m[j] = m[j], m[i] +} + +// parts returns the number of parts in the destination of a mount. Used in sorting. +func (m orderedMounts) parts(i int) int { + return strings.Count(filepath.Clean(m[i].ContainerPath), string(os.PathSeparator)) +} + +// WithAnnotation sets the provided annotation +func WithAnnotation(k, v string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Annotations == nil { + s.Annotations = make(map[string]string) + } + s.Annotations[k] = v + return nil + } +} diff -Nru containerd-1.2.6/pkg/cri/opts/spec_linux.go containerd-1.5.9/pkg/cri/opts/spec_linux.go --- containerd-1.2.6/pkg/cri/opts/spec_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/spec_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,676 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "syscall" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/oci" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/util" + osinterface "github.com/containerd/containerd/pkg/os" +) + +// WithAdditionalGIDs adds any additional groups listed for a particular user in the +// /etc/groups file of the image's root filesystem to the OCI spec's additionalGids array. +func WithAdditionalGIDs(userstr string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + gids := s.Process.User.AdditionalGids + if err := oci.WithAdditionalGIDs(userstr)(ctx, client, c, s); err != nil { + return err + } + // Merge existing gids and new gids. + s.Process.User.AdditionalGids = mergeGids(s.Process.User.AdditionalGids, gids) + return nil + } +} + +func mergeGids(gids1, gids2 []uint32) []uint32 { + gidsMap := make(map[uint32]struct{}) + for _, gid1 := range gids1 { + gidsMap[gid1] = struct{}{} + } + for _, gid2 := range gids2 { + gidsMap[gid2] = struct{}{} + } + var gids []uint32 + for gid := range gidsMap { + gids = append(gids, gid) + } + sort.Slice(gids, func(i, j int) bool { return gids[i] < gids[j] }) + return gids +} + +// WithoutDefaultSecuritySettings removes the default security settings generated on a spec +func WithoutDefaultSecuritySettings(_ context.Context, _ oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + // Make sure no default seccomp/apparmor is specified + s.Process.ApparmorProfile = "" + if s.Linux != nil { + s.Linux.Seccomp = nil + } + // Remove default rlimits (See issue #515) + s.Process.Rlimits = nil + return nil +} + +// WithMounts sorts and adds runtime and CRI mounts to the spec +func WithMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*runtime.Mount, mountLabel string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, _ *containers.Container, s *runtimespec.Spec) (err error) { + // mergeMounts merge CRI mounts with extra mounts. If a mount destination + // is mounted by both a CRI mount and an extra mount, the CRI mount will + // be kept. + var ( + criMounts = config.GetMounts() + mounts = append([]*runtime.Mount{}, criMounts...) + ) + // Copy all mounts from extra mounts, except for mounts overridden by CRI. + for _, e := range extra { + found := false + for _, c := range criMounts { + if filepath.Clean(e.ContainerPath) == filepath.Clean(c.ContainerPath) { + found = true + break + } + } + if !found { + mounts = append(mounts, e) + } + } + + // Sort mounts in number of parts. This ensures that high level mounts don't + // shadow other mounts. + sort.Sort(orderedMounts(mounts)) + + // Mount cgroup into the container as readonly, which inherits docker's behavior. + s.Mounts = append(s.Mounts, runtimespec.Mount{ + Source: "cgroup", + Destination: "/sys/fs/cgroup", + Type: "cgroup", + Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, + }) + + // Copy all mounts from default mounts, except for + // - mounts overridden by supplied mount; + // - all mounts under /dev if a supplied /dev is present. + mountSet := make(map[string]struct{}) + for _, m := range mounts { + mountSet[filepath.Clean(m.ContainerPath)] = struct{}{} + } + + defaultMounts := s.Mounts + s.Mounts = nil + + for _, m := range defaultMounts { + dst := filepath.Clean(m.Destination) + if _, ok := mountSet[dst]; ok { + // filter out mount overridden by a supplied mount + continue + } + if _, mountDev := mountSet["/dev"]; mountDev && strings.HasPrefix(dst, "/dev/") { + // filter out everything under /dev if /dev is a supplied mount + continue + } + s.Mounts = append(s.Mounts, m) + } + + for _, mount := range mounts { + var ( + dst = mount.GetContainerPath() + src = mount.GetHostPath() + ) + // Create the host path if it doesn't exist. + // TODO(random-liu): Add CRI validation test for this case. + if _, err := osi.Stat(src); err != nil { + if !os.IsNotExist(err) { + return errors.Wrapf(err, "failed to stat %q", src) + } + if err := osi.MkdirAll(src, 0755); err != nil { + return errors.Wrapf(err, "failed to mkdir %q", src) + } + } + // TODO(random-liu): Add cri-containerd integration test or cri validation test + // for this. + src, err := osi.ResolveSymbolicLink(src) + if err != nil { + return errors.Wrapf(err, "failed to resolve symlink %q", src) + } + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + options := []string{"rbind"} + switch mount.GetPropagation() { + case runtime.MountPropagation_PROPAGATION_PRIVATE: + options = append(options, "rprivate") + // Since default root propagation in runc is rprivate ignore + // setting the root propagation + case runtime.MountPropagation_PROPAGATION_BIDIRECTIONAL: + if err := ensureShared(src, osi.(osinterface.UNIX).LookupMount); err != nil { + return err + } + options = append(options, "rshared") + s.Linux.RootfsPropagation = "rshared" + case runtime.MountPropagation_PROPAGATION_HOST_TO_CONTAINER: + if err := ensureSharedOrSlave(src, osi.(osinterface.UNIX).LookupMount); err != nil { + return err + } + options = append(options, "rslave") + if s.Linux.RootfsPropagation != "rshared" && + s.Linux.RootfsPropagation != "rslave" { + s.Linux.RootfsPropagation = "rslave" + } + default: + log.G(ctx).Warnf("Unknown propagation mode for hostPath %q", mount.HostPath) + options = append(options, "rprivate") + } + + // NOTE(random-liu): we don't change all mounts to `ro` when root filesystem + // is readonly. This is different from docker's behavior, but make more sense. + if mount.GetReadonly() { + options = append(options, "ro") + } else { + options = append(options, "rw") + } + + if mount.GetSelinuxRelabel() { + if err := label.Relabel(src, mountLabel, false); err != nil && err != unix.ENOTSUP { + return errors.Wrapf(err, "relabel %q with %q failed", src, mountLabel) + } + } + s.Mounts = append(s.Mounts, runtimespec.Mount{ + Source: src, + Destination: dst, + Type: "bind", + Options: options, + }) + } + return nil + } +} + +// Ensure mount point on which path is mounted, is shared. +func ensureShared(path string, lookupMount func(string) (mount.Info, error)) error { + mountInfo, err := lookupMount(path) + if err != nil { + return err + } + + // Make sure source mount point is shared. + optsSplit := strings.Split(mountInfo.Optional, " ") + for _, opt := range optsSplit { + if strings.HasPrefix(opt, "shared:") { + return nil + } + } + + return errors.Errorf("path %q is mounted on %q but it is not a shared mount", path, mountInfo.Mountpoint) +} + +// ensure mount point on which path is mounted, is either shared or slave. +func ensureSharedOrSlave(path string, lookupMount func(string) (mount.Info, error)) error { + mountInfo, err := lookupMount(path) + if err != nil { + return err + } + // Make sure source mount point is shared. + optsSplit := strings.Split(mountInfo.Optional, " ") + for _, opt := range optsSplit { + if strings.HasPrefix(opt, "shared:") { + return nil + } else if strings.HasPrefix(opt, "master:") { + return nil + } + } + return errors.Errorf("path %q is mounted on %q but it is not a shared or slave mount", path, mountInfo.Mountpoint) +} + +// WithDevices sets the provided devices onto the container spec +func WithDevices(osi osinterface.OS, config *runtime.ContainerConfig) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + if s.Linux.Resources == nil { + s.Linux.Resources = &runtimespec.LinuxResources{} + } + + for _, device := range config.GetDevices() { + path, err := osi.ResolveSymbolicLink(device.HostPath) + if err != nil { + return err + } + + o := oci.WithDevices(path, device.ContainerPath, device.Permissions) + if err := o(ctx, client, c, s); err != nil { + return err + } + } + return nil + } +} + +// WithCapabilities sets the provided capabilities from the security context +func WithCapabilities(sc *runtime.LinuxContainerSecurityContext, allCaps []string) oci.SpecOpts { + capabilities := sc.GetCapabilities() + if capabilities == nil { + return nullOpt + } + + var opts []oci.SpecOpts + // Add/drop all capabilities if "all" is specified, so that + // following individual add/drop could still work. E.g. + // AddCapabilities: []string{"ALL"}, DropCapabilities: []string{"CHOWN"} + // will be all capabilities without `CAP_CHOWN`. + if util.InStringSlice(capabilities.GetAddCapabilities(), "ALL") { + opts = append(opts, oci.WithCapabilities(allCaps)) + } + if util.InStringSlice(capabilities.GetDropCapabilities(), "ALL") { + opts = append(opts, oci.WithCapabilities(nil)) + } + + var caps []string + for _, c := range capabilities.GetAddCapabilities() { + if strings.ToUpper(c) == "ALL" { + continue + } + // Capabilities in CRI doesn't have `CAP_` prefix, so add it. + caps = append(caps, "CAP_"+strings.ToUpper(c)) + } + opts = append(opts, oci.WithAddedCapabilities(caps)) + + caps = []string{} + for _, c := range capabilities.GetDropCapabilities() { + if strings.ToUpper(c) == "ALL" { + continue + } + caps = append(caps, "CAP_"+strings.ToUpper(c)) + } + opts = append(opts, oci.WithDroppedCapabilities(caps)) + return oci.Compose(opts...) +} + +// WithoutAmbientCaps removes the ambient caps from the spec +func WithoutAmbientCaps(_ context.Context, _ oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + if s.Process.Capabilities == nil { + s.Process.Capabilities = &runtimespec.LinuxCapabilities{} + } + s.Process.Capabilities.Ambient = nil + return nil +} + +// WithDisabledCgroups clears the Cgroups Path from the spec +func WithDisabledCgroups(_ context.Context, _ oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + s.Linux.CgroupsPath = "" + return nil +} + +// WithSelinuxLabels sets the mount and process labels +func WithSelinuxLabels(process, mount string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + s.Linux.MountLabel = mount + s.Process.SelinuxLabel = process + return nil + } +} + +// WithResources sets the provided resource restrictions +func WithResources(resources *runtime.LinuxContainerResources, tolerateMissingHugetlbController, disableHugetlbController bool) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { + if resources == nil { + return nil + } + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + if s.Linux.Resources == nil { + s.Linux.Resources = &runtimespec.LinuxResources{} + } + if s.Linux.Resources.CPU == nil { + s.Linux.Resources.CPU = &runtimespec.LinuxCPU{} + } + if s.Linux.Resources.Memory == nil { + s.Linux.Resources.Memory = &runtimespec.LinuxMemory{} + } + var ( + p = uint64(resources.GetCpuPeriod()) + q = resources.GetCpuQuota() + shares = uint64(resources.GetCpuShares()) + limit = resources.GetMemoryLimitInBytes() + hugepages = resources.GetHugepageLimits() + ) + + if p != 0 { + s.Linux.Resources.CPU.Period = &p + } + if q != 0 { + s.Linux.Resources.CPU.Quota = &q + } + if shares != 0 { + s.Linux.Resources.CPU.Shares = &shares + } + if cpus := resources.GetCpusetCpus(); cpus != "" { + s.Linux.Resources.CPU.Cpus = cpus + } + if mems := resources.GetCpusetMems(); mems != "" { + s.Linux.Resources.CPU.Mems = resources.GetCpusetMems() + } + if limit != 0 { + s.Linux.Resources.Memory.Limit = &limit + } + if !disableHugetlbController { + if isHugetlbControllerPresent() { + for _, limit := range hugepages { + s.Linux.Resources.HugepageLimits = append(s.Linux.Resources.HugepageLimits, runtimespec.LinuxHugepageLimit{ + Pagesize: limit.PageSize, + Limit: limit.Limit, + }) + } + } else { + if !tolerateMissingHugetlbController { + return errors.Errorf("huge pages limits are specified but hugetlb cgroup controller is missing. " + + "Please set tolerate_missing_hugetlb_controller to `true` to ignore this error") + } + logrus.Warn("hugetlb cgroup controller is absent. skipping huge pages limits") + } + } + return nil + } +} + +var ( + supportsHugetlbOnce sync.Once + supportsHugetlb bool +) + +func isHugetlbControllerPresent() bool { + supportsHugetlbOnce.Do(func() { + supportsHugetlb = false + if IsCgroup2UnifiedMode() { + supportsHugetlb, _ = cgroupv2HasHugetlb() + } else { + supportsHugetlb, _ = cgroupv1HasHugetlb() + } + }) + return supportsHugetlb +} + +var ( + _cgroupv1HasHugetlbOnce sync.Once + _cgroupv1HasHugetlb bool + _cgroupv1HasHugetlbErr error + _cgroupv2HasHugetlbOnce sync.Once + _cgroupv2HasHugetlb bool + _cgroupv2HasHugetlbErr error + isUnifiedOnce sync.Once + isUnified bool +) + +// cgroupv1HasHugetlb returns whether the hugetlb controller is present on +// cgroup v1. +func cgroupv1HasHugetlb() (bool, error) { + _cgroupv1HasHugetlbOnce.Do(func() { + if _, err := ioutil.ReadDir("/sys/fs/cgroup/hugetlb"); err != nil { + _cgroupv1HasHugetlbErr = errors.Wrap(err, "readdir /sys/fs/cgroup/hugetlb") + _cgroupv1HasHugetlb = false + } else { + _cgroupv1HasHugetlbErr = nil + _cgroupv1HasHugetlb = true + } + }) + return _cgroupv1HasHugetlb, _cgroupv1HasHugetlbErr +} + +// cgroupv2HasHugetlb returns whether the hugetlb controller is present on +// cgroup v2. +func cgroupv2HasHugetlb() (bool, error) { + _cgroupv2HasHugetlbOnce.Do(func() { + controllers, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers") + if err != nil { + _cgroupv2HasHugetlbErr = errors.Wrap(err, "read /sys/fs/cgroup/cgroup.controllers") + return + } + _cgroupv2HasHugetlb = strings.Contains(string(controllers), "hugetlb") + }) + return _cgroupv2HasHugetlb, _cgroupv2HasHugetlbErr +} + +// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode. +func IsCgroup2UnifiedMode() bool { + isUnifiedOnce.Do(func() { + var st syscall.Statfs_t + if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil { + panic("cannot statfs cgroup root") + } + isUnified = st.Type == unix.CGROUP2_SUPER_MAGIC + }) + return isUnified +} + +// WithOOMScoreAdj sets the oom score +func WithOOMScoreAdj(config *runtime.ContainerConfig, restrict bool) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + + resources := config.GetLinux().GetResources() + if resources == nil { + return nil + } + adj := int(resources.GetOomScoreAdj()) + if restrict { + var err error + adj, err = restrictOOMScoreAdj(adj) + if err != nil { + return err + } + } + s.Process.OOMScoreAdj = &adj + return nil + } +} + +// WithSysctls sets the provided sysctls onto the spec +func WithSysctls(sysctls map[string]string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + if s.Linux.Sysctl == nil { + s.Linux.Sysctl = make(map[string]string) + } + for k, v := range sysctls { + s.Linux.Sysctl[k] = v + } + return nil + } +} + +// WithPodOOMScoreAdj sets the oom score for the pod sandbox +func WithPodOOMScoreAdj(adj int, restrict bool) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + if restrict { + var err error + adj, err = restrictOOMScoreAdj(adj) + if err != nil { + return err + } + } + s.Process.OOMScoreAdj = &adj + return nil + } +} + +// WithSupplementalGroups sets the supplemental groups for the process +func WithSupplementalGroups(groups []int64) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Process == nil { + s.Process = &runtimespec.Process{} + } + var guids []uint32 + for _, g := range groups { + guids = append(guids, uint32(g)) + } + s.Process.User.AdditionalGids = mergeGids(s.Process.User.AdditionalGids, guids) + return nil + } +} + +// WithPodNamespaces sets the pod namespaces for the container +func WithPodNamespaces(config *runtime.LinuxContainerSecurityContext, sandboxPid uint32, targetPid uint32) oci.SpecOpts { + namespaces := config.GetNamespaceOptions() + + opts := []oci.SpecOpts{ + oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.NetworkNamespace, Path: GetNetworkNamespace(sandboxPid)}), + oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.IPCNamespace, Path: GetIPCNamespace(sandboxPid)}), + oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.UTSNamespace, Path: GetUTSNamespace(sandboxPid)}), + } + if namespaces.GetPid() != runtime.NamespaceMode_CONTAINER { + opts = append(opts, oci.WithLinuxNamespace(runtimespec.LinuxNamespace{Type: runtimespec.PIDNamespace, Path: GetPIDNamespace(targetPid)})) + } + return oci.Compose(opts...) +} + +// WithDefaultSandboxShares sets the default sandbox CPU shares +func WithDefaultSandboxShares(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Linux == nil { + s.Linux = &runtimespec.Linux{} + } + if s.Linux.Resources == nil { + s.Linux.Resources = &runtimespec.LinuxResources{} + } + if s.Linux.Resources.CPU == nil { + s.Linux.Resources.CPU = &runtimespec.LinuxCPU{} + } + i := uint64(DefaultSandboxCPUshares) + s.Linux.Resources.CPU.Shares = &i + return nil +} + +// WithoutNamespace removes the provided namespace +func WithoutNamespace(t runtimespec.LinuxNamespaceType) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Linux == nil { + return nil + } + var namespaces []runtimespec.LinuxNamespace + for i, ns := range s.Linux.Namespaces { + if ns.Type != t { + namespaces = append(namespaces, s.Linux.Namespaces[i]) + } + } + s.Linux.Namespaces = namespaces + return nil + } +} + +func nullOpt(_ context.Context, _ oci.Client, _ *containers.Container, _ *runtimespec.Spec) error { + return 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 +} + +const ( + // netNSFormat is the format of network namespace of a process. + netNSFormat = "/proc/%v/ns/net" + // ipcNSFormat is the format of ipc namespace of a process. + ipcNSFormat = "/proc/%v/ns/ipc" + // utsNSFormat is the format of uts namespace of a process. + utsNSFormat = "/proc/%v/ns/uts" + // pidNSFormat is the format of pid namespace of a process. + pidNSFormat = "/proc/%v/ns/pid" +) + +// GetNetworkNamespace returns the network namespace of a process. +func GetNetworkNamespace(pid uint32) string { + return fmt.Sprintf(netNSFormat, pid) +} + +// GetIPCNamespace returns the ipc namespace of a process. +func GetIPCNamespace(pid uint32) string { + return fmt.Sprintf(ipcNSFormat, pid) +} + +// GetUTSNamespace returns the uts namespace of a process. +func GetUTSNamespace(pid uint32) string { + return fmt.Sprintf(utsNSFormat, pid) +} + +// GetPIDNamespace returns the pid namespace of a process. +func GetPIDNamespace(pid uint32) string { + return fmt.Sprintf(pidNSFormat, pid) +} diff -Nru containerd-1.2.6/pkg/cri/opts/spec_linux_test.go containerd-1.5.9/pkg/cri/opts/spec_linux_test.go --- containerd-1.2.6/pkg/cri/opts/spec_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/spec_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMergeGids(t *testing.T) { + gids1 := []uint32{3, 2, 1} + gids2 := []uint32{2, 3, 4} + assert.Equal(t, []uint32{1, 2, 3, 4}, mergeGids(gids1, gids2)) +} + +func TestRestrictOOMScoreAdj(t *testing.T) { + current, err := getCurrentOOMScoreAdj() + require.NoError(t, err) + + got, err := restrictOOMScoreAdj(current - 1) + require.NoError(t, err) + assert.Equal(t, got, current) + + got, err = restrictOOMScoreAdj(current) + require.NoError(t, err) + assert.Equal(t, got, current) + + got, err = restrictOOMScoreAdj(current + 1) + require.NoError(t, err) + assert.Equal(t, got, current+1) +} diff -Nru containerd-1.2.6/pkg/cri/opts/spec_test.go containerd-1.5.9/pkg/cri/opts/spec_test.go --- containerd-1.2.6/pkg/cri/opts/spec_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/spec_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestOrderedMounts(t *testing.T) { + mounts := []*runtime.Mount{ + {ContainerPath: "/a/b/c"}, + {ContainerPath: "/a/b"}, + {ContainerPath: "/a/b/c/d"}, + {ContainerPath: "/a"}, + {ContainerPath: "/b"}, + {ContainerPath: "/b/c"}, + } + expected := []*runtime.Mount{ + {ContainerPath: "/a"}, + {ContainerPath: "/b"}, + {ContainerPath: "/a/b"}, + {ContainerPath: "/b/c"}, + {ContainerPath: "/a/b/c"}, + {ContainerPath: "/a/b/c/d"}, + } + sort.Stable(orderedMounts(mounts)) + assert.Equal(t, expected, mounts) +} diff -Nru containerd-1.2.6/pkg/cri/opts/spec_windows.go containerd-1.5.9/pkg/cri/opts/spec_windows.go --- containerd-1.2.6/pkg/cri/opts/spec_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/spec_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,224 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + "path/filepath" + "sort" + "strings" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/oci" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + osinterface "github.com/containerd/containerd/pkg/os" +) + +// WithWindowsNetworkNamespace sets windows network namespace for container. +// TODO(windows): Move this into container/containerd. +func WithWindowsNetworkNamespace(path string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Windows == nil { + s.Windows = &runtimespec.Windows{} + } + if s.Windows.Network == nil { + s.Windows.Network = &runtimespec.WindowsNetwork{} + } + s.Windows.Network.NetworkNamespace = path + return nil + } +} + +// namedPipePath returns true if the given path is to a named pipe. +func namedPipePath(p string) bool { + return strings.HasPrefix(p, `\\.\pipe\`) +} + +// cleanMount returns a cleaned version of the mount path. The input is returned +// as-is if it is a named pipe path. +func cleanMount(p string) string { + if namedPipePath(p) { + return p + } + return filepath.Clean(p) +} + +// WithWindowsMounts sorts and adds runtime and CRI mounts to the spec for +// windows container. +func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*runtime.Mount) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, _ *containers.Container, s *runtimespec.Spec) error { + // mergeMounts merge CRI mounts with extra mounts. If a mount destination + // is mounted by both a CRI mount and an extra mount, the CRI mount will + // be kept. + var ( + criMounts = config.GetMounts() + mounts = append([]*runtime.Mount{}, criMounts...) + ) + // Copy all mounts from extra mounts, except for mounts overridden by CRI. + for _, e := range extra { + found := false + for _, c := range criMounts { + if cleanMount(e.ContainerPath) == cleanMount(c.ContainerPath) { + found = true + break + } + } + if !found { + mounts = append(mounts, e) + } + } + + // Sort mounts in number of parts. This ensures that high level mounts don't + // shadow other mounts. + sort.Sort(orderedMounts(mounts)) + + // Copy all mounts from default mounts, except for + // mounts overridden by supplied mount; + mountSet := make(map[string]struct{}) + for _, m := range mounts { + mountSet[cleanMount(m.ContainerPath)] = struct{}{} + } + + defaultMounts := s.Mounts + s.Mounts = nil + + for _, m := range defaultMounts { + dst := cleanMount(m.Destination) + if _, ok := mountSet[dst]; ok { + // filter out mount overridden by a supplied mount + continue + } + s.Mounts = append(s.Mounts, m) + } + + for _, mount := range mounts { + var ( + dst = mount.GetContainerPath() + src = mount.GetHostPath() + ) + // In the case of a named pipe mount on Windows, don't stat the file + // or do other operations that open it, as that could interfere with + // the listening process. filepath.Clean also breaks named pipe + // paths, so don't use it. + if !namedPipePath(src) { + if _, err := osi.Stat(src); err != nil { + // If the source doesn't exist, return an error instead + // of creating the source. This aligns with Docker's + // behavior on windows. + return errors.Wrapf(err, "failed to stat %q", src) + } + var err error + src, err = osi.ResolveSymbolicLink(src) + if err != nil { + return errors.Wrapf(err, "failed to resolve symlink %q", src) + } + // hcsshim requires clean path, especially '/' -> '\'. + src = filepath.Clean(src) + dst = filepath.Clean(dst) + } + + var options []string + // NOTE(random-liu): we don't change all mounts to `ro` when root filesystem + // is readonly. This is different from docker's behavior, but make more sense. + if mount.GetReadonly() { + options = append(options, "ro") + } else { + options = append(options, "rw") + } + s.Mounts = append(s.Mounts, runtimespec.Mount{ + Source: src, + Destination: dst, + Options: options, + }) + } + return nil + } +} + +// WithWindowsResources sets the provided resource restrictions for windows. +func WithWindowsResources(resources *runtime.WindowsContainerResources) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if resources == nil { + return nil + } + if s.Windows == nil { + s.Windows = &runtimespec.Windows{} + } + if s.Windows.Resources == nil { + s.Windows.Resources = &runtimespec.WindowsResources{} + } + if s.Windows.Resources.CPU == nil { + s.Windows.Resources.CPU = &runtimespec.WindowsCPUResources{} + } + if s.Windows.Resources.Memory == nil { + s.Windows.Resources.Memory = &runtimespec.WindowsMemoryResources{} + } + + var ( + count = uint64(resources.GetCpuCount()) + shares = uint16(resources.GetCpuShares()) + max = uint16(resources.GetCpuMaximum()) + limit = uint64(resources.GetMemoryLimitInBytes()) + ) + if count != 0 { + s.Windows.Resources.CPU.Count = &count + } + if shares != 0 { + s.Windows.Resources.CPU.Shares = &shares + } + if max != 0 { + s.Windows.Resources.CPU.Maximum = &max + } + if limit != 0 { + s.Windows.Resources.Memory.Limit = &limit + } + return nil + } +} + +// WithWindowsDefaultSandboxShares sets the default sandbox CPU shares +func WithWindowsDefaultSandboxShares(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Windows == nil { + s.Windows = &runtimespec.Windows{} + } + if s.Windows.Resources == nil { + s.Windows.Resources = &runtimespec.WindowsResources{} + } + if s.Windows.Resources.CPU == nil { + s.Windows.Resources.CPU = &runtimespec.WindowsCPUResources{} + } + i := uint16(DefaultSandboxCPUshares) + s.Windows.Resources.CPU.Shares = &i + return nil +} + +// WithWindowsCredentialSpec assigns `credentialSpec` to the +// `runtime.Spec.Windows.CredentialSpec` field. +func WithWindowsCredentialSpec(credentialSpec string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Windows == nil { + s.Windows = &runtimespec.Windows{} + } + s.Windows.CredentialSpec = credentialSpec + return nil + } +} diff -Nru containerd-1.2.6/pkg/cri/opts/task.go containerd-1.5.9/pkg/cri/opts/task.go --- containerd-1.2.6/pkg/cri/opts/task.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/opts/task.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/runtime/linux/runctypes" +) + +// WithContainerdShimCgroup returns function that sets the containerd +// shim cgroup path +func WithContainerdShimCgroup(path string) containerd.NewTaskOpts { + return func(_ context.Context, _ *containerd.Client, r *containerd.TaskInfo) error { + r.Options = &runctypes.CreateOptions{ + ShimCgroup: path, + } + return nil + } +} + +//TODO: Since Options is an interface different WithXXX will be needed to set different +// combinations of CreateOptions. diff -Nru containerd-1.2.6/pkg/cri/platforms/default_unix.go containerd-1.5.9/pkg/cri/platforms/default_unix.go --- containerd-1.2.6/pkg/cri/platforms/default_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/platforms/default_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package platforms + +import ( + "github.com/containerd/containerd/platforms" +) + +// Default returns the current platform's default platform specification. +func Default() platforms.MatchComparer { + return platforms.Default() +} diff -Nru containerd-1.2.6/pkg/cri/platforms/default_windows.go containerd-1.5.9/pkg/cri/platforms/default_windows.go --- containerd-1.2.6/pkg/cri/platforms/default_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/platforms/default_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package platforms + +import ( + "github.com/containerd/containerd/platforms" +) + +// Default returns the current platform's default platform specification. +func Default() platforms.MatchComparer { + return platforms.Default() +} diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/doc.go containerd-1.5.9/pkg/cri/server/bandwidth/doc.go --- containerd-1.2.6/pkg/cri/server/bandwidth/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package bandwidth provides utilities for bandwidth shaping +package bandwidth diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/fake_shaper.go containerd-1.5.9/pkg/cri/server/bandwidth/fake_shaper.go --- containerd-1.2.6/pkg/cri/server/bandwidth/fake_shaper.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/fake_shaper.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,72 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bandwidth + +import ( + "errors" + + "k8s.io/apimachinery/pkg/api/resource" +) + +// FakeShaper provides an implementation of the bandwidth.Shaper. +// Beware this is implementation has no features besides Reset and GetCIDRs. +type FakeShaper struct { + CIDRs []string + ResetCIDRs []string +} + +// Limit is not implemented +func (f *FakeShaper) Limit(cidr string, egress, ingress *resource.Quantity) error { + return errors.New("unimplemented") +} + +// Reset appends a particular CIDR to the set of ResetCIDRs being managed by this shaper +func (f *FakeShaper) Reset(cidr string) error { + f.ResetCIDRs = append(f.ResetCIDRs, cidr) + return nil +} + +// ReconcileInterface is not implemented +func (f *FakeShaper) ReconcileInterface() error { + return errors.New("unimplemented") +} + +// ReconcileCIDR is not implemented +func (f *FakeShaper) ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error { + return errors.New("unimplemented") +} + +// GetCIDRs returns the set of CIDRs that are being managed by this shaper +func (f *FakeShaper) GetCIDRs() ([]string, error) { + return f.CIDRs, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/interfaces.go containerd-1.5.9/pkg/cri/server/bandwidth/interfaces.go --- containerd-1.2.6/pkg/cri/server/bandwidth/interfaces.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/interfaces.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bandwidth + +import "k8s.io/apimachinery/pkg/api/resource" + +// Shaper is designed so that the shaper structs created +// satisfy the Shaper interface. +type Shaper interface { + // Limit the bandwidth for a particular CIDR on a particular interface + // * ingress and egress are in bits/second + // * cidr is expected to be a valid network CIDR (e.g. '1.2.3.4/32' or '10.20.0.1/16') + // 'egress' bandwidth limit applies to all packets on the interface whose source matches 'cidr' + // 'ingress' bandwidth limit applies to all packets on the interface whose destination matches 'cidr' + // Limits are aggregate limits for the CIDR, not per IP address. CIDRs must be unique, but can be overlapping, traffic + // that matches multiple CIDRs counts against all limits. + Limit(cidr string, egress, ingress *resource.Quantity) error + // Remove a bandwidth limit for a particular CIDR on a particular network interface + Reset(cidr string) error + // Reconcile the interface managed by this shaper with the state on the ground. + ReconcileInterface() error + // Reconcile a CIDR managed by this shaper with the state on the ground + ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error + // GetCIDRs returns the set of CIDRs that are being managed by this shaper + GetCIDRs() ([]string, error) +} diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/linux.go containerd-1.5.9/pkg/cri/server/bandwidth/linux.go --- containerd-1.2.6/pkg/cri/server/bandwidth/linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,361 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bandwidth + +import ( + "bufio" + "bytes" + "encoding/hex" + "fmt" + "net" + "regexp" + "strings" + + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/utils/exec" + + "k8s.io/klog/v2" +) + +var ( + classShowMatcher = regexp.MustCompile(`class htb (1:\d+)`) + classAndHandleMatcher = regexp.MustCompile(`filter parent 1:.*fh (\d+::\d+).*flowid (\d+:\d+)`) +) + +// tcShaper provides an implementation of the Shaper interface on Linux using the 'tc' tool. +// In general, using this requires that the caller posses the NET_CAP_ADMIN capability, though if you +// do this within an container, it only requires the NS_CAPABLE capability for manipulations to that +// container's network namespace. +// Uses the hierarchical token bucket queuing discipline (htb), this requires Linux 2.4.20 or newer +// or a custom kernel with that queuing discipline backported. +type tcShaper struct { + e exec.Interface + iface string +} + +// NewTCShaper makes a new tcShaper for the given interface +func NewTCShaper(iface string) Shaper { + shaper := &tcShaper{ + e: exec.New(), + iface: iface, + } + return shaper +} + +func (t *tcShaper) execAndLog(cmdStr string, args ...string) error { + klog.V(6).Infof("Running: %s %s", cmdStr, strings.Join(args, " ")) + cmd := t.e.Command(cmdStr, args...) + out, err := cmd.CombinedOutput() + klog.V(6).Infof("Output from tc: %s", string(out)) + return err +} + +func (t *tcShaper) nextClassID() (int, error) { + data, err := t.e.Command("tc", "class", "show", "dev", t.iface).CombinedOutput() + if err != nil { + return -1, err + } + + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + classes := sets.String{} + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + // skip empty lines + if len(line) == 0 { + continue + } + // expected tc line: + // class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b + matches := classShowMatcher.FindStringSubmatch(line) + if len(matches) != 2 { + return -1, fmt.Errorf("unexpected output from tc: %s (%v)", scanner.Text(), matches) + } + classes.Insert(matches[1]) + } + + // Make sure it doesn't go forever + for nextClass := 1; nextClass < 10000; nextClass++ { + if !classes.Has(fmt.Sprintf("1:%d", nextClass)) { + return nextClass, nil + } + } + // This should really never happen + return -1, fmt.Errorf("exhausted class space, please try again") +} + +// Convert a CIDR from text to a hex representation +// Strips any masked parts of the IP, so 1.2.3.4/16 becomes hex(1.2.0.0)/ffffffff +func hexCIDR(cidr string) (string, error) { + ip, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return "", err + } + ip = ip.Mask(ipnet.Mask) + hexIP := hex.EncodeToString([]byte(ip)) + hexMask := ipnet.Mask.String() + return hexIP + "/" + hexMask, nil +} + +// Convert a CIDR from hex representation to text, opposite of the above. +func asciiCIDR(cidr string) (string, error) { + parts := strings.Split(cidr, "/") + if len(parts) != 2 { + return "", fmt.Errorf("unexpected CIDR format: %s", cidr) + } + ipData, err := hex.DecodeString(parts[0]) + if err != nil { + return "", err + } + ip := net.IP(ipData) + + maskData, err := hex.DecodeString(parts[1]) + if err != nil { + return "", err + } + mask := net.IPMask(maskData) + size, _ := mask.Size() + + return fmt.Sprintf("%s/%d", ip.String(), size), nil +} + +func (t *tcShaper) findCIDRClass(cidr string) (classAndHandleList [][]string, found bool, err error) { + data, err := t.e.Command("tc", "filter", "show", "dev", t.iface).CombinedOutput() + if err != nil { + return classAndHandleList, false, err + } + + hex, err := hexCIDR(cidr) + if err != nil { + return classAndHandleList, false, err + } + spec := fmt.Sprintf("match %s", hex) + + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + filter := "" + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if len(line) == 0 { + continue + } + if strings.HasPrefix(line, "filter") { + filter = line + continue + } + if strings.Contains(line, spec) { + // expected tc line: + // `filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1` (old version) or + // `filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw` (new version) + matches := classAndHandleMatcher.FindStringSubmatch(filter) + if len(matches) != 3 { + return classAndHandleList, false, fmt.Errorf("unexpected output from tc: %s %d (%v)", filter, len(matches), matches) + } + resultTmp := []string{matches[2], matches[1]} + classAndHandleList = append(classAndHandleList, resultTmp) + } + } + if len(classAndHandleList) > 0 { + return classAndHandleList, true, nil + } + return classAndHandleList, false, nil +} + +func makeKBitString(rsrc *resource.Quantity) string { + return fmt.Sprintf("%dkbit", (rsrc.Value() / 1000)) +} + +func (t *tcShaper) makeNewClass(rate string) (int, error) { + class, err := t.nextClassID() + if err != nil { + return -1, err + } + if err := t.execAndLog("tc", "class", "add", + "dev", t.iface, + "parent", "1:", + "classid", fmt.Sprintf("1:%d", class), + "htb", "rate", rate); err != nil { + return -1, err + } + return class, nil +} + +func (t *tcShaper) Limit(cidr string, upload, download *resource.Quantity) (err error) { + var downloadClass, uploadClass int + if download != nil { + if downloadClass, err = t.makeNewClass(makeKBitString(download)); err != nil { + return err + } + if err := t.execAndLog("tc", "filter", "add", + "dev", t.iface, + "protocol", "ip", + "parent", "1:0", + "prio", "1", "u32", + "match", "ip", "dst", cidr, + "flowid", fmt.Sprintf("1:%d", downloadClass)); err != nil { + return err + } + } + if upload != nil { + if uploadClass, err = t.makeNewClass(makeKBitString(upload)); err != nil { + return err + } + if err := t.execAndLog("tc", "filter", "add", + "dev", t.iface, + "protocol", "ip", + "parent", "1:0", + "prio", "1", "u32", + "match", "ip", "src", cidr, + "flowid", fmt.Sprintf("1:%d", uploadClass)); err != nil { + return err + } + } + return nil +} + +// tests to see if an interface exists, if it does, return true and the status line for the interface +// returns false, "", if an error occurs. +func (t *tcShaper) interfaceExists() (bool, string, error) { + data, err := t.e.Command("tc", "qdisc", "show", "dev", t.iface).CombinedOutput() + if err != nil { + return false, "", err + } + value := strings.TrimSpace(string(data)) + if len(value) == 0 { + return false, "", nil + } + // Newer versions of tc and/or the kernel return the following instead of nothing: + // qdisc noqueue 0: root refcnt 2 + fields := strings.Fields(value) + if len(fields) > 1 && fields[1] == "noqueue" { + return false, "", nil + } + return true, value, nil +} + +func (t *tcShaper) ReconcileCIDR(cidr string, upload, download *resource.Quantity) error { + _, found, err := t.findCIDRClass(cidr) + if err != nil { + return err + } + if !found { + return t.Limit(cidr, upload, download) + } + // TODO: actually check bandwidth limits here + return nil +} + +func (t *tcShaper) ReconcileInterface() error { + exists, output, err := t.interfaceExists() + if err != nil { + return err + } + if !exists { + klog.V(4).Info("Didn't find bandwidth interface, creating") + return t.initializeInterface() + } + fields := strings.Split(output, " ") + if len(fields) < 12 || fields[1] != "htb" || fields[2] != "1:" { + if err := t.deleteInterface(fields[2]); err != nil { + return err + } + return t.initializeInterface() + } + return nil +} + +func (t *tcShaper) initializeInterface() error { + return t.execAndLog("tc", "qdisc", "add", "dev", t.iface, "root", "handle", "1:", "htb", "default", "30") +} + +func (t *tcShaper) Reset(cidr string) error { + classAndHandle, found, err := t.findCIDRClass(cidr) + if err != nil { + return err + } + if !found { + return fmt.Errorf("Failed to find cidr: %s on interface: %s", cidr, t.iface) + } + for i := 0; i < len(classAndHandle); i++ { + if err := t.execAndLog("tc", "filter", "del", + "dev", t.iface, + "parent", "1:", + "proto", "ip", + "prio", "1", + "handle", classAndHandle[i][1], "u32"); err != nil { + return err + } + if err := t.execAndLog("tc", "class", "del", + "dev", t.iface, + "parent", "1:", + "classid", classAndHandle[i][0]); err != nil { + return err + } + } + return nil +} + +func (t *tcShaper) deleteInterface(class string) error { + return t.execAndLog("tc", "qdisc", "delete", "dev", t.iface, "root", "handle", class) +} + +func (t *tcShaper) GetCIDRs() ([]string, error) { + data, err := t.e.Command("tc", "filter", "show", "dev", t.iface).CombinedOutput() + if err != nil { + return nil, err + } + + result := []string{} + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if len(line) == 0 { + continue + } + if strings.Contains(line, "match") { + parts := strings.Split(line, " ") + // expected tc line: + // match at + if len(parts) != 4 { + return nil, fmt.Errorf("unexpected output: %v", parts) + } + cidr, err := asciiCIDR(parts[1]) + if err != nil { + return nil, err + } + result = append(result, cidr) + } + } + return result, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/unsupported.go containerd-1.5.9/pkg/cri/server/bandwidth/unsupported.go --- containerd-1.2.6/pkg/cri/server/bandwidth/unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,69 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bandwidth + +import ( + "errors" + + "k8s.io/apimachinery/pkg/api/resource" +) + +type unsupportedShaper struct { +} + +// NewTCShaper makes a new unsupportedShapper for the given interface +func NewTCShaper(iface string) Shaper { + return &unsupportedShaper{} +} + +func (f *unsupportedShaper) Limit(cidr string, egress, ingress *resource.Quantity) error { + return errors.New("unimplemented") +} + +func (f *unsupportedShaper) Reset(cidr string) error { + return nil +} + +func (f *unsupportedShaper) ReconcileInterface() error { + return errors.New("unimplemented") +} + +func (f *unsupportedShaper) ReconcileCIDR(cidr string, egress, ingress *resource.Quantity) error { + return errors.New("unimplemented") +} + +func (f *unsupportedShaper) GetCIDRs() ([]string, error) { + return []string{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/bandwidth/utils.go containerd-1.5.9/pkg/cri/server/bandwidth/utils.go --- containerd-1.2.6/pkg/cri/server/bandwidth/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/bandwidth/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,82 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bandwidth + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/resource" +) + +var minRsrc = resource.MustParse("1k") +var maxRsrc = resource.MustParse("1P") + +func validateBandwidthIsReasonable(rsrc *resource.Quantity) error { + if rsrc.Value() < minRsrc.Value() { + return fmt.Errorf("resource is unreasonably small (< 1kbit)") + } + if rsrc.Value() > maxRsrc.Value() { + return fmt.Errorf("resource is unreasonably large (> 1Pbit)") + } + return nil +} + +// ExtractPodBandwidthResources extracts the ingress and egress from the given pod annotations +func ExtractPodBandwidthResources(podAnnotations map[string]string) (ingress, egress *resource.Quantity, err error) { + if podAnnotations == nil { + return nil, nil, nil + } + str, found := podAnnotations["kubernetes.io/ingress-bandwidth"] + if found { + ingressValue, err := resource.ParseQuantity(str) + if err != nil { + return nil, nil, err + } + ingress = &ingressValue + if err := validateBandwidthIsReasonable(ingress); err != nil { + return nil, nil, err + } + } + str, found = podAnnotations["kubernetes.io/egress-bandwidth"] + if found { + egressValue, err := resource.ParseQuantity(str) + if err != nil { + return nil, nil, err + } + egress = &egressValue + if err := validateBandwidthIsReasonable(egress); err != nil { + return nil, nil, err + } + } + return ingress, egress, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/cni_conf_syncer.go containerd-1.5.9/pkg/cri/server/cni_conf_syncer.go --- containerd-1.2.6/pkg/cri/server/cni_conf_syncer.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/cni_conf_syncer.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "os" + "sync" + + cni "github.com/containerd/go-cni" + "github.com/fsnotify/fsnotify" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// cniNetConfSyncer is used to reload cni network conf triggered by fs change +// events. +type cniNetConfSyncer struct { + // only used for lastSyncStatus + sync.RWMutex + lastSyncStatus error + + watcher *fsnotify.Watcher + confDir string + netPlugin cni.CNI + loadOpts []cni.Opt +} + +// newCNINetConfSyncer creates cni network conf syncer. +func newCNINetConfSyncer(confDir string, netPlugin cni.CNI, loadOpts []cni.Opt) (*cniNetConfSyncer, error) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return nil, errors.Wrap(err, "failed to create fsnotify watcher") + } + + if err := os.MkdirAll(confDir, 0700); err != nil { + return nil, errors.Wrapf(err, "failed to create cni conf dir=%s for watch", confDir) + } + + if err := watcher.Add(confDir); err != nil { + return nil, errors.Wrapf(err, "failed to watch cni conf dir %s", confDir) + } + + syncer := &cniNetConfSyncer{ + watcher: watcher, + confDir: confDir, + netPlugin: netPlugin, + loadOpts: loadOpts, + } + + if err := syncer.netPlugin.Load(syncer.loadOpts...); err != nil { + logrus.WithError(err).Error("failed to load cni during init, please check CRI plugin status before setting up network for pods") + syncer.updateLastStatus(err) + } + return syncer, nil +} + +// syncLoop monitors any fs change events from cni conf dir and tries to reload +// cni configuration. +func (syncer *cniNetConfSyncer) syncLoop() error { + for { + select { + case event, ok := <-syncer.watcher.Events: + if !ok { + logrus.Debugf("cni watcher channel is closed") + return nil + } + // Only reload config when receiving write/rename/remove + // events + // + // TODO(fuweid): Might only reload target cni config + // files to prevent no-ops. + if event.Op&(fsnotify.Chmod|fsnotify.Create) > 0 { + logrus.Debugf("ignore event from cni conf dir: %s", event) + continue + } + logrus.Debugf("receiving change event from cni conf dir: %s", event) + + lerr := syncer.netPlugin.Load(syncer.loadOpts...) + if lerr != nil { + logrus.WithError(lerr). + Errorf("failed to reload cni configuration after receiving fs change event(%s)", event) + } + syncer.updateLastStatus(lerr) + + case err := <-syncer.watcher.Errors: + if err != nil { + logrus.WithError(err).Error("failed to continue sync cni conf change") + return err + } + } + } +} + +// lastStatus retrieves last sync status. +func (syncer *cniNetConfSyncer) lastStatus() error { + syncer.RLock() + defer syncer.RUnlock() + return syncer.lastSyncStatus +} + +// updateLastStatus will be called after every single cni load. +func (syncer *cniNetConfSyncer) updateLastStatus(err error) { + syncer.Lock() + defer syncer.Unlock() + syncer.lastSyncStatus = err +} + +// stop stops watcher in the syncLoop. +func (syncer *cniNetConfSyncer) stop() error { + return syncer.watcher.Close() +} diff -Nru containerd-1.2.6/pkg/cri/server/container_attach.go containerd-1.5.9/pkg/cri/server/container_attach.go --- containerd-1.2.6/pkg/cri/server/container_attach.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_attach.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "golang.org/x/net/context" + "k8s.io/client-go/tools/remotecommand" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" +) + +// Attach prepares a streaming endpoint to attach to a running container, and returns the address. +func (c *criService) Attach(ctx context.Context, r *runtime.AttachRequest) (*runtime.AttachResponse, error) { + cntr, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrap(err, "failed to find container in store") + } + state := cntr.Status.Get().State() + if state != runtime.ContainerState_CONTAINER_RUNNING { + return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) + } + return c.streamServer.GetAttach(r) +} + +func (c *criService) attachContainer(ctx context.Context, id string, stdin io.Reader, stdout, stderr io.WriteCloser, + tty bool, resize <-chan remotecommand.TerminalSize) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + // Get container from our container store. + cntr, err := c.containerStore.Get(id) + if err != nil { + return errors.Wrapf(err, "failed to find container %q in store", id) + } + id = cntr.ID + + state := cntr.Status.Get().State() + if state != runtime.ContainerState_CONTAINER_RUNNING { + return errors.Errorf("container is in %s state", criContainerStateToString(state)) + } + + task, err := cntr.Container.Task(ctx, nil) + if err != nil { + return errors.Wrap(err, "failed to load task") + } + handleResizing(ctx, resize, func(size remotecommand.TerminalSize) { + if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to resize task %q console", id) + } + }) + + opts := cio.AttachOptions{ + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + Tty: tty, + StdinOnce: cntr.Config.StdinOnce, + CloseStdin: func() error { + return task.CloseIO(ctx, containerd.WithStdinCloser) + }, + } + // TODO(random-liu): Figure out whether we need to support historical output. + cntr.IO.Attach(opts) + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create.go containerd-1.5.9/pkg/cri/server/container_create.go --- containerd-1.2.6/pkg/cri/server/container_create.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,345 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "path/filepath" + "time" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/snapshots" + "github.com/containerd/typeurl" + "github.com/davecgh/go-spew/spew" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + selinux "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + customopts "github.com/containerd/containerd/pkg/cri/opts" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + "github.com/containerd/containerd/pkg/cri/util" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +func init() { + typeurl.Register(&containerstore.Metadata{}, + "github.com/containerd/cri/pkg/store/container", "Metadata") +} + +// CreateContainer creates a new container in the given PodSandbox. +func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateContainerRequest) (_ *runtime.CreateContainerResponse, retErr error) { + config := r.GetConfig() + log.G(ctx).Debugf("Container config %+v", config) + sandboxConfig := r.GetSandboxConfig() + sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) + if err != nil { + return nil, errors.Wrapf(err, "failed to find sandbox id %q", r.GetPodSandboxId()) + } + sandboxID := sandbox.ID + s, err := sandbox.Container.Task(ctx, nil) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox container task") + } + sandboxPid := s.Pid() + + // Generate unique id and name for the container and reserve the name. + // Reserve the container name to avoid concurrent `CreateContainer` request creating + // the same container. + id := util.GenerateID() + metadata := config.GetMetadata() + if metadata == nil { + return nil, errors.New("container config must include metadata") + } + containerName := metadata.Name + name := makeContainerName(metadata, sandboxConfig.GetMetadata()) + log.G(ctx).Debugf("Generated id %q for container %q", id, name) + if err = c.containerNameIndex.Reserve(name, id); err != nil { + return nil, errors.Wrapf(err, "failed to reserve container name %q", name) + } + defer func() { + // Release the name if the function returns with an error. + if retErr != nil { + c.containerNameIndex.ReleaseByName(name) + } + }() + + // Create initial internal container metadata. + meta := containerstore.Metadata{ + ID: id, + Name: name, + SandboxID: sandboxID, + Config: config, + } + + // Prepare container image snapshot. For container, the image should have + // been pulled before creating the container, so do not ensure the image. + image, err := c.localResolve(config.GetImage().GetImage()) + if err != nil { + return nil, errors.Wrapf(err, "failed to resolve image %q", config.GetImage().GetImage()) + } + containerdImage, err := c.toContainerdImage(ctx, image) + if err != nil { + return nil, errors.Wrapf(err, "failed to get image from containerd %q", image.ID) + } + + // Run container using the same runtime with sandbox. + sandboxInfo, err := sandbox.Container.Info(ctx) + if err != nil { + return nil, errors.Wrapf(err, "failed to get sandbox %q info", sandboxID) + } + + // Create container root directory. + containerRootDir := c.getContainerRootDir(id) + if err = c.os.MkdirAll(containerRootDir, 0755); err != nil { + return nil, errors.Wrapf(err, "failed to create container root directory %q", + containerRootDir) + } + defer func() { + if retErr != nil { + // Cleanup the container root directory. + if err = c.os.RemoveAll(containerRootDir); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to remove container root directory %q", + containerRootDir) + } + } + }() + volatileContainerRootDir := c.getVolatileContainerRootDir(id) + if err = c.os.MkdirAll(volatileContainerRootDir, 0755); err != nil { + return nil, errors.Wrapf(err, "failed to create volatile container root directory %q", + volatileContainerRootDir) + } + defer func() { + if retErr != nil { + // Cleanup the volatile container root directory. + if err = c.os.RemoveAll(volatileContainerRootDir); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to remove volatile container root directory %q", + volatileContainerRootDir) + } + } + }() + + var volumeMounts []*runtime.Mount + if !c.config.IgnoreImageDefinedVolumes { + // Create container image volumes mounts. + volumeMounts = c.volumeMounts(containerRootDir, config.GetMounts(), &image.ImageSpec.Config) + } else if len(image.ImageSpec.Config.Volumes) != 0 { + log.G(ctx).Debugf("Ignoring volumes defined in image %v because IgnoreImageDefinedVolumes is set", image.ID) + } + + // Generate container mounts. + mounts := c.containerMounts(sandboxID, config) + + ociRuntime, err := c.getSandboxRuntime(sandboxConfig, sandbox.Metadata.RuntimeHandler) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox runtime") + } + log.G(ctx).Debugf("Use OCI runtime %+v for sandbox %q and container %q", ociRuntime, sandboxID, id) + + spec, err := c.containerSpec(id, sandboxID, sandboxPid, sandbox.NetNSPath, containerName, containerdImage.Name(), config, sandboxConfig, + &image.ImageSpec.Config, append(mounts, volumeMounts...), ociRuntime) + if err != nil { + return nil, errors.Wrapf(err, "failed to generate container %q spec", id) + } + + meta.ProcessLabel = spec.Process.SelinuxLabel + + // handle any KVM based runtime + if err := modifyProcessLabel(ociRuntime.Type, spec); err != nil { + return nil, err + } + + if config.GetLinux().GetSecurityContext().GetPrivileged() { + // If privileged don't set the SELinux label but still record it on the container so + // the unused MCS label can be release later + spec.Process.SelinuxLabel = "" + } + defer func() { + if retErr != nil { + selinux.ReleaseLabel(spec.Process.SelinuxLabel) + } + }() + + log.G(ctx).Debugf("Container %q spec: %#+v", id, spew.NewFormatter(spec)) + + snapshotterOpt := snapshots.WithLabels(snapshots.FilterInheritedLabels(config.Annotations)) + // Set snapshotter before any other options. + opts := []containerd.NewContainerOpts{ + containerd.WithSnapshotter(c.config.ContainerdConfig.Snapshotter), + // Prepare container rootfs. This is always writeable even if + // the container wants a readonly rootfs since we want to give + // the runtime (runc) a chance to modify (e.g. to create mount + // points corresponding to spec.Mounts) before making the + // rootfs readonly (requested by spec.Root.Readonly). + customopts.WithNewSnapshot(id, containerdImage, snapshotterOpt), + } + if len(volumeMounts) > 0 { + mountMap := make(map[string]string) + for _, v := range volumeMounts { + mountMap[filepath.Clean(v.HostPath)] = v.ContainerPath + } + opts = append(opts, customopts.WithVolumes(mountMap)) + } + meta.ImageRef = image.ID + meta.StopSignal = image.ImageSpec.Config.StopSignal + + // Validate log paths and compose full container log path. + if sandboxConfig.GetLogDirectory() != "" && config.GetLogPath() != "" { + meta.LogPath = filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath()) + log.G(ctx).Debugf("Composed container full log path %q using sandbox log dir %q and container log path %q", + meta.LogPath, sandboxConfig.GetLogDirectory(), config.GetLogPath()) + } else { + log.G(ctx).Infof("Logging will be disabled due to empty log paths for sandbox (%q) or container (%q)", + sandboxConfig.GetLogDirectory(), config.GetLogPath()) + } + + containerIO, err := cio.NewContainerIO(id, + cio.WithNewFIFOs(volatileContainerRootDir, config.GetTty(), config.GetStdin())) + if err != nil { + return nil, errors.Wrap(err, "failed to create container io") + } + defer func() { + if retErr != nil { + if err := containerIO.Close(); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to close container io %q", id) + } + } + }() + + specOpts, err := c.containerSpecOpts(config, &image.ImageSpec.Config) + if err != nil { + return nil, errors.Wrap(err, "failed to get container spec opts") + } + + containerLabels := buildLabels(config.Labels, image.ImageSpec.Config.Labels, containerKindContainer) + + runtimeOptions, err := getRuntimeOptions(sandboxInfo) + if err != nil { + return nil, errors.Wrap(err, "failed to get runtime options") + } + opts = append(opts, + containerd.WithSpec(spec, specOpts...), + containerd.WithRuntime(sandboxInfo.Runtime.Name, runtimeOptions), + containerd.WithContainerLabels(containerLabels), + containerd.WithContainerExtension(containerMetadataExtension, &meta)) + var cntr containerd.Container + if cntr, err = c.client.NewContainer(ctx, id, opts...); err != nil { + return nil, errors.Wrap(err, "failed to create containerd container") + } + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + if err := cntr.Delete(deferCtx, containerd.WithSnapshotCleanup); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to delete containerd container %q", id) + } + } + }() + + status := containerstore.Status{CreatedAt: time.Now().UnixNano()} + container, err := containerstore.NewContainer(meta, + containerstore.WithStatus(status, containerRootDir), + containerstore.WithContainer(cntr), + containerstore.WithContainerIO(containerIO), + ) + if err != nil { + return nil, errors.Wrapf(err, "failed to create internal container object for %q", id) + } + defer func() { + if retErr != nil { + // Cleanup container checkpoint on error. + if err := container.Delete(); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to cleanup container checkpoint for %q", id) + } + } + }() + + // Add container into container store. + if err := c.containerStore.Add(container); err != nil { + return nil, errors.Wrapf(err, "failed to add container %q into store", id) + } + + return &runtime.CreateContainerResponse{ContainerId: id}, nil +} + +// volumeMounts sets up image volumes for container. Rely on the removal of container +// root directory to do cleanup. Note that image volume will be skipped, if there is criMounts +// specified with the same destination. +func (c *criService) volumeMounts(containerRootDir string, criMounts []*runtime.Mount, config *imagespec.ImageConfig) []*runtime.Mount { + if len(config.Volumes) == 0 { + return nil + } + var mounts []*runtime.Mount + for dst := range config.Volumes { + if isInCRIMounts(dst, criMounts) { + // Skip the image volume, if there is CRI defined volume mapping. + // TODO(random-liu): This should be handled by Kubelet in the future. + // Kubelet should decide what to use for image volume, and also de-duplicate + // the image volume and user mounts. + continue + } + volumeID := util.GenerateID() + src := filepath.Join(containerRootDir, "volumes", volumeID) + // addOCIBindMounts will create these volumes. + mounts = append(mounts, &runtime.Mount{ + ContainerPath: dst, + HostPath: src, + SelinuxRelabel: true, + }) + } + return mounts +} + +// runtimeSpec returns a default runtime spec used in cri-containerd. +func (c *criService) runtimeSpec(id string, baseSpecFile string, opts ...oci.SpecOpts) (*runtimespec.Spec, error) { + // GenerateSpec needs namespace. + ctx := ctrdutil.NamespacedContext() + container := &containers.Container{ID: id} + + if baseSpecFile != "" { + baseSpec, ok := c.baseOCISpecs[baseSpecFile] + if !ok { + return nil, errors.Errorf("can't find base OCI spec %q", baseSpecFile) + } + + spec := oci.Spec{} + if err := util.DeepCopy(&spec, &baseSpec); err != nil { + return nil, errors.Wrap(err, "failed to clone OCI spec") + } + + // Fix up cgroups path + applyOpts := append([]oci.SpecOpts{oci.WithNamespacedCgroup()}, opts...) + + if err := oci.ApplyOpts(ctx, nil, container, &spec, applyOpts...); err != nil { + return nil, errors.Wrap(err, "failed to apply OCI options") + } + + return &spec, nil + } + + spec, err := oci.GenerateSpec(ctx, nil, container, opts...) + if err != nil { + return nil, errors.Wrap(err, "failed to generate spec") + } + + return spec, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_linux.go containerd-1.5.9/pkg/cri/server/container_create_linux.go --- containerd-1.2.6/pkg/cri/server/container_create_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,570 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "bufio" + "io" + "os" + "strconv" + "strings" + + "github.com/containerd/cgroups" + "github.com/containerd/containerd/contrib/apparmor" + "github.com/containerd/containerd/contrib/seccomp" + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + selinux "github.com/opencontainers/selinux/go-selinux" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/config" + customopts "github.com/containerd/containerd/pkg/cri/opts" +) + +const ( + // profileNamePrefix is the prefix for loading profiles on a localhost. Eg. AppArmor localhost/profileName. + profileNamePrefix = "localhost/" // TODO (mikebrow): get localhost/ & runtime/default from CRI kubernetes/kubernetes#51747 + // runtimeDefault indicates that we should use or create a runtime default profile. + runtimeDefault = "runtime/default" + // dockerDefault indicates that we should use or create a docker default profile. + dockerDefault = "docker/default" + // appArmorDefaultProfileName is name to use when creating a default apparmor profile. + appArmorDefaultProfileName = "cri-containerd.apparmor.d" + // unconfinedProfile is a string indicating one should run a pod/containerd without a security profile + unconfinedProfile = "unconfined" + // seccompDefaultProfile is the default seccomp profile. + seccompDefaultProfile = dockerDefault +) + +// containerMounts sets up necessary container system file mounts +// including /dev/shm, /etc/hosts and /etc/resolv.conf. +func (c *criService) containerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount { + var mounts []*runtime.Mount + securityContext := config.GetLinux().GetSecurityContext() + if !isInCRIMounts(etcHostname, config.GetMounts()) { + // /etc/hostname is added since 1.1.6, 1.2.4 and 1.3. + // For in-place upgrade, the old sandbox doesn't have the hostname file, + // do not mount this in that case. + // TODO(random-liu): Remove the check and always mount this when + // containerd 1.1 and 1.2 are deprecated. + hostpath := c.getSandboxHostname(sandboxID) + if _, err := c.os.Stat(hostpath); err == nil { + mounts = append(mounts, &runtime.Mount{ + ContainerPath: etcHostname, + HostPath: hostpath, + Readonly: securityContext.GetReadonlyRootfs(), + SelinuxRelabel: true, + }) + } + } + + if !isInCRIMounts(etcHosts, config.GetMounts()) { + mounts = append(mounts, &runtime.Mount{ + ContainerPath: etcHosts, + HostPath: c.getSandboxHosts(sandboxID), + Readonly: securityContext.GetReadonlyRootfs(), + SelinuxRelabel: true, + }) + } + + // Mount sandbox resolv.config. + // TODO: Need to figure out whether we should always mount it as read-only + if !isInCRIMounts(resolvConfPath, config.GetMounts()) { + mounts = append(mounts, &runtime.Mount{ + ContainerPath: resolvConfPath, + HostPath: c.getResolvPath(sandboxID), + Readonly: securityContext.GetReadonlyRootfs(), + SelinuxRelabel: true, + }) + } + + if !isInCRIMounts(devShm, config.GetMounts()) { + sandboxDevShm := c.getSandboxDevShm(sandboxID) + if securityContext.GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE { + sandboxDevShm = devShm + } + mounts = append(mounts, &runtime.Mount{ + ContainerPath: devShm, + HostPath: sandboxDevShm, + Readonly: false, + SelinuxRelabel: sandboxDevShm != devShm, + }) + } + return mounts +} + +func (c *criService) containerSpec( + id string, + sandboxID string, + sandboxPid uint32, + netNSPath string, + containerName string, + imageName string, + config *runtime.ContainerConfig, + sandboxConfig *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, + extraMounts []*runtime.Mount, + ociRuntime config.Runtime, +) (_ *runtimespec.Spec, retErr error) { + specOpts := []oci.SpecOpts{ + oci.WithoutRunMount, + } + // only clear the default security settings if the runtime does not have a custom + // base runtime spec spec. Admins can use this functionality to define + // default ulimits, seccomp, or other default settings. + if ociRuntime.BaseRuntimeSpec == "" { + specOpts = append(specOpts, customopts.WithoutDefaultSecuritySettings) + } + specOpts = append(specOpts, + customopts.WithRelativeRoot(relativeRootfsPath), + customopts.WithProcessArgs(config, imageConfig), + oci.WithDefaultPathEnv, + // this will be set based on the security context below + oci.WithNewPrivileges, + ) + if config.GetWorkingDir() != "" { + specOpts = append(specOpts, oci.WithProcessCwd(config.GetWorkingDir())) + } else if imageConfig.WorkingDir != "" { + specOpts = append(specOpts, oci.WithProcessCwd(imageConfig.WorkingDir)) + } + + if config.GetTty() { + specOpts = append(specOpts, oci.WithTTY) + } + + // Add HOSTNAME env. + var ( + err error + hostname = sandboxConfig.GetHostname() + ) + if hostname == "" { + if hostname, err = c.os.Hostname(); err != nil { + return nil, err + } + } + specOpts = append(specOpts, oci.WithEnv([]string{hostnameEnv + "=" + hostname})) + + // Apply envs from image config first, so that envs from container config + // can override them. + env := append([]string{}, imageConfig.Env...) + for _, e := range config.GetEnvs() { + env = append(env, e.GetKey()+"="+e.GetValue()) + } + specOpts = append(specOpts, oci.WithEnv(env)) + + securityContext := config.GetLinux().GetSecurityContext() + labelOptions, err := toLabel(securityContext.GetSelinuxOptions()) + if err != nil { + return nil, err + } + if len(labelOptions) == 0 { + // Use pod level SELinux config + if sandbox, err := c.sandboxStore.Get(sandboxID); err == nil { + labelOptions, err = selinux.DupSecOpt(sandbox.ProcessLabel) + if err != nil { + return nil, err + } + } + } + + processLabel, mountLabel, err := label.InitLabels(labelOptions) + if err != nil { + return nil, errors.Wrapf(err, "failed to init selinux options %+v", securityContext.GetSelinuxOptions()) + } + defer func() { + if retErr != nil { + _ = label.ReleaseLabel(processLabel) + } + }() + + specOpts = append(specOpts, customopts.WithMounts(c.os, config, extraMounts, mountLabel)) + + if !c.config.DisableProcMount { + // Change the default masked/readonly paths to empty slices + // See https://github.com/containerd/containerd/issues/5029 + // TODO: Provide an option to set default paths to the ones in oci.populateDefaultUnixSpec() + specOpts = append(specOpts, oci.WithMaskedPaths([]string{}), oci.WithReadonlyPaths([]string{})) + + // Apply masked paths if specified. + // If the container is privileged, this will be cleared later on. + if maskedPaths := securityContext.GetMaskedPaths(); maskedPaths != nil { + specOpts = append(specOpts, oci.WithMaskedPaths(maskedPaths)) + } + + // Apply readonly paths if specified. + // If the container is privileged, this will be cleared later on. + if readonlyPaths := securityContext.GetReadonlyPaths(); readonlyPaths != nil { + specOpts = append(specOpts, oci.WithReadonlyPaths(readonlyPaths)) + } + } + + specOpts = append(specOpts, customopts.WithDevices(c.os, config), + customopts.WithCapabilities(securityContext, c.allCaps)) + + if securityContext.GetPrivileged() { + if !sandboxConfig.GetLinux().GetSecurityContext().GetPrivileged() { + return nil, errors.New("no privileged container allowed in sandbox") + } + specOpts = append(specOpts, oci.WithPrivileged) + if !ociRuntime.PrivilegedWithoutHostDevices { + specOpts = append(specOpts, oci.WithHostDevices, oci.WithAllDevicesAllowed) + } + } + + // Clear all ambient capabilities. The implication of non-root + caps + // is not clearly defined in Kubernetes. + // See https://github.com/kubernetes/kubernetes/issues/56374 + // Keep docker's behavior for now. + specOpts = append(specOpts, + customopts.WithoutAmbientCaps, + customopts.WithSelinuxLabels(processLabel, mountLabel), + ) + + // TODO: Figure out whether we should set no new privilege for sandbox container by default + if securityContext.GetNoNewPrivs() { + specOpts = append(specOpts, oci.WithNoNewPrivileges) + } + // TODO(random-liu): [P1] Set selinux options (privileged or not). + if securityContext.GetReadonlyRootfs() { + specOpts = append(specOpts, oci.WithRootFSReadonly()) + } + + if c.config.DisableCgroup { + specOpts = append(specOpts, customopts.WithDisabledCgroups) + } else { + specOpts = append(specOpts, customopts.WithResources(config.GetLinux().GetResources(), c.config.TolerateMissingHugetlbController, c.config.DisableHugetlbController)) + if sandboxConfig.GetLinux().GetCgroupParent() != "" { + cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id) + specOpts = append(specOpts, oci.WithCgroup(cgroupsPath)) + } + } + + supplementalGroups := securityContext.GetSupplementalGroups() + + for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, + ociRuntime.PodAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + ociRuntime.ContainerAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + // Default target PID namespace is the sandbox PID. + targetPid := sandboxPid + // If the container targets another container's PID namespace, + // set targetPid to the PID of that container. + nsOpts := securityContext.GetNamespaceOptions() + if nsOpts.GetPid() == runtime.NamespaceMode_TARGET { + targetContainer, err := c.validateTargetContainer(sandboxID, nsOpts.TargetId) + if err != nil { + return nil, errors.Wrapf(err, "invalid target container") + } + + status := targetContainer.Status.Get() + targetPid = status.Pid + } + + specOpts = append(specOpts, + customopts.WithOOMScoreAdj(config, c.config.RestrictOOMScoreAdj), + customopts.WithPodNamespaces(securityContext, sandboxPid, targetPid), + customopts.WithSupplementalGroups(supplementalGroups), + customopts.WithAnnotation(annotations.ContainerType, annotations.ContainerTypeContainer), + customopts.WithAnnotation(annotations.SandboxID, sandboxID), + customopts.WithAnnotation(annotations.SandboxNamespace, sandboxConfig.GetMetadata().GetNamespace()), + customopts.WithAnnotation(annotations.SandboxName, sandboxConfig.GetMetadata().GetName()), + customopts.WithAnnotation(annotations.ContainerName, containerName), + customopts.WithAnnotation(annotations.ImageName, imageName), + ) + // cgroupns is used for hiding /sys/fs/cgroup from containers. + // For compatibility, cgroupns is not used when running in cgroup v1 mode or in privileged. + // https://github.com/containers/libpod/issues/4363 + // https://github.com/kubernetes/enhancements/blob/0e409b47497e398b369c281074485c8de129694f/keps/sig-node/20191118-cgroups-v2.md#cgroup-namespace + if cgroups.Mode() == cgroups.Unified && !securityContext.GetPrivileged() { + specOpts = append(specOpts, oci.WithLinuxNamespace( + runtimespec.LinuxNamespace{ + Type: runtimespec.CgroupNamespace, + })) + } + return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec, specOpts...) +} + +func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + var specOpts []oci.SpecOpts + securityContext := config.GetLinux().GetSecurityContext() + // Set container username. This could only be done by containerd, because it needs + // access to the container rootfs. Pass user name to containerd, and let it overwrite + // the spec for us. + userstr, err := generateUserString( + securityContext.GetRunAsUsername(), + securityContext.GetRunAsUser(), + securityContext.GetRunAsGroup()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate user string") + } + if userstr == "" { + // Lastly, since no user override was passed via CRI try to set via OCI + // Image + userstr = imageConfig.User + } + if userstr != "" { + specOpts = append(specOpts, oci.WithUser(userstr)) + } + + if securityContext.GetRunAsUsername() != "" { + userstr = securityContext.GetRunAsUsername() + } else { + // Even if RunAsUser is not set, we still call `GetValue` to get uid 0. + // Because it is still useful to get additional gids for uid 0. + userstr = strconv.FormatInt(securityContext.GetRunAsUser().GetValue(), 10) + } + specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr)) + + asp := securityContext.GetApparmor() + if asp == nil { + asp, err = generateApparmorSecurityProfile(securityContext.GetApparmorProfile()) //nolint:staticcheck // Deprecated but we don't want to remove yet + if err != nil { + return nil, errors.Wrap(err, "failed to generate apparmor spec opts") + } + } + apparmorSpecOpts, err := generateApparmorSpecOpts( + asp, + securityContext.GetPrivileged(), + c.apparmorEnabled()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate apparmor spec opts") + } + if apparmorSpecOpts != nil { + specOpts = append(specOpts, apparmorSpecOpts) + } + + ssp := securityContext.GetSeccomp() + if ssp == nil { + ssp, err = generateSeccompSecurityProfile( + securityContext.GetSeccompProfilePath(), //nolint:staticcheck // Deprecated but we don't want to remove yet + c.config.UnsetSeccompProfile) + if err != nil { + return nil, errors.Wrap(err, "failed to generate seccomp spec opts") + } + } + seccompSpecOpts, err := c.generateSeccompSpecOpts( + ssp, + securityContext.GetPrivileged(), + c.seccompEnabled()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate seccomp spec opts") + } + if seccompSpecOpts != nil { + specOpts = append(specOpts, seccompSpecOpts) + } + return specOpts, nil +} + +func generateSeccompSecurityProfile(profilePath string, unsetProfilePath string) (*runtime.SecurityProfile, error) { + if profilePath != "" { + return generateSecurityProfile(profilePath) + } + if unsetProfilePath != "" { + return generateSecurityProfile(unsetProfilePath) + } + return nil, nil +} +func generateApparmorSecurityProfile(profilePath string) (*runtime.SecurityProfile, error) { + if profilePath != "" { + return generateSecurityProfile(profilePath) + } + return nil, nil +} + +func generateSecurityProfile(profilePath string) (*runtime.SecurityProfile, error) { + switch profilePath { + case runtimeDefault, dockerDefault, "": + return &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, nil + case unconfinedProfile: + return &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, nil + default: + // Require and Trim default profile name prefix + if !strings.HasPrefix(profilePath, profileNamePrefix) { + return nil, errors.Errorf("invalid profile %q", profilePath) + } + return &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: strings.TrimPrefix(profilePath, profileNamePrefix), + }, nil + } +} + +// generateSeccompSpecOpts generates containerd SpecOpts for seccomp. +func (c *criService) generateSeccompSpecOpts(sp *runtime.SecurityProfile, privileged, seccompEnabled bool) (oci.SpecOpts, error) { + if privileged { + // Do not set seccomp profile when container is privileged + return nil, nil + } + if !seccompEnabled { + if sp != nil { + if sp.ProfileType != runtime.SecurityProfile_Unconfined { + return nil, errors.New("seccomp is not supported") + } + } + return nil, nil + } + + if sp == nil { + return nil, nil + } + + if sp.ProfileType != runtime.SecurityProfile_Localhost && sp.LocalhostRef != "" { + return nil, errors.New("seccomp config invalid LocalhostRef must only be set if ProfileType is Localhost") + } + switch sp.ProfileType { + case runtime.SecurityProfile_Unconfined: + // Do not set seccomp profile. + return nil, nil + case runtime.SecurityProfile_RuntimeDefault: + return seccomp.WithDefaultProfile(), nil + case runtime.SecurityProfile_Localhost: + // trimming the localhost/ prefix just in case even though it should not + // be necessary with the new SecurityProfile struct + return seccomp.WithProfile(strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix)), nil + default: + return nil, errors.New("seccomp unknown ProfileType") + } +} + +// generateApparmorSpecOpts generates containerd SpecOpts for apparmor. +func generateApparmorSpecOpts(sp *runtime.SecurityProfile, privileged, apparmorEnabled bool) (oci.SpecOpts, error) { + if !apparmorEnabled { + // Should fail loudly if user try to specify apparmor profile + // but we don't support it. + if sp != nil { + if sp.ProfileType != runtime.SecurityProfile_Unconfined { + return nil, errors.New("apparmor is not supported") + } + } + return nil, nil + } + + if sp == nil { + // Based on kubernetes#51746, default apparmor profile should be applied + // for when apparmor is not specified. + sp, _ = generateSecurityProfile("") + } + + if sp.ProfileType != runtime.SecurityProfile_Localhost && sp.LocalhostRef != "" { + return nil, errors.New("apparmor config invalid LocalhostRef must only be set if ProfileType is Localhost") + } + + switch sp.ProfileType { + case runtime.SecurityProfile_Unconfined: + // Do not set apparmor profile. + return nil, nil + case runtime.SecurityProfile_RuntimeDefault: + if privileged { + // Do not set apparmor profile when container is privileged + return nil, nil + } + // TODO (mikebrow): delete created apparmor default profile + return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil + case runtime.SecurityProfile_Localhost: + // trimming the localhost/ prefix just in case even through it should not + // be necessary with the new SecurityProfile struct + appArmorProfile := strings.TrimPrefix(sp.LocalhostRef, profileNamePrefix) + if profileExists, err := appArmorProfileExists(appArmorProfile); !profileExists { + if err != nil { + return nil, errors.Wrap(err, "failed to generate apparmor spec opts") + } + return nil, errors.Errorf("apparmor profile not found %s", appArmorProfile) + } + return apparmor.WithProfile(appArmorProfile), nil + default: + return nil, errors.New("apparmor unknown ProfileType") + } +} + +// appArmorProfileExists scans apparmor/profiles for the requested profile +func appArmorProfileExists(profile string) (bool, error) { + if profile == "" { + return false, errors.New("nil apparmor profile is not supported") + } + profiles, err := os.Open("/sys/kernel/security/apparmor/profiles") + if err != nil { + return false, err + } + defer profiles.Close() + + rbuff := bufio.NewReader(profiles) + for { + line, err := rbuff.ReadString('\n') + switch err { + case nil: + if strings.HasPrefix(line, profile+" (") { + return true, nil + } + case io.EOF: + return false, nil + default: + return false, err + } + } +} + +// generateUserString generates valid user string based on OCI Image Spec +// v1.0.0. +// +// CRI defines that the following combinations are valid: +// +// (none) -> "" +// username -> username +// username, uid -> username +// username, uid, gid -> username:gid +// username, gid -> username:gid +// uid -> uid +// uid, gid -> uid:gid +// gid -> error +// +// TODO(random-liu): Add group name support in CRI. +func generateUserString(username string, uid, gid *runtime.Int64Value) (string, error) { + var userstr, groupstr string + if uid != nil { + userstr = strconv.FormatInt(uid.GetValue(), 10) + } + if username != "" { + userstr = username + } + if gid != nil { + groupstr = strconv.FormatInt(gid.GetValue(), 10) + } + if userstr == "" { + if groupstr != "" { + return "", errors.Errorf("user group %q is specified without user", groupstr) + } + return "", nil + } + if groupstr != "" { + userstr = userstr + ":" + groupstr + } + return userstr, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_linux_test.go containerd-1.5.9/pkg/cri/server/container_create_linux_test.go --- containerd-1.2.6/pkg/cri/server/container_create_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,1420 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "fmt" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/contrib/apparmor" + "github.com/containerd/containerd/contrib/seccomp" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cap" + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/opts" + "github.com/containerd/containerd/pkg/cri/util" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + ostesting "github.com/containerd/containerd/pkg/os/testing" +) + +func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandboxConfig, + *imagespec.ImageConfig, func(*testing.T, string, string, uint32, *runtimespec.Spec)) { + config := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Image: &runtime.ImageSpec{ + Image: "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113799", + }, + Command: []string{"test", "command"}, + Args: []string{"test", "args"}, + WorkingDir: "test-cwd", + Envs: []*runtime.KeyValue{ + {Key: "k1", Value: "v1"}, + {Key: "k2", Value: "v2"}, + {Key: "k3", Value: "v3=v3bis"}, + {Key: "k4", Value: "v4=v4bis=foop"}, + }, + Mounts: []*runtime.Mount{ + // everything default + { + ContainerPath: "container-path-1", + HostPath: "host-path-1", + }, + // readOnly + { + ContainerPath: "container-path-2", + HostPath: "host-path-2", + Readonly: true, + }, + }, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"ca-c": "ca-d"}, + Linux: &runtime.LinuxContainerConfig{ + Resources: &runtime.LinuxContainerResources{ + CpuPeriod: 100, + CpuQuota: 200, + CpuShares: 300, + MemoryLimitInBytes: 400, + OomScoreAdj: 500, + CpusetCpus: "0-1", + CpusetMems: "2-3", + }, + SecurityContext: &runtime.LinuxContainerSecurityContext{ + SupplementalGroups: []int64{1111, 2222}, + NoNewPrivs: true, + }, + }, + } + sandboxConfig := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-sandbox-name", + Uid: "test-sandbox-uid", + Namespace: "test-sandbox-ns", + Attempt: 2, + }, + Annotations: map[string]string{"c": "d"}, + Linux: &runtime.LinuxPodSandboxConfig{ + CgroupParent: "/test/cgroup/parent", + SecurityContext: &runtime.LinuxSandboxSecurityContext{}, + }, + } + imageConfig := &imagespec.ImageConfig{ + Env: []string{"ik1=iv1", "ik2=iv2", "ik3=iv3=iv3bis", "ik4=iv4=iv4bis=boop"}, + Entrypoint: []string{"/entrypoint"}, + Cmd: []string{"cmd"}, + WorkingDir: "/workspace", + } + specCheck := func(t *testing.T, id string, sandboxID string, sandboxPid uint32, spec *runtimespec.Spec) { + assert.Equal(t, relativeRootfsPath, spec.Root.Path) + assert.Equal(t, []string{"test", "command", "test", "args"}, spec.Process.Args) + assert.Equal(t, "test-cwd", spec.Process.Cwd) + assert.Contains(t, spec.Process.Env, "k1=v1", "k2=v2", "k3=v3=v3bis", "ik4=iv4=iv4bis=boop") + assert.Contains(t, spec.Process.Env, "ik1=iv1", "ik2=iv2", "ik3=iv3=iv3bis", "k4=v4=v4bis=foop") + + t.Logf("Check cgroups bind mount") + checkMount(t, spec.Mounts, "cgroup", "/sys/fs/cgroup", "cgroup", []string{"ro"}, nil) + + t.Logf("Check bind mount") + checkMount(t, spec.Mounts, "host-path-1", "container-path-1", "bind", []string{"rbind", "rprivate", "rw"}, nil) + checkMount(t, spec.Mounts, "host-path-2", "container-path-2", "bind", []string{"rbind", "rprivate", "ro"}, nil) + + t.Logf("Check resource limits") + assert.EqualValues(t, *spec.Linux.Resources.CPU.Period, 100) + assert.EqualValues(t, *spec.Linux.Resources.CPU.Quota, 200) + assert.EqualValues(t, *spec.Linux.Resources.CPU.Shares, 300) + assert.EqualValues(t, spec.Linux.Resources.CPU.Cpus, "0-1") + assert.EqualValues(t, spec.Linux.Resources.CPU.Mems, "2-3") + assert.EqualValues(t, *spec.Linux.Resources.Memory.Limit, 400) + assert.EqualValues(t, *spec.Process.OOMScoreAdj, 500) + + t.Logf("Check supplemental groups") + assert.Contains(t, spec.Process.User.AdditionalGids, uint32(1111)) + assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222)) + + t.Logf("Check no_new_privs") + assert.Equal(t, spec.Process.NoNewPrivileges, true) + + t.Logf("Check cgroup path") + assert.Equal(t, getCgroupsPath("/test/cgroup/parent", id), spec.Linux.CgroupsPath) + + t.Logf("Check namespaces") + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.NetworkNamespace, + Path: opts.GetNetworkNamespace(sandboxPid), + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.IPCNamespace, + Path: opts.GetIPCNamespace(sandboxPid), + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.UTSNamespace, + Path: opts.GetUTSNamespace(sandboxPid), + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + Path: opts.GetPIDNamespace(sandboxPid), + }) + + t.Logf("Check PodSandbox annotations") + assert.Contains(t, spec.Annotations, annotations.SandboxID) + assert.EqualValues(t, spec.Annotations[annotations.SandboxID], sandboxID) + + assert.Contains(t, spec.Annotations, annotations.ContainerType) + assert.EqualValues(t, spec.Annotations[annotations.ContainerType], annotations.ContainerTypeContainer) + + assert.Contains(t, spec.Annotations, annotations.SandboxNamespace) + assert.EqualValues(t, spec.Annotations[annotations.SandboxNamespace], "test-sandbox-ns") + + assert.Contains(t, spec.Annotations, annotations.SandboxName) + assert.EqualValues(t, spec.Annotations[annotations.SandboxName], "test-sandbox-name") + + assert.Contains(t, spec.Annotations, annotations.ImageName) + assert.EqualValues(t, spec.Annotations[annotations.ImageName], testImageName) + } + return config, sandboxConfig, imageConfig, specCheck +} + +func TestContainerCapabilities(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + allCaps := cap.Known() + for desc, test := range map[string]struct { + capability *runtime.Capability + includes []string + excludes []string + }{ + "should be able to add/drop capabilities": { + capability: &runtime.Capability{ + AddCapabilities: []string{"SYS_ADMIN"}, + DropCapabilities: []string{"CHOWN"}, + }, + includes: []string{"CAP_SYS_ADMIN"}, + excludes: []string{"CAP_CHOWN"}, + }, + "should be able to add all capabilities": { + capability: &runtime.Capability{ + AddCapabilities: []string{"ALL"}, + }, + includes: allCaps, + }, + "should be able to drop all capabilities": { + capability: &runtime.Capability{ + DropCapabilities: []string{"ALL"}, + }, + excludes: allCaps, + }, + "should be able to drop capabilities with add all": { + capability: &runtime.Capability{ + AddCapabilities: []string{"ALL"}, + DropCapabilities: []string{"CHOWN"}, + }, + includes: util.SubtractStringSlice(allCaps, "CAP_CHOWN"), + excludes: []string{"CAP_CHOWN"}, + }, + "should be able to add capabilities with drop all": { + capability: &runtime.Capability{ + AddCapabilities: []string{"SYS_ADMIN"}, + DropCapabilities: []string{"ALL"}, + }, + includes: []string{"CAP_SYS_ADMIN"}, + excludes: util.SubtractStringSlice(allCaps, "CAP_SYS_ADMIN"), + }, + } { + t.Logf("TestCase %q", desc) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + c.allCaps = allCaps + + containerConfig.Linux.SecurityContext.Capabilities = test.capability + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + + if selinux.GetEnabled() { + assert.NotEqual(t, "", spec.Process.SelinuxLabel) + assert.NotEqual(t, "", spec.Linux.MountLabel) + } + + specCheck(t, testID, testSandboxID, testPid, spec) + for _, include := range test.includes { + assert.Contains(t, spec.Process.Capabilities.Bounding, include) + assert.Contains(t, spec.Process.Capabilities.Effective, include) + assert.Contains(t, spec.Process.Capabilities.Inheritable, include) + assert.Contains(t, spec.Process.Capabilities.Permitted, include) + } + for _, exclude := range test.excludes { + assert.NotContains(t, spec.Process.Capabilities.Bounding, exclude) + assert.NotContains(t, spec.Process.Capabilities.Effective, exclude) + assert.NotContains(t, spec.Process.Capabilities.Inheritable, exclude) + assert.NotContains(t, spec.Process.Capabilities.Permitted, exclude) + } + assert.Empty(t, spec.Process.Capabilities.Ambient) + } +} + +func TestContainerSpecTty(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for _, tty := range []bool{true, false} { + containerConfig.Tty = tty + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) + assert.Equal(t, tty, spec.Process.Terminal) + if tty { + assert.Contains(t, spec.Process.Env, "TERM=xterm") + } else { + assert.NotContains(t, spec.Process.Env, "TERM=xterm") + } + } +} + +func TestContainerSpecDefaultPath(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + expectedDefault := "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for _, pathenv := range []string{"", "PATH=/usr/local/bin/games"} { + expected := expectedDefault + if pathenv != "" { + imageConfig.Env = append(imageConfig.Env, pathenv) + expected = pathenv + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) + assert.Contains(t, spec.Process.Env, expected) + } +} + +func TestContainerSpecReadonlyRootfs(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for _, readonly := range []bool{true, false} { + containerConfig.Linux.SecurityContext.ReadonlyRootfs = readonly + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) + assert.Equal(t, readonly, spec.Root.Readonly) + } +} + +func TestContainerSpecWithExtraMounts(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + mountInConfig := &runtime.Mount{ + // Test cleanpath + ContainerPath: "test-container-path/", + HostPath: "test-host-path", + Readonly: false, + } + containerConfig.Mounts = append(containerConfig.Mounts, mountInConfig) + extraMounts := []*runtime.Mount{ + { + ContainerPath: "test-container-path", + HostPath: "test-host-path-extra", + Readonly: true, + }, + { + ContainerPath: "/sys", + HostPath: "test-sys-extra", + Readonly: false, + }, + { + ContainerPath: "/dev", + HostPath: "test-dev-extra", + Readonly: false, + }, + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, extraMounts, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) + var mounts, sysMounts, devMounts []runtimespec.Mount + for _, m := range spec.Mounts { + if strings.HasPrefix(m.Destination, "test-container-path") { + mounts = append(mounts, m) + } else if m.Destination == "/sys" { + sysMounts = append(sysMounts, m) + } else if strings.HasPrefix(m.Destination, "/dev") { + devMounts = append(devMounts, m) + } + } + t.Logf("CRI mount should override extra mount") + require.Len(t, mounts, 1) + assert.Equal(t, "test-host-path", mounts[0].Source) + assert.Contains(t, mounts[0].Options, "rw") + + t.Logf("Extra mount should override default mount") + require.Len(t, sysMounts, 1) + assert.Equal(t, "test-sys-extra", sysMounts[0].Source) + assert.Contains(t, sysMounts[0].Options, "rw") + + t.Logf("Dev mount should override all default dev mounts") + require.Len(t, devMounts, 1) + assert.Equal(t, "test-dev-extra", devMounts[0].Source) + assert.Contains(t, devMounts[0].Options, "rw") +} + +func TestContainerAndSandboxPrivileged(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for desc, test := range map[string]struct { + containerPrivileged bool + sandboxPrivileged bool + expectError bool + }{ + "privileged container in non-privileged sandbox should fail": { + containerPrivileged: true, + sandboxPrivileged: false, + expectError: true, + }, + "privileged container in privileged sandbox should be fine": { + containerPrivileged: true, + sandboxPrivileged: true, + expectError: false, + }, + "non-privileged container in privileged sandbox should be fine": { + containerPrivileged: false, + sandboxPrivileged: true, + expectError: false, + }, + "non-privileged container in non-privileged sandbox should be fine": { + containerPrivileged: false, + sandboxPrivileged: false, + expectError: false, + }, + } { + t.Logf("TestCase %q", desc) + containerConfig.Linux.SecurityContext.Privileged = test.containerPrivileged + sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + Privileged: test.sandboxPrivileged, + } + _, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + if test.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + } +} + +func TestContainerMounts(t *testing.T) { + const testSandboxID = "test-id" + for desc, test := range map[string]struct { + statFn func(string) (os.FileInfo, error) + criMounts []*runtime.Mount + securityContext *runtime.LinuxContainerSecurityContext + expectedMounts []*runtime.Mount + }{ + "should setup ro mount when rootfs is read-only": { + securityContext: &runtime.LinuxContainerSecurityContext{ + ReadonlyRootfs: true, + }, + expectedMounts: []*runtime.Mount{ + { + ContainerPath: "/etc/hostname", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), + Readonly: true, + SelinuxRelabel: true, + }, + { + ContainerPath: "/etc/hosts", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"), + Readonly: true, + SelinuxRelabel: true, + }, + { + ContainerPath: resolvConfPath, + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"), + Readonly: true, + SelinuxRelabel: true, + }, + { + ContainerPath: "/dev/shm", + HostPath: filepath.Join(testStateDir, sandboxesDir, testSandboxID, "shm"), + Readonly: false, + SelinuxRelabel: true, + }, + }, + }, + "should setup rw mount when rootfs is read-write": { + securityContext: &runtime.LinuxContainerSecurityContext{}, + expectedMounts: []*runtime.Mount{ + { + ContainerPath: "/etc/hostname", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: "/etc/hosts", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: resolvConfPath, + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: "/dev/shm", + HostPath: filepath.Join(testStateDir, sandboxesDir, testSandboxID, "shm"), + Readonly: false, + SelinuxRelabel: true, + }, + }, + }, + "should use host /dev/shm when host ipc is set": { + securityContext: &runtime.LinuxContainerSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{Ipc: runtime.NamespaceMode_NODE}, + }, + expectedMounts: []*runtime.Mount{ + { + ContainerPath: "/etc/hostname", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: "/etc/hosts", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: resolvConfPath, + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: "/dev/shm", + HostPath: "/dev/shm", + Readonly: false, + }, + }, + }, + "should skip container mounts if already mounted by CRI": { + criMounts: []*runtime.Mount{ + { + ContainerPath: "/etc/hostname", + HostPath: "/test-etc-hostname", + }, + { + ContainerPath: "/etc/hosts", + HostPath: "/test-etc-host", + }, + { + ContainerPath: resolvConfPath, + HostPath: "test-resolv-conf", + }, + { + ContainerPath: "/dev/shm", + HostPath: "test-dev-shm", + }, + }, + securityContext: &runtime.LinuxContainerSecurityContext{}, + expectedMounts: nil, + }, + "should skip hostname mount if the old sandbox doesn't have hostname file": { + statFn: func(path string) (os.FileInfo, error) { + assert.Equal(t, filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hostname"), path) + return nil, errors.New("random error") + }, + securityContext: &runtime.LinuxContainerSecurityContext{}, + expectedMounts: []*runtime.Mount{ + { + ContainerPath: "/etc/hosts", + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "hosts"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: resolvConfPath, + HostPath: filepath.Join(testRootDir, sandboxesDir, testSandboxID, "resolv.conf"), + Readonly: false, + SelinuxRelabel: true, + }, + { + ContainerPath: "/dev/shm", + HostPath: filepath.Join(testStateDir, sandboxesDir, testSandboxID, "shm"), + Readonly: false, + SelinuxRelabel: true, + }, + }, + }, + } { + config := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Mounts: test.criMounts, + Linux: &runtime.LinuxContainerConfig{ + SecurityContext: test.securityContext, + }, + } + c := newTestCRIService() + c.os.(*ostesting.FakeOS).StatFn = test.statFn + mounts := c.containerMounts(testSandboxID, config) + assert.Equal(t, test.expectedMounts, mounts, desc) + } +} + +func TestPrivilegedBindMount(t *testing.T) { + testPid := uint32(1234) + c := newTestCRIService() + testSandboxID := "sandbox-id" + testContainerName := "container-name" + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + + for desc, test := range map[string]struct { + privileged bool + expectedSysFSRO bool + expectedCgroupFSRO bool + }{ + "sysfs and cgroupfs should mount as 'ro' by default": { + expectedSysFSRO: true, + expectedCgroupFSRO: true, + }, + "sysfs and cgroupfs should not mount as 'ro' if privileged": { + privileged: true, + expectedSysFSRO: false, + expectedCgroupFSRO: false, + }, + } { + t.Logf("TestCase %q", desc) + + containerConfig.Linux.SecurityContext.Privileged = test.privileged + sandboxConfig.Linux.SecurityContext.Privileged = test.privileged + + spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + + assert.NoError(t, err) + if test.expectedSysFSRO { + checkMount(t, spec.Mounts, "sysfs", "/sys", "sysfs", []string{"ro"}, []string{"rw"}) + } else { + checkMount(t, spec.Mounts, "sysfs", "/sys", "sysfs", []string{"rw"}, []string{"ro"}) + } + if test.expectedCgroupFSRO { + checkMount(t, spec.Mounts, "cgroup", "/sys/fs/cgroup", "cgroup", []string{"ro"}, []string{"rw"}) + } else { + checkMount(t, spec.Mounts, "cgroup", "/sys/fs/cgroup", "cgroup", []string{"rw"}, []string{"ro"}) + } + } +} + +func TestMountPropagation(t *testing.T) { + + sharedLookupMountFn := func(string) (mount.Info, error) { + return mount.Info{ + Mountpoint: "host-path", + Optional: "shared:", + }, nil + } + + slaveLookupMountFn := func(string) (mount.Info, error) { + return mount.Info{ + Mountpoint: "host-path", + Optional: "master:", + }, nil + } + + othersLookupMountFn := func(string) (mount.Info, error) { + return mount.Info{ + Mountpoint: "host-path", + Optional: "others", + }, nil + } + + for desc, test := range map[string]struct { + criMount *runtime.Mount + fakeLookupMountFn func(string) (mount.Info, error) + optionsCheck []string + expectErr bool + }{ + "HostPath should mount as 'rprivate' if propagation is MountPropagation_PROPAGATION_PRIVATE": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation_PROPAGATION_PRIVATE, + }, + fakeLookupMountFn: nil, + optionsCheck: []string{"rbind", "rprivate"}, + expectErr: false, + }, + "HostPath should mount as 'rslave' if propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + }, + fakeLookupMountFn: slaveLookupMountFn, + optionsCheck: []string{"rbind", "rslave"}, + expectErr: false, + }, + "HostPath should mount as 'rshared' if propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation_PROPAGATION_BIDIRECTIONAL, + }, + fakeLookupMountFn: sharedLookupMountFn, + optionsCheck: []string{"rbind", "rshared"}, + expectErr: false, + }, + "HostPath should mount as 'rprivate' if propagation is illegal": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation(42), + }, + fakeLookupMountFn: nil, + optionsCheck: []string{"rbind", "rprivate"}, + expectErr: false, + }, + "Expect an error if HostPath isn't shared and mount propagation is MountPropagation_PROPAGATION_BIDIRECTIONAL": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation_PROPAGATION_BIDIRECTIONAL, + }, + fakeLookupMountFn: slaveLookupMountFn, + expectErr: true, + }, + "Expect an error if HostPath isn't slave or shared and mount propagation is MountPropagation_PROPAGATION_HOST_TO_CONTAINER": { + criMount: &runtime.Mount{ + ContainerPath: "container-path", + HostPath: "host-path", + Propagation: runtime.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + }, + fakeLookupMountFn: othersLookupMountFn, + expectErr: true, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + c.os.(*ostesting.FakeOS).LookupMountFn = test.fakeLookupMountFn + config, _, _, _ := getCreateContainerTestData() + + var spec runtimespec.Spec + spec.Linux = &runtimespec.Linux{} + + err := opts.WithMounts(c.os, config, []*runtime.Mount{test.criMount}, "")(context.Background(), nil, nil, &spec) + if test.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + checkMount(t, spec.Mounts, test.criMount.HostPath, test.criMount.ContainerPath, "bind", test.optionsCheck, nil) + } + } +} + +func TestPidNamespace(t *testing.T) { + testID := "test-id" + testPid := uint32(1234) + testSandboxID := "sandbox-id" + testContainerName := "container-name" + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for desc, test := range map[string]struct { + pidNS runtime.NamespaceMode + expected runtimespec.LinuxNamespace + }{ + "node namespace mode": { + pidNS: runtime.NamespaceMode_NODE, + expected: runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + Path: opts.GetPIDNamespace(testPid), + }, + }, + "container namespace mode": { + pidNS: runtime.NamespaceMode_CONTAINER, + expected: runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + }, + }, + "pod namespace mode": { + pidNS: runtime.NamespaceMode_POD, + expected: runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + Path: opts.GetPIDNamespace(testPid), + }, + }, + } { + t.Logf("TestCase %q", desc) + containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{Pid: test.pidNS} + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + assert.Contains(t, spec.Linux.Namespaces, test.expected) + } +} + +func TestNoDefaultRunMount(t *testing.T) { + testID := "test-id" + testPid := uint32(1234) + testSandboxID := "sandbox-id" + testContainerName := "container-name" + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + assert.NoError(t, err) + for _, mount := range spec.Mounts { + assert.NotEqual(t, "/run", mount.Destination) + } +} + +func TestGenerateSeccompSecurityProfileSpecOpts(t *testing.T) { + for desc, test := range map[string]struct { + profile string + privileged bool + disable bool + specOpts oci.SpecOpts + expectErr bool + defaultProfile string + sp *runtime.SecurityProfile + }{ + "should return error if seccomp is specified when seccomp is not supported": { + profile: runtimeDefault, + disable: true, + expectErr: true, + }, + "should not return error if seccomp is not specified when seccomp is not supported": { + profile: "", + disable: true, + }, + "should not return error if seccomp is unconfined when seccomp is not supported": { + profile: unconfinedProfile, + disable: true, + }, + "should not set seccomp when privileged is true": { + profile: seccompDefaultProfile, + privileged: true, + }, + "should not set seccomp when seccomp is unconfined": { + profile: unconfinedProfile, + }, + "should not set seccomp when seccomp is not specified": { + profile: "", + }, + "should set default seccomp when seccomp is runtime/default": { + profile: runtimeDefault, + specOpts: seccomp.WithDefaultProfile(), + }, + "should set default seccomp when seccomp is docker/default": { + profile: dockerDefault, + specOpts: seccomp.WithDefaultProfile(), + }, + "should set specified profile when local profile is specified": { + profile: profileNamePrefix + "test-profile", + specOpts: seccomp.WithProfile("test-profile"), + }, + "should use default profile when seccomp is empty": { + defaultProfile: profileNamePrefix + "test-profile", + specOpts: seccomp.WithProfile("test-profile"), + }, + "should fallback to docker/default when seccomp is empty and default is runtime/default": { + defaultProfile: runtimeDefault, + specOpts: seccomp.WithDefaultProfile(), + }, + //----------------------------------------------- + // now buckets for the SecurityProfile variants + //----------------------------------------------- + "sp should return error if seccomp is specified when seccomp is not supported": { + disable: true, + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should not return error if seccomp is unconfined when seccomp is not supported": { + disable: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, + }, + "sp should not set seccomp when privileged is true": { + privileged: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should not set seccomp when seccomp is unconfined": { + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, + }, + "sp should not set seccomp when seccomp is not specified": {}, + "sp should set default seccomp when seccomp is runtime/default": { + specOpts: seccomp.WithDefaultProfile(), + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should set specified profile when local profile is specified": { + specOpts: seccomp.WithProfile("test-profile"), + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: profileNamePrefix + "test-profile", + }, + }, + "sp should set specified profile when local profile is specified even without prefix": { + specOpts: seccomp.WithProfile("test-profile"), + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: "test-profile", + }, + }, + "sp should return error if specified profile is invalid": { + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + LocalhostRef: "test-profile", + }, + }, + } { + t.Run(fmt.Sprintf("TestCase %q", desc), func(t *testing.T) { + cri := &criService{} + cri.config.UnsetSeccompProfile = test.defaultProfile + ssp := test.sp + csp, err := generateSeccompSecurityProfile( + test.profile, + test.defaultProfile) + if err != nil { + if test.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + } else { + if ssp == nil { + ssp = csp + } + specOpts, err := cri.generateSeccompSpecOpts(ssp, test.privileged, !test.disable) + assert.Equal(t, + reflect.ValueOf(test.specOpts).Pointer(), + reflect.ValueOf(specOpts).Pointer()) + if test.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + } + }) + } +} + +func TestGenerateApparmorSpecOpts(t *testing.T) { + for desc, test := range map[string]struct { + profile string + privileged bool + disable bool + specOpts oci.SpecOpts + expectErr bool + sp *runtime.SecurityProfile + }{ + "should return error if apparmor is specified when apparmor is not supported": { + profile: runtimeDefault, + disable: true, + expectErr: true, + }, + "should not return error if apparmor is not specified when apparmor is not supported": { + profile: "", + disable: true, + }, + "should set default apparmor when apparmor is not specified": { + profile: "", + specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), + }, + "should not apparmor when apparmor is not specified and privileged is true": { + profile: "", + privileged: true, + }, + "should not return error if apparmor is unconfined when apparmor is not supported": { + profile: unconfinedProfile, + disable: true, + }, + "should not apparmor when apparmor is unconfined": { + profile: unconfinedProfile, + }, + "should not apparmor when apparmor is unconfined and privileged is true": { + profile: unconfinedProfile, + privileged: true, + }, + "should set default apparmor when apparmor is runtime/default": { + profile: runtimeDefault, + specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), + }, + "should not apparmor when apparmor is default and privileged is true": { + profile: runtimeDefault, + privileged: true, + }, + // TODO (mikebrow) add success with existing defined profile tests + "should return error when undefined local profile is specified": { + profile: profileNamePrefix + "test-profile", + expectErr: true, + }, + "should return error when undefined local profile is specified and privileged is true": { + profile: profileNamePrefix + "test-profile", + privileged: true, + expectErr: true, + }, + "should return error if specified profile is invalid": { + profile: "test-profile", + expectErr: true, + }, + //-------------------------------------- + // buckets for SecurityProfile struct + //-------------------------------------- + "sp should return error if apparmor is specified when apparmor is not supported": { + disable: true, + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should not return error if apparmor is unconfined when apparmor is not supported": { + disable: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, + }, + "sp should not apparmor when apparmor is unconfined": { + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, + }, + "sp should not apparmor when apparmor is unconfined and privileged is true": { + privileged: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Unconfined, + }, + }, + "sp should set default apparmor when apparmor is runtime/default": { + specOpts: apparmor.WithDefaultProfile(appArmorDefaultProfileName), + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should not apparmor when apparmor is default and privileged is true": { + privileged: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_RuntimeDefault, + }, + }, + "sp should return error when undefined local profile is specified": { + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: profileNamePrefix + "test-profile", + }, + }, + "sp should return error when undefined local profile is specified even without prefix": { + profile: profileNamePrefix + "test-profile", + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: "test-profile", + }, + }, + "sp should return error when undefined local profile is specified and privileged is true": { + privileged: true, + expectErr: true, + sp: &runtime.SecurityProfile{ + ProfileType: runtime.SecurityProfile_Localhost, + LocalhostRef: profileNamePrefix + "test-profile", + }, + }, + } { + t.Logf("TestCase %q", desc) + asp := test.sp + csp, err := generateApparmorSecurityProfile(test.profile) + if err != nil { + if test.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + } else { + if asp == nil { + asp = csp + } + specOpts, err := generateApparmorSpecOpts(asp, test.privileged, !test.disable) + assert.Equal(t, + reflect.ValueOf(test.specOpts).Pointer(), + reflect.ValueOf(specOpts).Pointer()) + if test.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + } + } +} + +func TestMaskedAndReadonlyPaths(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + + defaultSpec, err := oci.GenerateSpec(ctrdutil.NamespacedContext(), nil, &containers.Container{ID: testID}) + require.NoError(t, err) + + for desc, test := range map[string]struct { + disableProcMount bool + masked []string + readonly []string + expectedMasked []string + expectedReadonly []string + privileged bool + }{ + "should apply default if not specified when disable_proc_mount = true": { + disableProcMount: true, + masked: nil, + readonly: nil, + expectedMasked: defaultSpec.Linux.MaskedPaths, + expectedReadonly: defaultSpec.Linux.ReadonlyPaths, + privileged: false, + }, + "should apply default if not specified when disable_proc_mount = false": { + disableProcMount: false, + masked: nil, + readonly: nil, + expectedMasked: []string{}, + expectedReadonly: []string{}, + privileged: false, + }, + "should be able to specify empty paths": { + masked: []string{}, + readonly: []string{}, + expectedMasked: []string{}, + expectedReadonly: []string{}, + privileged: false, + }, + "should apply CRI specified paths": { + masked: []string{"/proc"}, + readonly: []string{"/sys"}, + expectedMasked: []string{"/proc"}, + expectedReadonly: []string{"/sys"}, + privileged: false, + }, + "default should be nil for privileged": { + expectedMasked: nil, + expectedReadonly: nil, + privileged: true, + }, + "should be able to specify empty paths, esp. if privileged": { + masked: []string{}, + readonly: []string{}, + expectedMasked: nil, + expectedReadonly: nil, + privileged: true, + }, + "should not apply CRI specified paths if privileged": { + masked: []string{"/proc"}, + readonly: []string{"/sys"}, + expectedMasked: nil, + expectedReadonly: nil, + privileged: true, + }, + } { + t.Logf("TestCase %q", desc) + c.config.DisableProcMount = test.disableProcMount + containerConfig.Linux.SecurityContext.MaskedPaths = test.masked + containerConfig.Linux.SecurityContext.ReadonlyPaths = test.readonly + containerConfig.Linux.SecurityContext.Privileged = test.privileged + sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + Privileged: test.privileged, + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + if !test.privileged { // specCheck presumes an unprivileged container + specCheck(t, testID, testSandboxID, testPid, spec) + } + assert.Equal(t, test.expectedMasked, spec.Linux.MaskedPaths) + assert.Equal(t, test.expectedReadonly, spec.Linux.ReadonlyPaths) + } +} + +func TestHostname(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) { + return "real-hostname", nil + } + for desc, test := range map[string]struct { + hostname string + networkNs runtime.NamespaceMode + expectedEnv string + }{ + "should add HOSTNAME=sandbox.Hostname for pod network namespace": { + hostname: "test-hostname", + networkNs: runtime.NamespaceMode_POD, + expectedEnv: "HOSTNAME=test-hostname", + }, + "should add HOSTNAME=sandbox.Hostname for host network namespace": { + hostname: "test-hostname", + networkNs: runtime.NamespaceMode_NODE, + expectedEnv: "HOSTNAME=test-hostname", + }, + "should add HOSTNAME=os.Hostname for host network namespace if sandbox.Hostname is not set": { + hostname: "", + networkNs: runtime.NamespaceMode_NODE, + expectedEnv: "HOSTNAME=real-hostname", + }, + } { + t.Logf("TestCase %q", desc) + sandboxConfig.Hostname = test.hostname + sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{Network: test.networkNs}, + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) + assert.Contains(t, spec.Process.Env, test.expectedEnv) + } +} + +func TestDisableCgroup(t *testing.T) { + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + c.config.DisableCgroup = true + spec, err := c.containerSpec("test-id", "sandbox-id", 1234, "", "container-name", testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + + t.Log("resource limit should not be set") + assert.Nil(t, spec.Linux.Resources.Memory) + assert.Nil(t, spec.Linux.Resources.CPU) + + t.Log("cgroup path should be empty") + assert.Empty(t, spec.Linux.CgroupsPath) +} + +func TestGenerateUserString(t *testing.T) { + type testcase struct { + // the name of the test case + name string + + u string + uid, gid *runtime.Int64Value + + result string + expectedError bool + } + testcases := []testcase{ + { + name: "Empty", + result: "", + }, + { + name: "Username Only", + u: "testuser", + result: "testuser", + }, + { + name: "Username, UID", + u: "testuser", + uid: &runtime.Int64Value{Value: 1}, + result: "testuser", + }, + { + name: "Username, UID, GID", + u: "testuser", + uid: &runtime.Int64Value{Value: 1}, + gid: &runtime.Int64Value{Value: 10}, + result: "testuser:10", + }, + { + name: "Username, GID", + u: "testuser", + gid: &runtime.Int64Value{Value: 10}, + result: "testuser:10", + }, + { + name: "UID only", + uid: &runtime.Int64Value{Value: 1}, + result: "1", + }, + { + name: "UID, GID", + uid: &runtime.Int64Value{Value: 1}, + gid: &runtime.Int64Value{Value: 10}, + result: "1:10", + }, + { + name: "GID only", + gid: &runtime.Int64Value{Value: 10}, + result: "", + expectedError: true, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + r, err := generateUserString(tc.u, tc.uid, tc.gid) + if tc.expectedError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tc.result, r) + }) + } +} + +func TestPrivilegedDevices(t *testing.T) { + testPid := uint32(1234) + c := newTestCRIService() + testSandboxID := "sandbox-id" + testContainerName := "container-name" + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + + for desc, test := range map[string]struct { + privileged bool + privilegedWithoutHostDevices bool + expectHostDevices bool + }{ + "expect no host devices when privileged is false": { + privileged: false, + privilegedWithoutHostDevices: false, + expectHostDevices: false, + }, + "expect no host devices when privileged is false and privilegedWithoutHostDevices is true": { + privileged: false, + privilegedWithoutHostDevices: true, + expectHostDevices: false, + }, + "expect host devices when privileged is true": { + privileged: true, + privilegedWithoutHostDevices: false, + expectHostDevices: true, + }, + "expect no host devices when privileged is true and privilegedWithoutHostDevices is true": { + privileged: true, + privilegedWithoutHostDevices: true, + expectHostDevices: false, + }, + } { + t.Logf("TestCase %q", desc) + + containerConfig.Linux.SecurityContext.Privileged = test.privileged + sandboxConfig.Linux.SecurityContext.Privileged = test.privileged + + ociRuntime := config.Runtime{ + PrivilegedWithoutHostDevices: test.privilegedWithoutHostDevices, + } + spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + assert.NoError(t, err) + + hostDevicesRaw, err := oci.HostDevices() + assert.NoError(t, err) + var hostDevices = make([]string, 0) + for _, dev := range hostDevicesRaw { + // https://github.com/containerd/cri/pull/1521#issuecomment-652807951 + if dev.Major != 0 { + hostDevices = append(hostDevices, dev.Path) + } + } + + if test.expectHostDevices { + assert.Len(t, spec.Linux.Devices, len(hostDevices)) + } else { + assert.Empty(t, spec.Linux.Devices) + } + } +} + +func TestBaseOCISpec(t *testing.T) { + c := newTestCRIService() + baseLimit := int64(100) + c.baseOCISpecs = map[string]*oci.Spec{ + "/etc/containerd/cri-base.json": { + Process: &runtimespec.Process{ + User: runtimespec.User{AdditionalGids: []uint32{9999}}, + Capabilities: &runtimespec.LinuxCapabilities{ + Permitted: []string{"CAP_SETUID"}, + }, + }, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: &baseLimit}, // Will be overwritten by `getCreateContainerTestData` + }, + }, + }, + } + + ociRuntime := config.Runtime{} + ociRuntime.BaseRuntimeSpec = "/etc/containerd/cri-base.json" + + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + assert.NoError(t, err) + + specCheck(t, testID, testSandboxID, testPid, spec) + + assert.Contains(t, spec.Process.User.AdditionalGids, uint32(9999)) + assert.Len(t, spec.Process.User.AdditionalGids, 3) + + assert.Contains(t, spec.Process.Capabilities.Permitted, "CAP_SETUID") + assert.Len(t, spec.Process.Capabilities.Permitted, 1) + + assert.Equal(t, *spec.Linux.Resources.Memory.Limit, containerConfig.Linux.Resources.MemoryLimitInBytes) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_other.go containerd-1.5.9/pkg/cri/server/container_create_other.go --- containerd-1.2.6/pkg/cri/server/container_create_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,54 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/config" +) + +// containerMounts sets up necessary container system file mounts +// including /dev/shm, /etc/hosts and /etc/resolv.conf. +func (c *criService) containerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount { + return []*runtime.Mount{} +} + +func (c *criService) containerSpec( + id string, + sandboxID string, + sandboxPid uint32, + netNSPath string, + containerName string, + imageName string, + config *runtime.ContainerConfig, + sandboxConfig *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, + extraMounts []*runtime.Mount, + ociRuntime config.Runtime, +) (_ *runtimespec.Spec, retErr error) { + return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec) +} + +func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + return []oci.SpecOpts{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_other_test.go containerd-1.5.9/pkg/cri/server/container_create_other_test.go --- containerd-1.2.6/pkg/cri/server/container_create_other_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_other_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// checkMount is defined by all tests but not used here +var _ = checkMount + +func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandboxConfig, + *imagespec.ImageConfig, func(*testing.T, string, string, uint32, *runtimespec.Spec)) { + config := &runtime.ContainerConfig{} + sandboxConfig := &runtime.PodSandboxConfig{} + imageConfig := &imagespec.ImageConfig{} + specCheck := func(t *testing.T, id string, sandboxID string, sandboxPid uint32, spec *runtimespec.Spec) { + } + return config, sandboxConfig, imageConfig, specCheck +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_test.go containerd-1.5.9/pkg/cri/server/container_create_test.go --- containerd-1.2.6/pkg/cri/server/container_create_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,418 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "path/filepath" + goruntime "runtime" + "testing" + + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/constants" + "github.com/containerd/containerd/pkg/cri/opts" +) + +func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string, + contains, notcontains []string) { + found := false + for _, m := range mounts { + if m.Source == src && m.Destination == dest { + assert.Equal(t, m.Type, typ) + for _, c := range contains { + assert.Contains(t, m.Options, c) + } + for _, n := range notcontains { + assert.NotContains(t, m.Options, n) + } + found = true + break + } + } + assert.True(t, found, "mount from %q to %q not found", src, dest) +} + +const testImageName = "container-image-name" + +func TestGeneralContainerSpec(t *testing.T) { + testID := "test-id" + testPid := uint32(1234) + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + testSandboxID := "sandbox-id" + testContainerName := "container-name" + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + require.NoError(t, err) + specCheck(t, testID, testSandboxID, testPid, spec) +} + +func TestPodAnnotationPassthroughContainerSpec(t *testing.T) { + if goruntime.GOOS == "darwin" { + t.Skip("not implemented on Darwin") + } + + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + + for desc, test := range map[string]struct { + podAnnotations []string + configChange func(*runtime.PodSandboxConfig) + specCheck func(*testing.T, *runtimespec.Spec) + }{ + "a passthrough annotation should be passed as an OCI annotation": { + podAnnotations: []string{"c"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, spec.Annotations["c"], "d") + }, + }, + "a non-passthrough annotation should not be passed as an OCI annotation": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Annotations["d"] = "e" + }, + podAnnotations: []string{"c"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, spec.Annotations["c"], "d") + _, ok := spec.Annotations["d"] + assert.False(t, ok) + }, + }, + "passthrough annotations should support wildcard match": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Annotations["t.f"] = "j" + c.Annotations["z.g"] = "o" + c.Annotations["z"] = "o" + c.Annotations["y.ca"] = "b" + c.Annotations["y"] = "b" + }, + podAnnotations: []string{"t*", "z.*", "y.c*"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + t.Logf("%+v", spec.Annotations) + assert.Equal(t, spec.Annotations["t.f"], "j") + assert.Equal(t, spec.Annotations["z.g"], "o") + assert.Equal(t, spec.Annotations["y.ca"], "b") + _, ok := spec.Annotations["y"] + assert.False(t, ok) + _, ok = spec.Annotations["z"] + assert.False(t, ok) + }, + }, + } { + t.Run(desc, func(t *testing.T) { + c := newTestCRIService() + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + if test.configChange != nil { + test.configChange(sandboxConfig) + } + + ociRuntime := config.Runtime{ + PodAnnotations: test.podAnnotations, + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, + containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, testSandboxID, testPid, spec) + if test.specCheck != nil { + test.specCheck(t, spec) + } + }) + } +} + +func TestContainerSpecCommand(t *testing.T) { + for desc, test := range map[string]struct { + criEntrypoint []string + criArgs []string + imageEntrypoint []string + imageArgs []string + expected []string + expectErr bool + }{ + "should use cri entrypoint if it's specified": { + criEntrypoint: []string{"a", "b"}, + imageEntrypoint: []string{"c", "d"}, + imageArgs: []string{"e", "f"}, + expected: []string{"a", "b"}, + }, + "should use cri entrypoint if it's specified even if it's empty": { + criEntrypoint: []string{}, + criArgs: []string{"a", "b"}, + imageEntrypoint: []string{"c", "d"}, + imageArgs: []string{"e", "f"}, + expected: []string{"a", "b"}, + }, + "should use cri entrypoint and args if they are specified": { + criEntrypoint: []string{"a", "b"}, + criArgs: []string{"c", "d"}, + imageEntrypoint: []string{"e", "f"}, + imageArgs: []string{"g", "h"}, + expected: []string{"a", "b", "c", "d"}, + }, + "should use image entrypoint if cri entrypoint is not specified": { + criArgs: []string{"a", "b"}, + imageEntrypoint: []string{"c", "d"}, + imageArgs: []string{"e", "f"}, + expected: []string{"c", "d", "a", "b"}, + }, + "should use image args if both cri entrypoint and args are not specified": { + imageEntrypoint: []string{"c", "d"}, + imageArgs: []string{"e", "f"}, + expected: []string{"c", "d", "e", "f"}, + }, + "should return error if both entrypoint and args are empty": { + expectErr: true, + }, + } { + + config, _, imageConfig, _ := getCreateContainerTestData() + config.Command = test.criEntrypoint + config.Args = test.criArgs + imageConfig.Entrypoint = test.imageEntrypoint + imageConfig.Cmd = test.imageArgs + + var spec runtimespec.Spec + err := opts.WithProcessArgs(config, imageConfig)(context.Background(), nil, nil, &spec) + if test.expectErr { + assert.Error(t, err) + continue + } + assert.NoError(t, err) + assert.Equal(t, test.expected, spec.Process.Args, desc) + } +} + +func TestVolumeMounts(t *testing.T) { + testContainerRootDir := "test-container-root" + for desc, test := range map[string]struct { + criMounts []*runtime.Mount + imageVolumes map[string]struct{} + expectedMountDest []string + }{ + "should setup rw mount for image volumes": { + imageVolumes: map[string]struct{}{ + "/test-volume-1": {}, + "/test-volume-2": {}, + }, + expectedMountDest: []string{ + "/test-volume-1", + "/test-volume-2", + }, + }, + "should skip image volumes if already mounted by CRI": { + criMounts: []*runtime.Mount{ + { + ContainerPath: "/test-volume-1", + HostPath: "/test-hostpath-1", + }, + }, + imageVolumes: map[string]struct{}{ + "/test-volume-1": {}, + "/test-volume-2": {}, + }, + expectedMountDest: []string{ + "/test-volume-2", + }, + }, + "should compare and return cleanpath": { + criMounts: []*runtime.Mount{ + { + ContainerPath: "/test-volume-1", + HostPath: "/test-hostpath-1", + }, + }, + imageVolumes: map[string]struct{}{ + "/test-volume-1/": {}, + "/test-volume-2/": {}, + }, + expectedMountDest: []string{ + "/test-volume-2/", + }, + }, + } { + t.Logf("TestCase %q", desc) + config := &imagespec.ImageConfig{ + Volumes: test.imageVolumes, + } + c := newTestCRIService() + got := c.volumeMounts(testContainerRootDir, test.criMounts, config) + assert.Len(t, got, len(test.expectedMountDest)) + for _, dest := range test.expectedMountDest { + found := false + for _, m := range got { + if m.ContainerPath == dest { + found = true + assert.Equal(t, + filepath.Dir(m.HostPath), + filepath.Join(testContainerRootDir, "volumes")) + break + } + } + assert.True(t, found) + } + } +} + +func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) { + if goruntime.GOOS == "darwin" { + t.Skip("not implemented on Darwin") + } + + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + + for desc, test := range map[string]struct { + podAnnotations []string + containerAnnotations []string + podConfigChange func(*runtime.PodSandboxConfig) + configChange func(*runtime.ContainerConfig) + specCheck func(*testing.T, *runtimespec.Spec) + }{ + "passthrough annotations from pod and container should be passed as an OCI annotation": { + podConfigChange: func(p *runtime.PodSandboxConfig) { + p.Annotations["pod.annotation.1"] = "1" + p.Annotations["pod.annotation.2"] = "2" + p.Annotations["pod.annotation.3"] = "3" + }, + configChange: func(c *runtime.ContainerConfig) { + c.Annotations["container.annotation.1"] = "1" + c.Annotations["container.annotation.2"] = "2" + c.Annotations["container.annotation.3"] = "3" + }, + podAnnotations: []string{"pod.annotation.1"}, + containerAnnotations: []string{"container.annotation.1"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, "1", spec.Annotations["container.annotation.1"]) + _, ok := spec.Annotations["container.annotation.2"] + assert.False(t, ok) + _, ok = spec.Annotations["container.annotation.3"] + assert.False(t, ok) + assert.Equal(t, "1", spec.Annotations["pod.annotation.1"]) + _, ok = spec.Annotations["pod.annotation.2"] + assert.False(t, ok) + _, ok = spec.Annotations["pod.annotation.3"] + assert.False(t, ok) + }, + }, + "passthrough annotations from pod and container should support wildcard": { + podConfigChange: func(p *runtime.PodSandboxConfig) { + p.Annotations["pod.annotation.1"] = "1" + p.Annotations["pod.annotation.2"] = "2" + p.Annotations["pod.annotation.3"] = "3" + }, + configChange: func(c *runtime.ContainerConfig) { + c.Annotations["container.annotation.1"] = "1" + c.Annotations["container.annotation.2"] = "2" + c.Annotations["container.annotation.3"] = "3" + }, + podAnnotations: []string{"pod.annotation.*"}, + containerAnnotations: []string{"container.annotation.*"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, "1", spec.Annotations["container.annotation.1"]) + assert.Equal(t, "2", spec.Annotations["container.annotation.2"]) + assert.Equal(t, "3", spec.Annotations["container.annotation.3"]) + assert.Equal(t, "1", spec.Annotations["pod.annotation.1"]) + assert.Equal(t, "2", spec.Annotations["pod.annotation.2"]) + assert.Equal(t, "3", spec.Annotations["pod.annotation.3"]) + }, + }, + "annotations should not pass through if no passthrough annotations are configured": { + podConfigChange: func(p *runtime.PodSandboxConfig) { + p.Annotations["pod.annotation.1"] = "1" + p.Annotations["pod.annotation.2"] = "2" + p.Annotations["pod.annotation.3"] = "3" + }, + configChange: func(c *runtime.ContainerConfig) { + c.Annotations["container.annotation.1"] = "1" + c.Annotations["container.annotation.2"] = "2" + c.Annotations["container.annotation.3"] = "3" + }, + podAnnotations: []string{}, + containerAnnotations: []string{}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + _, ok := spec.Annotations["container.annotation.1"] + assert.False(t, ok) + _, ok = spec.Annotations["container.annotation.2"] + assert.False(t, ok) + _, ok = spec.Annotations["container.annotation.3"] + assert.False(t, ok) + _, ok = spec.Annotations["pod.annotation.1"] + assert.False(t, ok) + _, ok = spec.Annotations["pod.annotation.2"] + assert.False(t, ok) + _, ok = spec.Annotations["pod.annotation.3"] + assert.False(t, ok) + }, + }, + } { + t.Run(desc, func(t *testing.T) { + c := newTestCRIService() + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + if test.configChange != nil { + test.configChange(containerConfig) + } + if test.podConfigChange != nil { + test.podConfigChange(sandboxConfig) + } + ociRuntime := config.Runtime{ + PodAnnotations: test.podAnnotations, + ContainerAnnotations: test.containerAnnotations, + } + spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, + containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, testSandboxID, testPid, spec) + if test.specCheck != nil { + test.specCheck(t, spec) + } + }) + } +} + +func TestBaseRuntimeSpec(t *testing.T) { + c := newTestCRIService() + c.baseOCISpecs = map[string]*oci.Spec{ + "/etc/containerd/cri-base.json": { + Version: "1.0.2", + Hostname: "old", + }, + } + + out, err := c.runtimeSpec("id1", "/etc/containerd/cri-base.json", oci.WithHostname("new")) + assert.NoError(t, err) + + assert.Equal(t, "1.0.2", out.Version) + assert.Equal(t, "new", out.Hostname) + + // Make sure original base spec not changed + assert.NotEqual(t, out, c.baseOCISpecs["/etc/containerd/cri-base.json"]) + assert.Equal(t, c.baseOCISpecs["/etc/containerd/cri-base.json"].Hostname, "old") + + assert.Equal(t, filepath.Join("/", constants.K8sContainerdNamespace, "id1"), out.Linux.CgroupsPath) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_windows.go containerd-1.5.9/pkg/cri/server/container_create_windows.go --- containerd-1.2.6/pkg/cri/server/container_create_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,130 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/config" + customopts "github.com/containerd/containerd/pkg/cri/opts" +) + +// No container mounts for windows. +func (c *criService) containerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount { + return nil +} + +func (c *criService) containerSpec( + id string, + sandboxID string, + sandboxPid uint32, + netNSPath string, + containerName string, + imageName string, + config *runtime.ContainerConfig, + sandboxConfig *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, + extraMounts []*runtime.Mount, + ociRuntime config.Runtime, +) (*runtimespec.Spec, error) { + specOpts := []oci.SpecOpts{ + customopts.WithProcessArgs(config, imageConfig), + } + if config.GetWorkingDir() != "" { + specOpts = append(specOpts, oci.WithProcessCwd(config.GetWorkingDir())) + } else if imageConfig.WorkingDir != "" { + specOpts = append(specOpts, oci.WithProcessCwd(imageConfig.WorkingDir)) + } + + if config.GetTty() { + specOpts = append(specOpts, oci.WithTTY) + } + + // Apply envs from image config first, so that envs from container config + // can override them. + env := append([]string{}, imageConfig.Env...) + for _, e := range config.GetEnvs() { + env = append(env, e.GetKey()+"="+e.GetValue()) + } + specOpts = append(specOpts, oci.WithEnv(env)) + + specOpts = append(specOpts, + // Clear the root location since hcsshim expects it. + // NOTE: readonly rootfs doesn't work on windows. + customopts.WithoutRoot, + customopts.WithWindowsNetworkNamespace(netNSPath), + oci.WithHostname(sandboxConfig.GetHostname()), + ) + + specOpts = append(specOpts, customopts.WithWindowsMounts(c.os, config, extraMounts)) + + // Start with the image config user and override below if RunAsUsername is not "". + username := imageConfig.User + + windowsConfig := config.GetWindows() + if windowsConfig != nil { + specOpts = append(specOpts, customopts.WithWindowsResources(windowsConfig.GetResources())) + securityCtx := windowsConfig.GetSecurityContext() + if securityCtx != nil { + runAsUser := securityCtx.GetRunAsUsername() + if runAsUser != "" { + username = runAsUser + } + cs := securityCtx.GetCredentialSpec() + if cs != "" { + specOpts = append(specOpts, customopts.WithWindowsCredentialSpec(cs)) + } + } + } + + // There really isn't a good Windows way to verify that the username is available in the + // image as early as here like there is for Linux. Later on in the stack hcsshim + // will handle the behavior of erroring out if the user isn't available in the image + // when trying to run the init process. + specOpts = append(specOpts, oci.WithUser(username)) + + for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, + ociRuntime.PodAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + ociRuntime.ContainerAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + specOpts = append(specOpts, + customopts.WithAnnotation(annotations.ContainerType, annotations.ContainerTypeContainer), + customopts.WithAnnotation(annotations.SandboxID, sandboxID), + customopts.WithAnnotation(annotations.SandboxNamespace, sandboxConfig.GetMetadata().GetNamespace()), + customopts.WithAnnotation(annotations.SandboxName, sandboxConfig.GetMetadata().GetName()), + customopts.WithAnnotation(annotations.ContainerName, containerName), + customopts.WithAnnotation(annotations.ImageName, imageName), + ) + return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec, specOpts...) +} + +// No extra spec options needed for windows. +func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + return nil, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_create_windows_test.go containerd-1.5.9/pkg/cri/server/container_create_windows_test.go --- containerd-1.2.6/pkg/cri/server/container_create_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_create_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,195 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/config" +) + +func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandboxConfig, + *imagespec.ImageConfig, func(*testing.T, string, string, uint32, *runtimespec.Spec)) { + config := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Image: &runtime.ImageSpec{ + Image: "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113799", + }, + Command: []string{"test", "command"}, + Args: []string{"test", "args"}, + WorkingDir: "test-cwd", + Envs: []*runtime.KeyValue{ + {Key: "k1", Value: "v1"}, + {Key: "k2", Value: "v2"}, + {Key: "k3", Value: "v3=v3bis"}, + {Key: "k4", Value: "v4=v4bis=foop"}, + }, + Mounts: []*runtime.Mount{ + // everything default + { + ContainerPath: "container-path-1", + HostPath: "host-path-1", + }, + // readOnly + { + ContainerPath: "container-path-2", + HostPath: "host-path-2", + Readonly: true, + }, + }, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + Windows: &runtime.WindowsContainerConfig{ + Resources: &runtime.WindowsContainerResources{ + CpuShares: 100, + CpuCount: 200, + CpuMaximum: 300, + MemoryLimitInBytes: 400, + }, + SecurityContext: &runtime.WindowsContainerSecurityContext{ + RunAsUsername: "test-user", + CredentialSpec: "{\"test\": \"spec\"}", + }, + }, + } + sandboxConfig := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-sandbox-name", + Uid: "test-sandbox-uid", + Namespace: "test-sandbox-ns", + Attempt: 2, + }, + Hostname: "test-hostname", + Annotations: map[string]string{"c": "d"}, + } + imageConfig := &imagespec.ImageConfig{ + Env: []string{"ik1=iv1", "ik2=iv2", "ik3=iv3=iv3bis", "ik4=iv4=iv4bis=boop"}, + Entrypoint: []string{"/entrypoint"}, + Cmd: []string{"cmd"}, + WorkingDir: "/workspace", + User: "ContainerUser", + } + specCheck := func(t *testing.T, id string, sandboxID string, sandboxPid uint32, spec *runtimespec.Spec) { + assert.Nil(t, spec.Root) + assert.Equal(t, "test-hostname", spec.Hostname) + assert.Equal(t, []string{"test", "command", "test", "args"}, spec.Process.Args) + assert.Equal(t, "test-cwd", spec.Process.Cwd) + assert.Contains(t, spec.Process.Env, "k1=v1", "k2=v2", "k3=v3=v3bis", "ik4=iv4=iv4bis=boop") + assert.Contains(t, spec.Process.Env, "ik1=iv1", "ik2=iv2", "ik3=iv3=iv3bis", "k4=v4=v4bis=foop") + + t.Logf("Check bind mount") + checkMount(t, spec.Mounts, "host-path-1", "container-path-1", "", []string{"rw"}, nil) + checkMount(t, spec.Mounts, "host-path-2", "container-path-2", "", []string{"ro"}, nil) + + t.Logf("Check resource limits") + assert.EqualValues(t, *spec.Windows.Resources.CPU.Shares, 100) + assert.EqualValues(t, *spec.Windows.Resources.CPU.Count, 200) + assert.EqualValues(t, *spec.Windows.Resources.CPU.Maximum, 300) + assert.EqualValues(t, *spec.Windows.Resources.CPU.Maximum, 300) + assert.EqualValues(t, *spec.Windows.Resources.Memory.Limit, 400) + + // Also checks if override of the image configs user is behaving. + t.Logf("Check username") + assert.Contains(t, spec.Process.User.Username, "test-user") + + t.Logf("Check credential spec") + assert.Contains(t, spec.Windows.CredentialSpec, "{\"test\": \"spec\"}") + + t.Logf("Check PodSandbox annotations") + assert.Contains(t, spec.Annotations, annotations.SandboxID) + assert.EqualValues(t, spec.Annotations[annotations.SandboxID], sandboxID) + + assert.Contains(t, spec.Annotations, annotations.ContainerType) + assert.EqualValues(t, spec.Annotations[annotations.ContainerType], annotations.ContainerTypeContainer) + + assert.Contains(t, spec.Annotations, annotations.SandboxNamespace) + assert.EqualValues(t, spec.Annotations[annotations.SandboxNamespace], "test-sandbox-ns") + + assert.Contains(t, spec.Annotations, annotations.SandboxName) + assert.EqualValues(t, spec.Annotations[annotations.SandboxName], "test-sandbox-name") + } + return config, sandboxConfig, imageConfig, specCheck +} + +func TestContainerWindowsNetworkNamespace(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + nsPath := "test-cni" + c := newTestCRIService() + + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{}) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, testSandboxID, testPid, spec) + assert.NotNil(t, spec.Windows) + assert.NotNil(t, spec.Windows.Network) + assert.Equal(t, nsPath, spec.Windows.Network.NetworkNamespace) +} + +func TestMountCleanPath(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + nsPath := "test-cni" + c := newTestCRIService() + + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + containerConfig.Mounts = append(containerConfig.Mounts, &runtime.Mount{ + ContainerPath: "c:/test/container-path", + HostPath: "c:/test/host-path", + }) + spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{}) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, testSandboxID, testPid, spec) + checkMount(t, spec.Mounts, "c:\\test\\host-path", "c:\\test\\container-path", "", []string{"rw"}, nil) +} + +func TestMountNamedPipe(t *testing.T) { + testID := "test-id" + testSandboxID := "sandbox-id" + testContainerName := "container-name" + testPid := uint32(1234) + nsPath := "test-cni" + c := newTestCRIService() + + containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData() + containerConfig.Mounts = append(containerConfig.Mounts, &runtime.Mount{ + ContainerPath: `\\.\pipe\foo`, + HostPath: `\\.\pipe\foo`, + }) + spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{}) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, testSandboxID, testPid, spec) + checkMount(t, spec.Mounts, `\\.\pipe\foo`, `\\.\pipe\foo`, "", []string{"rw"}, nil) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_exec.go containerd-1.5.9/pkg/cri/server/container_exec.go --- containerd-1.2.6/pkg/cri/server/container_exec.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// Exec prepares a streaming endpoint to execute a command in the container, and returns the address. +func (c *criService) Exec(ctx context.Context, r *runtime.ExecRequest) (*runtime.ExecResponse, error) { + cntr, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrapf(err, "failed to find container %q in store", r.GetContainerId()) + } + state := cntr.Status.Get().State() + if state != runtime.ContainerState_CONTAINER_RUNNING { + return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) + } + return c.streamServer.GetExec(r) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_execsync.go containerd-1.5.9/pkg/cri/server/container_execsync.go --- containerd-1.2.6/pkg/cri/server/container_execsync.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_execsync.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,211 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "bytes" + "io" + "syscall" + "time" + + "github.com/containerd/containerd" + containerdio "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/oci" + "github.com/pkg/errors" + "golang.org/x/net/context" + "k8s.io/client-go/tools/remotecommand" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + "github.com/containerd/containerd/pkg/cri/util" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +// ExecSync executes a command in the container, and returns the stdout output. +// If command exits with a non-zero exit code, an error is returned. +func (c *criService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (*runtime.ExecSyncResponse, error) { + var stdout, stderr bytes.Buffer + exitCode, err := c.execInContainer(ctx, r.GetContainerId(), execOptions{ + cmd: r.GetCmd(), + stdout: cioutil.NewNopWriteCloser(&stdout), + stderr: cioutil.NewNopWriteCloser(&stderr), + timeout: time.Duration(r.GetTimeout()) * time.Second, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to exec in container") + } + + return &runtime.ExecSyncResponse{ + Stdout: stdout.Bytes(), + Stderr: stderr.Bytes(), + ExitCode: int32(*exitCode), + }, nil +} + +// execOptions specifies how to execute command in container. +type execOptions struct { + cmd []string + stdin io.Reader + stdout io.WriteCloser + stderr io.WriteCloser + tty bool + resize <-chan remotecommand.TerminalSize + timeout time.Duration +} + +func (c *criService) execInternal(ctx context.Context, container containerd.Container, id string, opts execOptions) (*uint32, error) { + // Cancel the context before returning to ensure goroutines are stopped. + // This is important, because if `Start` returns error, `Wait` will hang + // forever unless we cancel the context. + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + spec, err := container.Spec(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get container spec") + } + task, err := container.Task(ctx, nil) + if err != nil { + return nil, errors.Wrap(err, "failed to load task") + } + pspec := spec.Process + + pspec.Terminal = opts.tty + if opts.tty { + if err := oci.WithEnv([]string{"TERM=xterm"})(ctx, nil, nil, spec); err != nil { + return nil, errors.Wrap(err, "add TERM env var to spec") + } + } + + pspec.Args = opts.cmd + + if opts.stdout == nil { + opts.stdout = cio.NewDiscardLogger() + } + if opts.stderr == nil { + opts.stderr = cio.NewDiscardLogger() + } + execID := util.GenerateID() + log.G(ctx).Debugf("Generated exec id %q for container %q", execID, id) + volatileRootDir := c.getVolatileContainerRootDir(id) + var execIO *cio.ExecIO + process, err := task.Exec(ctx, execID, pspec, + func(id string) (containerdio.IO, error) { + var err error + execIO, err = cio.NewExecIO(id, volatileRootDir, opts.tty, opts.stdin != nil) + return execIO, err + }, + ) + if err != nil { + return nil, errors.Wrapf(err, "failed to create exec %q", execID) + } + defer func() { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + if _, err := process.Delete(deferCtx, containerd.WithProcessKill); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to delete exec process %q for container %q", execID, id) + } + }() + + exitCh, err := process.Wait(ctx) + if err != nil { + return nil, errors.Wrapf(err, "failed to wait for process %q", execID) + } + if err := process.Start(ctx); err != nil { + return nil, errors.Wrapf(err, "failed to start exec %q", execID) + } + + handleResizing(ctx, opts.resize, func(size remotecommand.TerminalSize) { + if err := process.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to resize process %q console for container %q", execID, id) + } + }) + + attachDone := execIO.Attach(cio.AttachOptions{ + Stdin: opts.stdin, + Stdout: opts.stdout, + Stderr: opts.stderr, + Tty: opts.tty, + StdinOnce: true, + CloseStdin: func() error { + return process.CloseIO(ctx, containerd.WithStdinCloser) + }, + }) + + execCtx := ctx + if opts.timeout > 0 { + var execCtxCancel context.CancelFunc + execCtx, execCtxCancel = context.WithTimeout(ctx, opts.timeout) + defer execCtxCancel() + } + + select { + case <-execCtx.Done(): + // Ignore the not found error because the process may exit itself before killing. + if err := process.Kill(ctx, syscall.SIGKILL); err != nil && !errdefs.IsNotFound(err) { + return nil, errors.Wrapf(err, "failed to kill exec %q", execID) + } + // Wait for the process to be killed. + exitRes := <-exitCh + log.G(ctx).Debugf("Timeout received while waiting for exec process kill %q code %d and error %v", + execID, exitRes.ExitCode(), exitRes.Error()) + <-attachDone + log.G(ctx).Debugf("Stream pipe for exec process %q done", execID) + return nil, errors.Wrapf(execCtx.Err(), "timeout %v exceeded", opts.timeout) + case exitRes := <-exitCh: + code, _, err := exitRes.Result() + log.G(ctx).Debugf("Exec process %q exits with exit code %d and error %v", execID, code, err) + if err != nil { + return nil, errors.Wrapf(err, "failed while waiting for exec %q", execID) + } + <-attachDone + log.G(ctx).Debugf("Stream pipe for exec process %q done", execID) + return &code, nil + } +} + +// execInContainer executes a command inside the container synchronously, and +// redirects stdio stream properly. +// This function only returns when the exec process exits, this means that: +// 1) As long as the exec process is running, the goroutine in the cri plugin +// will be running and wait for the exit code; +// 2) `kubectl exec -it` will hang until the exec process exits, even after io +// is detached. This is different from dockershim, which leaves the exec process +// running in background after io is detached. +// https://github.com/kubernetes/kubernetes/blob/v1.15.0/pkg/kubelet/dockershim/exec.go#L127 +// For example, if the `kubectl exec -it` process is killed, IO will be closed. In +// this case, the CRI plugin will still have a goroutine waiting for the exec process +// to exit and log the exit code, but dockershim won't. +func (c *criService) execInContainer(ctx context.Context, id string, opts execOptions) (*uint32, error) { + // Get container from our container store. + cntr, err := c.containerStore.Get(id) + + if err != nil { + return nil, errors.Wrapf(err, "failed to find container %q in store", id) + } + id = cntr.ID + + state := cntr.Status.Get().State() + if state != runtime.ContainerState_CONTAINER_RUNNING { + return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) + } + + return c.execInternal(ctx, cntr.Container, id, opts) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_list.go containerd-1.5.9/pkg/cri/server/container_list.go --- containerd-1.2.6/pkg/cri/server/container_list.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_list.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,112 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "golang.org/x/net/context" + + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// ListContainers lists all containers matching the filter. +func (c *criService) ListContainers(ctx context.Context, r *runtime.ListContainersRequest) (*runtime.ListContainersResponse, error) { + // List all containers from store. + containersInStore := c.containerStore.List() + + var containers []*runtime.Container + for _, container := range containersInStore { + containers = append(containers, toCRIContainer(container)) + } + + containers = c.filterCRIContainers(containers, r.GetFilter()) + return &runtime.ListContainersResponse{Containers: containers}, nil +} + +// toCRIContainer converts internal container object into CRI container. +func toCRIContainer(container containerstore.Container) *runtime.Container { + status := container.Status.Get() + return &runtime.Container{ + Id: container.ID, + PodSandboxId: container.SandboxID, + Metadata: container.Config.GetMetadata(), + Image: container.Config.GetImage(), + ImageRef: container.ImageRef, + State: status.State(), + CreatedAt: status.CreatedAt, + Labels: container.Config.GetLabels(), + Annotations: container.Config.GetAnnotations(), + } +} + +func (c *criService) normalizeContainerFilter(filter *runtime.ContainerFilter) { + if cntr, err := c.containerStore.Get(filter.GetId()); err == nil { + filter.Id = cntr.ID + } + if sb, err := c.sandboxStore.Get(filter.GetPodSandboxId()); err == nil { + filter.PodSandboxId = sb.ID + } +} + +// filterCRIContainers filters CRIContainers. +func (c *criService) filterCRIContainers(containers []*runtime.Container, filter *runtime.ContainerFilter) []*runtime.Container { + if filter == nil { + return containers + } + + // The containerd cri plugin supports short ids so long as there is only one + // match. So we do a lookup against the store here if a pod id has been + // included in the filter. + sb := filter.GetPodSandboxId() + if sb != "" { + sandbox, err := c.sandboxStore.Get(sb) + if err == nil { + sb = sandbox.ID + } + } + + c.normalizeContainerFilter(filter) + filtered := []*runtime.Container{} + for _, cntr := range containers { + if filter.GetId() != "" && filter.GetId() != cntr.Id { + continue + } + if sb != "" && sb != cntr.PodSandboxId { + continue + } + if filter.GetState() != nil && filter.GetState().GetState() != cntr.State { + continue + } + if filter.GetLabelSelector() != nil { + match := true + for k, v := range filter.GetLabelSelector() { + got, ok := cntr.Labels[k] + if !ok || got != v { + match = false + break + } + } + if !match { + continue + } + } + filtered = append(filtered, cntr) + } + + return filtered +} diff -Nru containerd-1.2.6/pkg/cri/server/container_list_test.go containerd-1.5.9/pkg/cri/server/container_list_test.go --- containerd-1.2.6/pkg/cri/server/container_list_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_list_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,345 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +func TestToCRIContainer(t *testing.T) { + config := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Image: &runtime.ImageSpec{Image: "test-image"}, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + } + createdAt := time.Now().UnixNano() + container, err := containerstore.NewContainer( + containerstore.Metadata{ + ID: "test-id", + Name: "test-name", + SandboxID: "test-sandbox-id", + Config: config, + ImageRef: "test-image-ref", + }, + containerstore.WithFakeStatus( + containerstore.Status{ + Pid: 1234, + CreatedAt: createdAt, + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 1, + Reason: "test-reason", + Message: "test-message", + }, + ), + ) + assert.NoError(t, err) + expect := &runtime.Container{ + Id: "test-id", + PodSandboxId: "test-sandbox-id", + Metadata: config.GetMetadata(), + Image: config.GetImage(), + ImageRef: "test-image-ref", + State: runtime.ContainerState_CONTAINER_EXITED, + CreatedAt: createdAt, + Labels: config.GetLabels(), + Annotations: config.GetAnnotations(), + } + c := toCRIContainer(container) + assert.Equal(t, expect, c) +} + +func TestFilterContainers(t *testing.T) { + c := newTestCRIService() + + testContainers := []*runtime.Container{ + { + Id: "1", + PodSandboxId: "s-1", + Metadata: &runtime.ContainerMetadata{Name: "name-1", Attempt: 1}, + State: runtime.ContainerState_CONTAINER_RUNNING, + }, + { + Id: "2", + PodSandboxId: "s-2", + Metadata: &runtime.ContainerMetadata{Name: "name-2", Attempt: 2}, + State: runtime.ContainerState_CONTAINER_EXITED, + Labels: map[string]string{"a": "b"}, + }, + { + Id: "3", + PodSandboxId: "s-2", + Metadata: &runtime.ContainerMetadata{Name: "name-2", Attempt: 3}, + State: runtime.ContainerState_CONTAINER_CREATED, + Labels: map[string]string{"c": "d"}, + }, + } + for desc, test := range map[string]struct { + filter *runtime.ContainerFilter + expect []*runtime.Container + }{ + "no filter": { + expect: testContainers, + }, + "id filter": { + filter: &runtime.ContainerFilter{Id: "2"}, + expect: []*runtime.Container{testContainers[1]}, + }, + "state filter": { + filter: &runtime.ContainerFilter{ + State: &runtime.ContainerStateValue{ + State: runtime.ContainerState_CONTAINER_EXITED, + }, + }, + expect: []*runtime.Container{testContainers[1]}, + }, + "label filter": { + filter: &runtime.ContainerFilter{ + LabelSelector: map[string]string{"a": "b"}, + }, + expect: []*runtime.Container{testContainers[1]}, + }, + "sandbox id filter": { + filter: &runtime.ContainerFilter{PodSandboxId: "s-2"}, + expect: []*runtime.Container{testContainers[1], testContainers[2]}, + }, + "mixed filter not matched": { + filter: &runtime.ContainerFilter{ + Id: "1", + PodSandboxId: "s-2", + LabelSelector: map[string]string{"a": "b"}, + }, + expect: []*runtime.Container{}, + }, + "mixed filter matched": { + filter: &runtime.ContainerFilter{ + PodSandboxId: "s-2", + State: &runtime.ContainerStateValue{ + State: runtime.ContainerState_CONTAINER_CREATED, + }, + LabelSelector: map[string]string{"c": "d"}, + }, + expect: []*runtime.Container{testContainers[2]}, + }, + } { + filtered := c.filterCRIContainers(testContainers, test.filter) + assert.Equal(t, test.expect, filtered, desc) + } +} + +// containerForTest is a helper type for test. +type containerForTest struct { + metadata containerstore.Metadata + status containerstore.Status +} + +func (c containerForTest) toContainer() (containerstore.Container, error) { + return containerstore.NewContainer( + c.metadata, + containerstore.WithFakeStatus(c.status), + ) +} + +func TestListContainers(t *testing.T) { + c := newTestCRIService() + sandboxesInStore := []sandboxstore.Sandbox{ + sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: "s-1abcdef1234", + Name: "sandboxname-1", + Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "podname-1"}}, + }, + sandboxstore.Status{ + State: sandboxstore.StateReady, + }, + ), + sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: "s-2abcdef1234", + Name: "sandboxname-2", + Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "podname-2"}}, + }, + sandboxstore.Status{ + State: sandboxstore.StateNotReady, + }, + ), + } + createdAt := time.Now().UnixNano() + startedAt := time.Now().UnixNano() + finishedAt := time.Now().UnixNano() + containersInStore := []containerForTest{ + { + metadata: containerstore.Metadata{ + ID: "c-1container", + Name: "name-1", + SandboxID: "s-1abcdef1234", + Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-1"}}, + }, + status: containerstore.Status{CreatedAt: createdAt}, + }, + { + metadata: containerstore.Metadata{ + ID: "c-2container", + Name: "name-2", + SandboxID: "s-1abcdef1234", + Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-2"}}, + }, + status: containerstore.Status{ + CreatedAt: createdAt, + StartedAt: startedAt, + }, + }, + { + metadata: containerstore.Metadata{ + ID: "c-3container", + Name: "name-3", + SandboxID: "s-1abcdef1234", + Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-3"}}, + }, + status: containerstore.Status{ + CreatedAt: createdAt, + StartedAt: startedAt, + FinishedAt: finishedAt, + }, + }, + { + metadata: containerstore.Metadata{ + ID: "c-4container", + Name: "name-4", + SandboxID: "s-2abcdef1234", + Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-4"}}, + }, + status: containerstore.Status{ + CreatedAt: createdAt, + }, + }, + } + + expectedContainers := []*runtime.Container{ + { + Id: "c-1container", + PodSandboxId: "s-1abcdef1234", + Metadata: &runtime.ContainerMetadata{Name: "name-1"}, + State: runtime.ContainerState_CONTAINER_CREATED, + CreatedAt: createdAt, + }, + { + Id: "c-2container", + PodSandboxId: "s-1abcdef1234", + Metadata: &runtime.ContainerMetadata{Name: "name-2"}, + State: runtime.ContainerState_CONTAINER_RUNNING, + CreatedAt: createdAt, + }, + { + Id: "c-3container", + PodSandboxId: "s-1abcdef1234", + Metadata: &runtime.ContainerMetadata{Name: "name-3"}, + State: runtime.ContainerState_CONTAINER_EXITED, + CreatedAt: createdAt, + }, + { + Id: "c-4container", + PodSandboxId: "s-2abcdef1234", + Metadata: &runtime.ContainerMetadata{Name: "name-4"}, + State: runtime.ContainerState_CONTAINER_CREATED, + CreatedAt: createdAt, + }, + } + + // Inject test sandbox metadata + for _, sb := range sandboxesInStore { + assert.NoError(t, c.sandboxStore.Add(sb)) + } + + // Inject test container metadata + for _, cntr := range containersInStore { + container, err := cntr.toContainer() + assert.NoError(t, err) + assert.NoError(t, c.containerStore.Add(container)) + } + + for testdesc, testdata := range map[string]struct { + filter *runtime.ContainerFilter + expect []*runtime.Container + }{ + "test without filter": { + filter: &runtime.ContainerFilter{}, + expect: expectedContainers, + }, + "test filter by sandboxid": { + filter: &runtime.ContainerFilter{ + PodSandboxId: "s-1abcdef1234", + }, + expect: expectedContainers[:3], + }, + "test filter by truncated sandboxid": { + filter: &runtime.ContainerFilter{ + PodSandboxId: "s-1", + }, + expect: expectedContainers[:3], + }, + "test filter by containerid": { + filter: &runtime.ContainerFilter{ + Id: "c-1container", + }, + expect: expectedContainers[:1], + }, + "test filter by truncated containerid": { + filter: &runtime.ContainerFilter{ + Id: "c-1", + }, + expect: expectedContainers[:1], + }, + "test filter by containerid and sandboxid": { + filter: &runtime.ContainerFilter{ + Id: "c-1container", + PodSandboxId: "s-1abcdef1234", + }, + expect: expectedContainers[:1], + }, + "test filter by truncated containerid and truncated sandboxid": { + filter: &runtime.ContainerFilter{ + Id: "c-1", + PodSandboxId: "s-1", + }, + expect: expectedContainers[:1], + }, + } { + t.Logf("TestCase: %s", testdesc) + resp, err := c.ListContainers(context.Background(), &runtime.ListContainersRequest{Filter: testdata.filter}) + assert.NoError(t, err) + require.NotNil(t, resp) + containers := resp.GetContainers() + assert.Len(t, containers, len(testdata.expect)) + for _, cntr := range testdata.expect { + assert.Contains(t, containers, cntr) + } + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_log_reopen.go containerd-1.5.9/pkg/cri/server/container_log_reopen.go --- containerd-1.2.6/pkg/cri/server/container_log_reopen.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_log_reopen.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/pkg/errors" + "golang.org/x/net/context" + + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// ReopenContainerLog asks the cri plugin to reopen the stdout/stderr log file for the container. +// This is often called after the log file has been rotated. +func (c *criService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (*runtime.ReopenContainerLogResponse, error) { + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) + } + + if container.Status.Get().State() != runtime.ContainerState_CONTAINER_RUNNING { + return nil, errors.New("container is not running") + } + + // Create new container logger and replace the existing ones. + stdoutWC, stderrWC, err := c.createContainerLoggers(container.LogPath, container.Config.GetTty()) + if err != nil { + return nil, err + } + oldStdoutWC, oldStderrWC := container.IO.AddOutput("log", stdoutWC, stderrWC) + if oldStdoutWC != nil { + oldStdoutWC.Close() + } + if oldStderrWC != nil { + oldStderrWC.Close() + } + return &runtime.ReopenContainerLogResponse{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_remove.go containerd-1.5.9/pkg/cri/server/container_remove.go --- containerd-1.2.6/pkg/cri/server/container_remove.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_remove.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,135 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// RemoveContainer removes the container. +func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (_ *runtime.RemoveContainerResponse, retErr error) { + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + if err != store.ErrNotExist { + return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) + } + // Do not return error if container metadata doesn't exist. + log.G(ctx).Tracef("RemoveContainer called for container %q that does not exist", r.GetContainerId()) + return &runtime.RemoveContainerResponse{}, nil + } + id := container.ID + + // Forcibly stop the containers if they are in running or unknown state + state := container.Status.Get().State() + if state == runtime.ContainerState_CONTAINER_RUNNING || + state == runtime.ContainerState_CONTAINER_UNKNOWN { + logrus.Infof("Forcibly stopping container %q", id) + if err := c.stopContainer(ctx, container, 0); err != nil { + return nil, errors.Wrapf(err, "failed to forcibly stop container %q", id) + } + + } + + // Set removing state to prevent other start/remove operations against this container + // while it's being removed. + if err := setContainerRemoving(container); err != nil { + return nil, errors.Wrapf(err, "failed to set removing state for container %q", id) + } + defer func() { + if retErr != nil { + // Reset removing if remove failed. + if err := resetContainerRemoving(container); err != nil { + log.G(ctx).WithError(err).Errorf("failed to reset removing state for container %q", id) + } + } + }() + + // NOTE(random-liu): Docker set container to "Dead" state when start removing the + // container so as to avoid start/restart the container again. However, for current + // kubelet implementation, we'll never start a container once we decide to remove it, + // so we don't need the "Dead" state for now. + + // Delete containerd container. + if err := container.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil { + if !errdefs.IsNotFound(err) { + return nil, errors.Wrapf(err, "failed to delete containerd container %q", id) + } + log.G(ctx).Tracef("Remove called for containerd container %q that does not exist", id) + } + + // Delete container checkpoint. + if err := container.Delete(); err != nil { + return nil, errors.Wrapf(err, "failed to delete container checkpoint for %q", id) + } + + containerRootDir := c.getContainerRootDir(id) + if err := ensureRemoveAll(ctx, containerRootDir); err != nil { + return nil, errors.Wrapf(err, "failed to remove container root directory %q", + containerRootDir) + } + volatileContainerRootDir := c.getVolatileContainerRootDir(id) + if err := ensureRemoveAll(ctx, volatileContainerRootDir); err != nil { + return nil, errors.Wrapf(err, "failed to remove volatile container root directory %q", + volatileContainerRootDir) + } + + c.containerStore.Delete(id) + + c.containerNameIndex.ReleaseByKey(id) + + return &runtime.RemoveContainerResponse{}, nil +} + +// setContainerRemoving sets the container into removing state. In removing state, the +// container will not be started or removed again. +func setContainerRemoving(container containerstore.Container) error { + return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + // Do not remove container if it's still running or unknown. + if status.State() == runtime.ContainerState_CONTAINER_RUNNING { + return status, errors.New("container is still running, to stop first") + } + if status.State() == runtime.ContainerState_CONTAINER_UNKNOWN { + return status, errors.New("container state is unknown, to stop first") + } + if status.Starting { + return status, errors.New("container is in starting state, can't be removed") + } + if status.Removing { + return status, errors.New("container is already in removing state") + } + status.Removing = true + return status, nil + }) +} + +// resetContainerRemoving resets the container removing state on remove failure. So +// that we could remove the container again. +func resetContainerRemoving(container containerstore.Container) error { + return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + status.Removing = false + return status, nil + }) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_remove_test.go containerd-1.5.9/pkg/cri/server/container_remove_test.go --- containerd-1.2.6/pkg/cri/server/container_remove_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_remove_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,85 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// TestSetContainerRemoving tests setContainerRemoving sets removing +// state correctly. +func TestSetContainerRemoving(t *testing.T) { + testID := "test-id" + for desc, test := range map[string]struct { + status containerstore.Status + expectErr bool + }{ + "should return error when container is in running state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + }, + expectErr: true, + }, + "should return error when container is in starting state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + Starting: true, + }, + expectErr: true, + }, + "should return error when container is in removing state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + Removing: true, + }, + expectErr: true, + }, + "should not return error when container is not running and removing": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + }, + expectErr: false, + }, + } { + t.Logf("TestCase %q", desc) + container, err := containerstore.NewContainer( + containerstore.Metadata{ID: testID}, + containerstore.WithFakeStatus(test.status), + ) + assert.NoError(t, err) + err = setContainerRemoving(container) + if test.expectErr { + assert.Error(t, err) + assert.Equal(t, test.status, container.Status.Get(), "metadata should not be updated") + } else { + assert.NoError(t, err) + assert.True(t, container.Status.Get().Removing, "removing should be set") + assert.NoError(t, resetContainerRemoving(container)) + assert.False(t, container.Status.Get().Removing, "removing should be reset") + } + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_start.go containerd-1.5.9/pkg/cri/server/container_start.go --- containerd-1.2.6/pkg/cri/server/container_start.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_start.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,232 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io" + "time" + + "github.com/containerd/containerd" + containerdio "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/containerd/nri" + v1 "github.com/containerd/nri/types/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + cioutil "github.com/containerd/containerd/pkg/ioutil" +) + +// StartContainer starts the container. +func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (retRes *runtime.StartContainerResponse, retErr error) { + cntr, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) + } + + id := cntr.ID + meta := cntr.Metadata + container := cntr.Container + config := meta.Config + + // Set starting state to prevent other start/remove operations against this container + // while it's being started. + if err := setContainerStarting(cntr); err != nil { + return nil, errors.Wrapf(err, "failed to set starting state for container %q", id) + } + defer func() { + if retErr != nil { + // Set container to exited if fail to start. + if err := cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { + status.Pid = 0 + status.FinishedAt = time.Now().UnixNano() + status.ExitCode = errorStartExitCode + status.Reason = errorStartReason + status.Message = retErr.Error() + return status, nil + }); err != nil { + log.G(ctx).WithError(err).Errorf("failed to set start failure state for container %q", id) + } + } + if err := resetContainerStarting(cntr); err != nil { + log.G(ctx).WithError(err).Errorf("failed to reset starting state for container %q", id) + } + }() + + // Get sandbox config from sandbox store. + sandbox, err := c.sandboxStore.Get(meta.SandboxID) + if err != nil { + return nil, errors.Wrapf(err, "sandbox %q not found", meta.SandboxID) + } + sandboxID := meta.SandboxID + if sandbox.Status.Get().State != sandboxstore.StateReady { + return nil, errors.Errorf("sandbox container %q is not running", sandboxID) + } + + // Recheck target container validity in Linux namespace options. + if linux := config.GetLinux(); linux != nil { + nsOpts := linux.GetSecurityContext().GetNamespaceOptions() + if nsOpts.GetPid() == runtime.NamespaceMode_TARGET { + _, err := c.validateTargetContainer(sandboxID, nsOpts.TargetId) + if err != nil { + return nil, errors.Wrap(err, "invalid target container") + } + } + } + + ioCreation := func(id string) (_ containerdio.IO, err error) { + stdoutWC, stderrWC, err := c.createContainerLoggers(meta.LogPath, config.GetTty()) + if err != nil { + return nil, errors.Wrap(err, "failed to create container loggers") + } + cntr.IO.AddOutput("log", stdoutWC, stderrWC) + cntr.IO.Pipe() + return cntr.IO, nil + } + + ctrInfo, err := container.Info(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get container info") + } + + taskOpts := c.taskOpts(ctrInfo.Runtime.Name) + task, err := container.NewTask(ctx, ioCreation, taskOpts...) + if err != nil { + return nil, errors.Wrap(err, "failed to create containerd task") + } + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + // It's possible that task is deleted by event monitor. + if _, err := task.Delete(deferCtx, WithNRISandboxDelete(sandboxID), containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { + log.G(ctx).WithError(err).Errorf("Failed to delete containerd task %q", id) + } + } + }() + + // wait is a long running background request, no timeout needed. + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + if err != nil { + return nil, errors.Wrap(err, "failed to wait for containerd task") + } + nric, err := nri.New() + if err != nil { + log.G(ctx).WithError(err).Error("unable to create nri client") + } + if nric != nil { + nriSB := &nri.Sandbox{ + ID: sandboxID, + Labels: sandbox.Config.Labels, + } + if _, err := nric.InvokeWithSandbox(ctx, task, v1.Create, nriSB); err != nil { + return nil, errors.Wrap(err, "nri invoke") + } + } + + // Start containerd task. + if err := task.Start(ctx); err != nil { + return nil, errors.Wrapf(err, "failed to start containerd task %q", id) + } + + // Update container start timestamp. + if err := cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { + status.Pid = task.Pid() + status.StartedAt = time.Now().UnixNano() + return status, nil + }); err != nil { + return nil, errors.Wrapf(err, "failed to update container %q state", id) + } + + // It handles the TaskExit event and update container state after this. + c.eventMonitor.startContainerExitMonitor(context.Background(), id, task.Pid(), exitCh) + + return &runtime.StartContainerResponse{}, nil +} + +// setContainerStarting sets the container into starting state. In starting state, the +// container will not be removed or started again. +func setContainerStarting(container containerstore.Container) error { + return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + // Return error if container is not in created state. + if status.State() != runtime.ContainerState_CONTAINER_CREATED { + return status, errors.Errorf("container is in %s state", criContainerStateToString(status.State())) + } + // Do not start the container when there is a removal in progress. + if status.Removing { + return status, errors.New("container is in removing state, can't be started") + } + if status.Starting { + return status, errors.New("container is already in starting state") + } + status.Starting = true + return status, nil + }) +} + +// resetContainerStarting resets the container starting state on start failure. So +// that we could remove the container later. +func resetContainerStarting(container containerstore.Container) error { + return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + status.Starting = false + return status, nil + }) +} + +// createContainerLoggers creates container loggers and return write closer for stdout and stderr. +func (c *criService) createContainerLoggers(logPath string, tty bool) (stdout io.WriteCloser, stderr io.WriteCloser, err error) { + if logPath != "" { + // Only generate container log when log path is specified. + f, err := openLogFile(logPath) + if err != nil { + return nil, nil, errors.Wrap(err, "failed to create and open log file") + } + defer func() { + if err != nil { + f.Close() + } + }() + var stdoutCh, stderrCh <-chan struct{} + wc := cioutil.NewSerialWriteCloser(f) + stdout, stdoutCh = cio.NewCRILogger(logPath, wc, cio.Stdout, c.config.MaxContainerLogLineSize) + // Only redirect stderr when there is no tty. + if !tty { + stderr, stderrCh = cio.NewCRILogger(logPath, wc, cio.Stderr, c.config.MaxContainerLogLineSize) + } + go func() { + if stdoutCh != nil { + <-stdoutCh + } + if stderrCh != nil { + <-stderrCh + } + logrus.Debugf("Finish redirecting log file %q, closing it", logPath) + f.Close() + }() + } else { + stdout = cio.NewDiscardLogger() + stderr = cio.NewDiscardLogger() + } + return +} diff -Nru containerd-1.2.6/pkg/cri/server/container_start_test.go containerd-1.5.9/pkg/cri/server/container_start_test.go --- containerd-1.2.6/pkg/cri/server/container_start_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_start_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,98 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// TestSetContainerStarting tests setContainerStarting sets removing +// state correctly. +func TestSetContainerStarting(t *testing.T) { + testID := "test-id" + for desc, test := range map[string]struct { + status containerstore.Status + expectErr bool + }{ + + "should not return error when container is in created state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + }, + expectErr: false, + }, + "should return error when container is in running state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + }, + expectErr: true, + }, + "should return error when container is in exited state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + }, + expectErr: true, + }, + "should return error when container is in unknown state": { + status: containerstore.Status{ + CreatedAt: 0, + StartedAt: 0, + FinishedAt: 0, + }, + expectErr: true, + }, + "should return error when container is in starting state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + Starting: true, + }, + expectErr: true, + }, + "should return error when container is in removing state": { + status: containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + Removing: true, + }, + expectErr: true, + }, + } { + t.Logf("TestCase %q", desc) + container, err := containerstore.NewContainer( + containerstore.Metadata{ID: testID}, + containerstore.WithFakeStatus(test.status), + ) + assert.NoError(t, err) + err = setContainerStarting(container) + if test.expectErr { + assert.Error(t, err) + assert.Equal(t, test.status, container.Status.Get(), "metadata should not be updated") + } else { + assert.NoError(t, err) + assert.True(t, container.Status.Get().Starting, "starting should be set") + assert.NoError(t, resetContainerStarting(container)) + assert.False(t, container.Status.Get().Starting, "starting should be reset") + } + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats.go containerd-1.5.9/pkg/cri/server/container_stats.go --- containerd-1.2.6/pkg/cri/server/container_stats.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + tasks "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// ContainerStats returns stats of the container. If the container does not +// exist, the call returns an error. +func (c *criService) ContainerStats(ctx context.Context, in *runtime.ContainerStatsRequest) (*runtime.ContainerStatsResponse, error) { + cntr, err := c.containerStore.Get(in.GetContainerId()) + if err != nil { + return nil, errors.Wrap(err, "failed to find container") + } + request := &tasks.MetricsRequest{Filters: []string{"id==" + cntr.ID}} + resp, err := c.client.TaskService().Metrics(ctx, request) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch metrics for task") + } + if len(resp.Metrics) != 1 { + return nil, errors.Errorf("unexpected metrics response: %+v", resp.Metrics) + } + + cs, err := c.containerMetrics(cntr.Metadata, resp.Metrics[0]) + if err != nil { + return nil, errors.Wrap(err, "failed to decode container metrics") + } + return &runtime.ContainerStatsResponse{Stats: cs}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats_list.go containerd-1.5.9/pkg/cri/server/container_stats_list.go --- containerd-1.2.6/pkg/cri/server/container_stats_list.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats_list.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,116 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + tasks "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/api/types" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// ListContainerStats returns stats of all running containers. +func (c *criService) ListContainerStats( + ctx context.Context, + in *runtime.ListContainerStatsRequest, +) (*runtime.ListContainerStatsResponse, error) { + request, containers, err := c.buildTaskMetricsRequest(in) + if err != nil { + return nil, errors.Wrap(err, "failed to build metrics request") + } + resp, err := c.client.TaskService().Metrics(ctx, &request) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch metrics for tasks") + } + criStats, err := c.toCRIContainerStats(resp.Metrics, containers) + if err != nil { + return nil, errors.Wrap(err, "failed to convert to cri containerd stats format") + } + return criStats, nil +} + +func (c *criService) toCRIContainerStats( + stats []*types.Metric, + containers []containerstore.Container, +) (*runtime.ListContainerStatsResponse, error) { + statsMap := make(map[string]*types.Metric) + for _, stat := range stats { + statsMap[stat.ID] = stat + } + containerStats := new(runtime.ListContainerStatsResponse) + for _, cntr := range containers { + cs, err := c.containerMetrics(cntr.Metadata, statsMap[cntr.ID]) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode container metrics for %q", cntr.ID) + } + containerStats.Stats = append(containerStats.Stats, cs) + } + return containerStats, nil +} + +func (c *criService) normalizeContainerStatsFilter(filter *runtime.ContainerStatsFilter) { + if cntr, err := c.containerStore.Get(filter.GetId()); err == nil { + filter.Id = cntr.ID + } + if sb, err := c.sandboxStore.Get(filter.GetPodSandboxId()); err == nil { + filter.PodSandboxId = sb.ID + } +} + +// buildTaskMetricsRequest constructs a tasks.MetricsRequest based on +// the information in the stats request and the containerStore +func (c *criService) buildTaskMetricsRequest( + r *runtime.ListContainerStatsRequest, +) (tasks.MetricsRequest, []containerstore.Container, error) { + var req tasks.MetricsRequest + if r.GetFilter() == nil { + return req, nil, nil + } + c.normalizeContainerStatsFilter(r.GetFilter()) + var containers []containerstore.Container + for _, cntr := range c.containerStore.List() { + if r.GetFilter().GetId() != "" && cntr.ID != r.GetFilter().GetId() { + continue + } + if r.GetFilter().GetPodSandboxId() != "" && cntr.SandboxID != r.GetFilter().GetPodSandboxId() { + continue + } + if r.GetFilter().GetLabelSelector() != nil && + !matchLabelSelector(r.GetFilter().GetLabelSelector(), cntr.Config.GetLabels()) { + continue + } + containers = append(containers, cntr) + req.Filters = append(req.Filters, "id=="+cntr.ID) + } + return req, containers, nil +} + +func matchLabelSelector(selector, labels map[string]string) bool { + for k, v := range selector { + if val, ok := labels[k]; ok { + if v != val { + return false + } + } else { + return false + } + } + return true +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats_list_linux.go containerd-1.5.9/pkg/cri/server/container_stats_list_linux.go --- containerd-1.2.6/pkg/cri/server/container_stats_list_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats_list_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,125 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/api/types" + v1 "github.com/containerd/containerd/metrics/types/v1" + v2 "github.com/containerd/containerd/metrics/types/v2" + "github.com/containerd/typeurl" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +func (c *criService) containerMetrics( + meta containerstore.Metadata, + stats *types.Metric, +) (*runtime.ContainerStats, error) { + var cs runtime.ContainerStats + var usedBytes, inodesUsed uint64 + sn, err := c.snapshotStore.Get(meta.ID) + // If snapshotstore doesn't have cached snapshot information + // set WritableLayer usage to zero + if err == nil { + usedBytes = sn.Size + inodesUsed = sn.Inodes + } + cs.WritableLayer = &runtime.FilesystemUsage{ + Timestamp: sn.Timestamp, + FsId: &runtime.FilesystemIdentifier{ + Mountpoint: c.imageFSPath, + }, + UsedBytes: &runtime.UInt64Value{Value: usedBytes}, + InodesUsed: &runtime.UInt64Value{Value: inodesUsed}, + } + cs.Attributes = &runtime.ContainerAttributes{ + Id: meta.ID, + Metadata: meta.Config.GetMetadata(), + Labels: meta.Config.GetLabels(), + Annotations: meta.Config.GetAnnotations(), + } + + if stats != nil { + s, err := typeurl.UnmarshalAny(stats.Data) + if err != nil { + return nil, errors.Wrap(err, "failed to extract container metrics") + } + switch metrics := s.(type) { + case *v1.Metrics: + if metrics.CPU != nil && metrics.CPU.Usage != nil { + cs.Cpu = &runtime.CpuUsage{ + Timestamp: stats.Timestamp.UnixNano(), + UsageCoreNanoSeconds: &runtime.UInt64Value{Value: metrics.CPU.Usage.Total}, + } + } + if metrics.Memory != nil && metrics.Memory.Usage != nil { + cs.Memory = &runtime.MemoryUsage{ + Timestamp: stats.Timestamp.UnixNano(), + WorkingSetBytes: &runtime.UInt64Value{ + Value: getWorkingSet(metrics.Memory), + }, + } + } + case *v2.Metrics: + if metrics.CPU != nil { + cs.Cpu = &runtime.CpuUsage{ + Timestamp: stats.Timestamp.UnixNano(), + UsageCoreNanoSeconds: &runtime.UInt64Value{Value: metrics.CPU.UsageUsec * 1000}, + } + } + if metrics.Memory != nil { + cs.Memory = &runtime.MemoryUsage{ + Timestamp: stats.Timestamp.UnixNano(), + WorkingSetBytes: &runtime.UInt64Value{ + Value: getWorkingSetV2(metrics.Memory), + }, + } + } + default: + return &cs, errors.Errorf("unexpected metrics type: %v", metrics) + } + } + + return &cs, nil +} + +// getWorkingSet calculates workingset memory from cgroup memory stats. +// The caller should make sure memory is not nil. +// workingset = usage - total_inactive_file +func getWorkingSet(memory *v1.MemoryStat) uint64 { + if memory.Usage == nil { + return 0 + } + var workingSet uint64 + if memory.TotalInactiveFile < memory.Usage.Usage { + workingSet = memory.Usage.Usage - memory.TotalInactiveFile + } + return workingSet +} + +// getWorkingSetV2 calculates workingset memory from cgroupv2 memory stats. +// The caller should make sure memory is not nil. +// workingset = usage - inactive_file +func getWorkingSetV2(memory *v2.MemoryStat) uint64 { + var workingSet uint64 + if memory.InactiveFile < memory.Usage { + workingSet = memory.Usage - memory.InactiveFile + } + return workingSet +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats_list_linux_test.go containerd-1.5.9/pkg/cri/server/container_stats_list_linux_test.go --- containerd-1.2.6/pkg/cri/server/container_stats_list_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats_list_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + v1 "github.com/containerd/cgroups/stats/v1" + "github.com/stretchr/testify/assert" +) + +func TestGetWorkingSet(t *testing.T) { + for desc, test := range map[string]struct { + memory *v1.MemoryStat + expected uint64 + }{ + "nil memory usage": { + memory: &v1.MemoryStat{}, + expected: 0, + }, + "memory usage higher than inactive_total_file": { + memory: &v1.MemoryStat{ + TotalInactiveFile: 1000, + Usage: &v1.MemoryEntry{Usage: 2000}, + }, + expected: 1000, + }, + "memory usage lower than inactive_total_file": { + memory: &v1.MemoryStat{ + TotalInactiveFile: 2000, + Usage: &v1.MemoryEntry{Usage: 1000}, + }, + expected: 0, + }, + } { + t.Run(desc, func(t *testing.T) { + got := getWorkingSet(test.memory) + assert.Equal(t, test.expected, got) + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats_list_other.go containerd-1.5.9/pkg/cri/server/container_stats_list_other.go --- containerd-1.2.6/pkg/cri/server/container_stats_list_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats_list_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +func (c *criService) containerMetrics( + meta containerstore.Metadata, + stats *types.Metric, +) (*runtime.ContainerStats, error) { + var cs runtime.ContainerStats + return &cs, errors.Wrap(errdefs.ErrNotImplemented, "container metrics") +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stats_list_windows.go containerd-1.5.9/pkg/cri/server/container_stats_list_windows.go --- containerd-1.2.6/pkg/cri/server/container_stats_list_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stats_list_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + wstats "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats" + "github.com/containerd/containerd/api/types" + "github.com/containerd/typeurl" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +func (c *criService) containerMetrics( + meta containerstore.Metadata, + stats *types.Metric, +) (*runtime.ContainerStats, error) { + var cs runtime.ContainerStats + var usedBytes, inodesUsed uint64 + sn, err := c.snapshotStore.Get(meta.ID) + // If snapshotstore doesn't have cached snapshot information + // set WritableLayer usage to zero + if err == nil { + usedBytes = sn.Size + inodesUsed = sn.Inodes + } + cs.WritableLayer = &runtime.FilesystemUsage{ + Timestamp: sn.Timestamp, + FsId: &runtime.FilesystemIdentifier{ + Mountpoint: c.imageFSPath, + }, + UsedBytes: &runtime.UInt64Value{Value: usedBytes}, + InodesUsed: &runtime.UInt64Value{Value: inodesUsed}, + } + cs.Attributes = &runtime.ContainerAttributes{ + Id: meta.ID, + Metadata: meta.Config.GetMetadata(), + Labels: meta.Config.GetLabels(), + Annotations: meta.Config.GetAnnotations(), + } + + if stats != nil { + s, err := typeurl.UnmarshalAny(stats.Data) + if err != nil { + return nil, errors.Wrap(err, "failed to extract container metrics") + } + wstats := s.(*wstats.Statistics).GetWindows() + if wstats == nil { + return nil, errors.New("windows stats is empty") + } + if wstats.Processor != nil { + cs.Cpu = &runtime.CpuUsage{ + Timestamp: wstats.Timestamp.UnixNano(), + UsageCoreNanoSeconds: &runtime.UInt64Value{Value: wstats.Processor.TotalRuntimeNS}, + } + } + if wstats.Memory != nil { + cs.Memory = &runtime.MemoryUsage{ + Timestamp: wstats.Timestamp.UnixNano(), + WorkingSetBytes: &runtime.UInt64Value{ + Value: wstats.Memory.MemoryUsagePrivateWorkingSetBytes, + }, + } + } + } + return &cs, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_status.go containerd-1.5.9/pkg/cri/server/container_status.go --- containerd-1.2.6/pkg/cri/server/container_status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,183 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// ContainerStatus inspects the container and returns the status. +func (c *criService) ContainerStatus(ctx context.Context, r *runtime.ContainerStatusRequest) (*runtime.ContainerStatusResponse, error) { + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) + } + + // TODO(random-liu): Clean up the following logic in CRI. + // Current assumption: + // * ImageSpec in container config is image ID. + // * ImageSpec in container status is image tag. + // * ImageRef in container status is repo digest. + spec := container.Config.GetImage() + imageRef := container.ImageRef + image, err := c.imageStore.Get(imageRef) + if err != nil { + if err != store.ErrNotExist { + return nil, errors.Wrapf(err, "failed to get image %q", imageRef) + } + } else { + repoTags, repoDigests := parseImageReferences(image.References) + if len(repoTags) > 0 { + // Based on current behavior of dockershim, this field should be + // image tag. + spec = &runtime.ImageSpec{Image: repoTags[0]} + } + if len(repoDigests) > 0 { + // Based on the CRI definition, this field will be consumed by user. + imageRef = repoDigests[0] + } + } + status := toCRIContainerStatus(container, spec, imageRef) + if status.GetCreatedAt() == 0 { + // CRI doesn't allow CreatedAt == 0. + info, err := container.Container.Info(ctx) + if err != nil { + return nil, errors.Wrapf(err, "failed to get CreatedAt in %q state", status.State) + } + status.CreatedAt = info.CreatedAt.UnixNano() + } + + info, err := toCRIContainerInfo(ctx, container, r.GetVerbose()) + if err != nil { + return nil, errors.Wrap(err, "failed to get verbose container info") + } + + return &runtime.ContainerStatusResponse{ + Status: status, + Info: info, + }, nil +} + +// toCRIContainerStatus converts internal container object to CRI container status. +func toCRIContainerStatus(container containerstore.Container, spec *runtime.ImageSpec, imageRef string) *runtime.ContainerStatus { + meta := container.Metadata + status := container.Status.Get() + reason := status.Reason + if status.State() == runtime.ContainerState_CONTAINER_EXITED && reason == "" { + if status.ExitCode == 0 { + reason = completeExitReason + } else { + reason = errorExitReason + } + } + + // If container is in the created state, not set started and finished unix timestamps + var st, ft int64 + switch status.State() { + case runtime.ContainerState_CONTAINER_RUNNING: + // If container is in the running state, set started unix timestamps + st = status.StartedAt + case runtime.ContainerState_CONTAINER_EXITED, runtime.ContainerState_CONTAINER_UNKNOWN: + st, ft = status.StartedAt, status.FinishedAt + } + + return &runtime.ContainerStatus{ + Id: meta.ID, + Metadata: meta.Config.GetMetadata(), + State: status.State(), + CreatedAt: status.CreatedAt, + StartedAt: st, + FinishedAt: ft, + ExitCode: status.ExitCode, + Image: spec, + ImageRef: imageRef, + Reason: reason, + Message: status.Message, + Labels: meta.Config.GetLabels(), + Annotations: meta.Config.GetAnnotations(), + Mounts: meta.Config.GetMounts(), + LogPath: meta.LogPath, + } +} + +// ContainerInfo is extra information for a container. +type ContainerInfo struct { + // TODO(random-liu): Add sandboxID in CRI container status. + SandboxID string `json:"sandboxID"` + Pid uint32 `json:"pid"` + Removing bool `json:"removing"` + SnapshotKey string `json:"snapshotKey"` + Snapshotter string `json:"snapshotter"` + RuntimeType string `json:"runtimeType"` + RuntimeOptions interface{} `json:"runtimeOptions"` + Config *runtime.ContainerConfig `json:"config"` + RuntimeSpec *runtimespec.Spec `json:"runtimeSpec"` +} + +// toCRIContainerInfo converts internal container object information to CRI container status response info map. +func toCRIContainerInfo(ctx context.Context, container containerstore.Container, verbose bool) (map[string]string, error) { + if !verbose { + return nil, nil + } + + meta := container.Metadata + status := container.Status.Get() + + // TODO(random-liu): Change CRI status info to use array instead of map. + ci := &ContainerInfo{ + SandboxID: container.SandboxID, + Pid: status.Pid, + Removing: status.Removing, + Config: meta.Config, + } + + var err error + ci.RuntimeSpec, err = container.Container.Spec(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get container runtime spec") + } + + ctrInfo, err := container.Container.Info(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get container info") + } + ci.SnapshotKey = ctrInfo.SnapshotKey + ci.Snapshotter = ctrInfo.Snapshotter + + runtimeOptions, err := getRuntimeOptions(ctrInfo) + if err != nil { + return nil, errors.Wrap(err, "failed to get runtime options") + } + ci.RuntimeType = ctrInfo.Runtime.Name + ci.RuntimeOptions = runtimeOptions + + infoBytes, err := json.Marshal(ci) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal info %v", ci) + } + return map[string]string{ + "info": string(infoBytes), + }, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_status_test.go containerd-1.5.9/pkg/cri/server/container_status_test.go --- containerd-1.2.6/pkg/cri/server/container_status_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_status_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,254 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" +) + +func getContainerStatusTestData() (*containerstore.Metadata, *containerstore.Status, + *imagestore.Image, *runtime.ContainerStatus) { + imageID := "sha256:1123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + testID := "test-id" + config := &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + Image: &runtime.ImageSpec{Image: "test-image"}, + Mounts: []*runtime.Mount{{ + ContainerPath: "test-container-path", + HostPath: "test-host-path", + }}, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + } + + createdAt := time.Now().UnixNano() + + metadata := &containerstore.Metadata{ + ID: testID, + Name: "test-long-name", + SandboxID: "test-sandbox-id", + Config: config, + ImageRef: imageID, + LogPath: "test-log-path", + } + status := &containerstore.Status{ + Pid: 1234, + CreatedAt: createdAt, + } + image := &imagestore.Image{ + ID: imageID, + References: []string{ + "gcr.io/library/busybox:latest", + "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + } + expected := &runtime.ContainerStatus{ + Id: testID, + Metadata: config.GetMetadata(), + State: runtime.ContainerState_CONTAINER_CREATED, + CreatedAt: createdAt, + Image: &runtime.ImageSpec{Image: "gcr.io/library/busybox:latest"}, + ImageRef: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + Reason: completeExitReason, + Labels: config.GetLabels(), + Annotations: config.GetAnnotations(), + Mounts: config.GetMounts(), + LogPath: "test-log-path", + } + + return metadata, status, image, expected +} + +func TestToCRIContainerStatus(t *testing.T) { + for desc, test := range map[string]struct { + startedAt int64 + finishedAt int64 + exitCode int32 + reason string + message string + expectedState runtime.ContainerState + expectedReason string + }{ + "container created": { + expectedState: runtime.ContainerState_CONTAINER_CREATED, + }, + "container running": { + startedAt: time.Now().UnixNano(), + expectedState: runtime.ContainerState_CONTAINER_RUNNING, + }, + "container exited with reason": { + startedAt: time.Now().UnixNano(), + finishedAt: time.Now().UnixNano(), + exitCode: 1, + reason: "test-reason", + message: "test-message", + expectedState: runtime.ContainerState_CONTAINER_EXITED, + expectedReason: "test-reason", + }, + "container exited with exit code 0 without reason": { + startedAt: time.Now().UnixNano(), + finishedAt: time.Now().UnixNano(), + exitCode: 0, + message: "test-message", + expectedState: runtime.ContainerState_CONTAINER_EXITED, + expectedReason: completeExitReason, + }, + "container exited with non-zero exit code without reason": { + startedAt: time.Now().UnixNano(), + finishedAt: time.Now().UnixNano(), + exitCode: 1, + message: "test-message", + expectedState: runtime.ContainerState_CONTAINER_EXITED, + expectedReason: errorExitReason, + }, + } { + metadata, status, _, expected := getContainerStatusTestData() + // Update status with test case. + status.StartedAt = test.startedAt + status.FinishedAt = test.finishedAt + status.ExitCode = test.exitCode + status.Reason = test.reason + status.Message = test.message + container, err := containerstore.NewContainer( + *metadata, + containerstore.WithFakeStatus(*status), + ) + assert.NoError(t, err) + // Set expectation based on test case. + expected.Reason = test.expectedReason + expected.StartedAt = test.startedAt + expected.FinishedAt = test.finishedAt + expected.ExitCode = test.exitCode + expected.Message = test.message + patchExceptedWithState(expected, test.expectedState) + containerStatus := toCRIContainerStatus(container, + expected.Image, + expected.ImageRef) + assert.Equal(t, expected, containerStatus, desc) + } +} + +// TODO(mikebrow): add a fake containerd container.Container.Spec client api so we can test verbose is true option +func TestToCRIContainerInfo(t *testing.T) { + metadata, status, _, _ := getContainerStatusTestData() + container, err := containerstore.NewContainer( + *metadata, + containerstore.WithFakeStatus(*status), + ) + assert.NoError(t, err) + + info, err := toCRIContainerInfo(context.Background(), + container, + false) + assert.NoError(t, err) + assert.Nil(t, info) +} + +func TestContainerStatus(t *testing.T) { + for desc, test := range map[string]struct { + exist bool + imageExist bool + startedAt int64 + finishedAt int64 + reason string + expectedState runtime.ContainerState + expectErr bool + }{ + "container created": { + exist: true, + imageExist: true, + expectedState: runtime.ContainerState_CONTAINER_CREATED, + }, + "container running": { + exist: true, + imageExist: true, + startedAt: time.Now().UnixNano(), + expectedState: runtime.ContainerState_CONTAINER_RUNNING, + }, + "container exited": { + exist: true, + imageExist: true, + startedAt: time.Now().UnixNano(), + finishedAt: time.Now().UnixNano(), + reason: "test-reason", + expectedState: runtime.ContainerState_CONTAINER_EXITED, + }, + "container not exist": { + exist: false, + imageExist: true, + expectErr: true, + }, + "image not exist": { + exist: false, + imageExist: false, + expectErr: true, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + metadata, status, image, expected := getContainerStatusTestData() + // Update status with test case. + status.StartedAt = test.startedAt + status.FinishedAt = test.finishedAt + status.Reason = test.reason + container, err := containerstore.NewContainer( + *metadata, + containerstore.WithFakeStatus(*status), + ) + assert.NoError(t, err) + if test.exist { + assert.NoError(t, c.containerStore.Add(container)) + } + if test.imageExist { + c.imageStore, err = imagestore.NewFakeStore([]imagestore.Image{*image}) + assert.NoError(t, err) + } + resp, err := c.ContainerStatus(context.Background(), &runtime.ContainerStatusRequest{ContainerId: container.ID}) + if test.expectErr { + assert.Error(t, err) + assert.Nil(t, resp) + continue + } + // Set expectation based on test case. + expected.StartedAt = test.startedAt + expected.FinishedAt = test.finishedAt + expected.Reason = test.reason + patchExceptedWithState(expected, test.expectedState) + assert.Equal(t, expected, resp.GetStatus()) + } +} + +func patchExceptedWithState(expected *runtime.ContainerStatus, state runtime.ContainerState) { + expected.State = state + switch state { + case runtime.ContainerState_CONTAINER_CREATED: + expected.StartedAt, expected.FinishedAt = 0, 0 + case runtime.ContainerState_CONTAINER_RUNNING: + expected.FinishedAt = 0 + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stop.go containerd-1.5.9/pkg/cri/server/container_stop.go --- containerd-1.2.6/pkg/cri/server/container_stop.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stop.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,200 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "sync/atomic" + "syscall" + "time" + + "github.com/containerd/containerd" + eventtypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +// StopContainer stops a running container with a grace period (i.e., timeout). +func (c *criService) StopContainer(ctx context.Context, r *runtime.StopContainerRequest) (*runtime.StopContainerResponse, error) { + // Get container config from container store. + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) + } + + if err := c.stopContainer(ctx, container, time.Duration(r.GetTimeout())*time.Second); err != nil { + return nil, err + } + + return &runtime.StopContainerResponse{}, nil +} + +// stopContainer stops a container based on the container metadata. +func (c *criService) stopContainer(ctx context.Context, container containerstore.Container, timeout time.Duration) error { + id := container.ID + + // Return without error if container is not running. This makes sure that + // stop only takes real action after the container is started. + state := container.Status.Get().State() + if state != runtime.ContainerState_CONTAINER_RUNNING && + state != runtime.ContainerState_CONTAINER_UNKNOWN { + log.G(ctx).Infof("Container to stop %q must be in running or unknown state, current state %q", + id, criContainerStateToString(state)) + return nil + } + + task, err := container.Container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to get task for container %q", id) + } + // Don't return for unknown state, some cleanup needs to be done. + if state == runtime.ContainerState_CONTAINER_UNKNOWN { + return cleanupUnknownContainer(ctx, id, container) + } + return nil + } + + // Handle unknown state. + if state == runtime.ContainerState_CONTAINER_UNKNOWN { + // Start an exit handler for containers in unknown state. + waitCtx, waitCancel := context.WithCancel(ctrdutil.NamespacedContext()) + defer waitCancel() + exitCh, err := task.Wait(waitCtx) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to wait for task for %q", id) + } + return cleanupUnknownContainer(ctx, id, container) + } + + exitCtx, exitCancel := context.WithCancel(context.Background()) + stopCh := c.eventMonitor.startContainerExitMonitor(exitCtx, id, task.Pid(), exitCh) + defer func() { + exitCancel() + // This ensures that exit monitor is stopped before + // `Wait` is cancelled, so no exit event is generated + // because of the `Wait` cancellation. + <-stopCh + }() + } + + // We only need to kill the task. The event handler will Delete the + // task from containerd after it handles the Exited event. + if timeout > 0 { + stopSignal := "SIGTERM" + if container.StopSignal != "" { + stopSignal = container.StopSignal + } else { + // The image may have been deleted, and the `StopSignal` field is + // just introduced to handle that. + // However, for containers created before the `StopSignal` field is + // introduced, still try to get the stop signal from the image config. + // If the image has been deleted, logging an error and using the + // default SIGTERM is still better than returning error and leaving + // the container unstoppable. (See issue #990) + // TODO(random-liu): Remove this logic when containerd 1.2 is deprecated. + image, err := c.imageStore.Get(container.ImageRef) + if err != nil { + if err != store.ErrNotExist { + return errors.Wrapf(err, "failed to get image %q", container.ImageRef) + } + log.G(ctx).Warningf("Image %q not found, stop container with signal %q", container.ImageRef, stopSignal) + } else { + if image.ImageSpec.Config.StopSignal != "" { + stopSignal = image.ImageSpec.Config.StopSignal + } + } + } + sig, err := containerd.ParseSignal(stopSignal) + if err != nil { + return errors.Wrapf(err, "failed to parse stop signal %q", stopSignal) + } + + var sswt bool + if container.IsStopSignaledWithTimeout == nil { + log.G(ctx).Infof("unable to ensure stop signal %v was not sent twice to container %v", sig, id) + sswt = true + } else { + sswt = atomic.CompareAndSwapUint32(container.IsStopSignaledWithTimeout, 0, 1) + } + + if sswt { + log.G(ctx).Infof("Stop container %q with signal %v", id, sig) + if err = task.Kill(ctx, sig); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to stop container %q", id) + } + } else { + log.G(ctx).Infof("Skipping the sending of signal %v to container %q because a prior stop with timeout>0 request already sent the signal", sig, id) + } + + sigTermCtx, sigTermCtxCancel := context.WithTimeout(ctx, timeout) + defer sigTermCtxCancel() + err = c.waitContainerStop(sigTermCtx, container) + if err == nil { + // Container stopped on first signal no need for SIGKILL + return nil + } + // If the parent context was cancelled or exceeded return immediately + if ctx.Err() != nil { + return ctx.Err() + } + // sigTermCtx was exceeded. Send SIGKILL + log.G(ctx).Debugf("Stop container %q with signal %v timed out", id, sig) + } + + log.G(ctx).Infof("Kill container %q", id) + if err = task.Kill(ctx, syscall.SIGKILL); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to kill container %q", id) + } + + // Wait for a fixed timeout until container stop is observed by event monitor. + err = c.waitContainerStop(ctx, container) + if err != nil { + return errors.Wrapf(err, "an error occurs during waiting for container %q to be killed", id) + } + return nil +} + +// waitContainerStop waits for container to be stopped until context is +// cancelled or the context deadline is exceeded. +func (c *criService) waitContainerStop(ctx context.Context, container containerstore.Container) error { + select { + case <-ctx.Done(): + return errors.Wrapf(ctx.Err(), "wait container %q", container.ID) + case <-container.Stopped(): + return nil + } +} + +// cleanupUnknownContainer cleanup stopped container in unknown state. +func cleanupUnknownContainer(ctx context.Context, id string, cntr containerstore.Container) error { + // Reuse handleContainerExit to do the cleanup. + return handleContainerExit(ctx, &eventtypes.TaskExit{ + ContainerID: id, + ID: id, + Pid: 0, + ExitStatus: unknownExitCode, + ExitedAt: time.Now(), + }, cntr) +} diff -Nru containerd-1.2.6/pkg/cri/server/container_stop_test.go containerd-1.5.9/pkg/cri/server/container_stop_test.go --- containerd-1.2.6/pkg/cri/server/container_stop_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_stop_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,85 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +func TestWaitContainerStop(t *testing.T) { + id := "test-id" + for desc, test := range map[string]struct { + status *containerstore.Status + cancel bool + timeout time.Duration + expectErr bool + }{ + "should return error if timeout exceeds": { + status: &containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + }, + timeout: 200 * time.Millisecond, + expectErr: true, + }, + "should return error if context is cancelled": { + status: &containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + }, + timeout: time.Hour, + cancel: true, + expectErr: true, + }, + "should not return error if container is stopped before timeout": { + status: &containerstore.Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + }, + timeout: time.Hour, + expectErr: false, + }, + } { + c := newTestCRIService() + container, err := containerstore.NewContainer( + containerstore.Metadata{ID: id}, + containerstore.WithFakeStatus(*test.status), + ) + assert.NoError(t, err) + assert.NoError(t, c.containerStore.Add(container)) + ctx := context.Background() + if test.cancel { + cancelledCtx, cancel := context.WithCancel(ctx) + cancel() + ctx = cancelledCtx + } + if test.timeout > 0 { + timeoutCtx, cancel := context.WithTimeout(ctx, test.timeout) + defer cancel() + ctx = timeoutCtx + } + err = c.waitContainerStop(ctx, container) + assert.Equal(t, test.expectErr, err != nil, desc) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_update_resources_linux.go containerd-1.5.9/pkg/cri/server/container_update_resources_linux.go --- containerd-1.2.6/pkg/cri/server/container_update_resources_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_update_resources_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,148 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + gocontext "context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/containerd/typeurl" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/opts" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + "github.com/containerd/containerd/pkg/cri/util" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +// UpdateContainerResources updates ContainerConfig of the container. +func (c *criService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (retRes *runtime.UpdateContainerResourcesResponse, retErr error) { + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrap(err, "failed to find container") + } + // Update resources in status update transaction, so that: + // 1) There won't be race condition with container start. + // 2) There won't be concurrent resource update to the same container. + if err := container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + return status, c.updateContainerResources(ctx, container, r.GetLinux(), status) + }); err != nil { + return nil, errors.Wrap(err, "failed to update resources") + } + return &runtime.UpdateContainerResourcesResponse{}, nil +} + +func (c *criService) updateContainerResources(ctx context.Context, + cntr containerstore.Container, + resources *runtime.LinuxContainerResources, + status containerstore.Status) (retErr error) { + id := cntr.ID + // Do not update the container when there is a removal in progress. + if status.Removing { + return errors.Errorf("container %q is in removing state", id) + } + + // Update container spec. If the container is not started yet, updating + // spec makes sure that the resource limits are correct when start; + // if the container is already started, updating spec is still required, + // the spec will become our source of truth for resource limits. + oldSpec, err := cntr.Container.Spec(ctx) + if err != nil { + return errors.Wrap(err, "failed to get container spec") + } + newSpec, err := updateOCILinuxResource(ctx, oldSpec, resources, + c.config.TolerateMissingHugetlbController, c.config.DisableHugetlbController) + if err != nil { + return errors.Wrap(err, "failed to update resource in spec") + } + + if err := updateContainerSpec(ctx, cntr.Container, newSpec); err != nil { + return err + } + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + // Reset spec on error. + if err := updateContainerSpec(deferCtx, cntr.Container, oldSpec); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to update spec %+v for container %q", oldSpec, id) + } + } + }() + + // If container is not running, only update spec is enough, new resource + // limit will be applied when container start. + if status.State() != runtime.ContainerState_CONTAINER_RUNNING { + return nil + } + + task, err := cntr.Container.Task(ctx, nil) + if err != nil { + if errdefs.IsNotFound(err) { + // Task exited already. + return nil + } + return errors.Wrap(err, "failed to get task") + } + // newSpec.Linux won't be nil + if err := task.Update(ctx, containerd.WithResources(newSpec.Linux.Resources)); err != nil { + if errdefs.IsNotFound(err) { + // Task exited already. + return nil + } + return errors.Wrap(err, "failed to update resources") + } + return nil +} + +// updateContainerSpec updates container spec. +func updateContainerSpec(ctx context.Context, cntr containerd.Container, spec *runtimespec.Spec) error { + any, err := typeurl.MarshalAny(spec) + if err != nil { + return errors.Wrapf(err, "failed to marshal spec %+v", spec) + } + if err := cntr.Update(ctx, func(ctx gocontext.Context, client *containerd.Client, c *containers.Container) error { + c.Spec = any + return nil + }); err != nil { + return errors.Wrap(err, "failed to update container spec") + } + return nil +} + +// updateOCILinuxResource updates container resource limit. +func updateOCILinuxResource(ctx context.Context, spec *runtimespec.Spec, new *runtime.LinuxContainerResources, + tolerateMissingHugetlbController, disableHugetlbController bool) (*runtimespec.Spec, error) { + // Copy to make sure old spec is not changed. + var cloned runtimespec.Spec + if err := util.DeepCopy(&cloned, spec); err != nil { + return nil, errors.Wrap(err, "failed to deep copy") + } + if cloned.Linux == nil { + cloned.Linux = &runtimespec.Linux{} + } + if err := opts.WithResources(new, tolerateMissingHugetlbController, disableHugetlbController)(ctx, nil, nil, &cloned); err != nil { + return nil, errors.Wrap(err, "unable to set linux container resources") + } + return &cloned, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_update_resources_linux_test.go containerd-1.5.9/pkg/cri/server/container_update_resources_linux_test.go --- containerd-1.2.6/pkg/cri/server/container_update_resources_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_update_resources_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,162 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "testing" + + "github.com/golang/protobuf/proto" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestUpdateOCILinuxResource(t *testing.T) { + oomscoreadj := new(int) + *oomscoreadj = -500 + for desc, test := range map[string]struct { + spec *runtimespec.Spec + resources *runtime.LinuxContainerResources + expected *runtimespec.Spec + expectErr bool + }{ + "should be able to update each resource": { + spec: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(12345)}, + CPU: &runtimespec.LinuxCPU{ + Shares: proto.Uint64(1111), + Quota: proto.Int64(2222), + Period: proto.Uint64(3333), + Cpus: "0-1", + Mems: "2-3", + }, + }, + }, + }, + resources: &runtime.LinuxContainerResources{ + CpuPeriod: 6666, + CpuQuota: 5555, + CpuShares: 4444, + MemoryLimitInBytes: 54321, + OomScoreAdj: 500, + CpusetCpus: "4-5", + CpusetMems: "6-7", + }, + expected: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(54321)}, + CPU: &runtimespec.LinuxCPU{ + Shares: proto.Uint64(4444), + Quota: proto.Int64(5555), + Period: proto.Uint64(6666), + Cpus: "4-5", + Mems: "6-7", + }, + }, + }, + }, + }, + "should skip empty fields": { + spec: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(12345)}, + CPU: &runtimespec.LinuxCPU{ + Shares: proto.Uint64(1111), + Quota: proto.Int64(2222), + Period: proto.Uint64(3333), + Cpus: "0-1", + Mems: "2-3", + }, + }, + }, + }, + resources: &runtime.LinuxContainerResources{ + CpuQuota: 5555, + CpuShares: 4444, + MemoryLimitInBytes: 54321, + OomScoreAdj: 500, + CpusetMems: "6-7", + }, + expected: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(54321)}, + CPU: &runtimespec.LinuxCPU{ + Shares: proto.Uint64(4444), + Quota: proto.Int64(5555), + Period: proto.Uint64(3333), + Cpus: "0-1", + Mems: "6-7", + }, + }, + }, + }, + }, + "should be able to fill empty fields": { + spec: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(12345)}, + }, + }, + }, + resources: &runtime.LinuxContainerResources{ + CpuPeriod: 6666, + CpuQuota: 5555, + CpuShares: 4444, + MemoryLimitInBytes: 54321, + OomScoreAdj: 500, + CpusetCpus: "4-5", + CpusetMems: "6-7", + }, + expected: &runtimespec.Spec{ + Process: &runtimespec.Process{OOMScoreAdj: oomscoreadj}, + Linux: &runtimespec.Linux{ + Resources: &runtimespec.LinuxResources{ + Memory: &runtimespec.LinuxMemory{Limit: proto.Int64(54321)}, + CPU: &runtimespec.LinuxCPU{ + Shares: proto.Uint64(4444), + Quota: proto.Int64(5555), + Period: proto.Uint64(6666), + Cpus: "4-5", + Mems: "6-7", + }, + }, + }, + }, + }, + } { + t.Logf("TestCase %q", desc) + got, err := updateOCILinuxResource(context.Background(), test.spec, test.resources, false, false) + if test.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, test.expected, got) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/container_update_resources_other.go containerd-1.5.9/pkg/cri/server/container_update_resources_other.go --- containerd-1.2.6/pkg/cri/server/container_update_resources_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_update_resources_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + containerstore "github.com/containerd/containerd/pkg/cri/store/container" +) + +// UpdateContainerResources updates ContainerConfig of the container. +func (c *criService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (retRes *runtime.UpdateContainerResourcesResponse, retErr error) { + container, err := c.containerStore.Get(r.GetContainerId()) + if err != nil { + return nil, errors.Wrap(err, "failed to find container") + } + // Update resources in status update transaction, so that: + // 1) There won't be race condition with container start. + // 2) There won't be concurrent resource update to the same container. + if err := container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { + return status, nil + }); err != nil { + return nil, errors.Wrap(err, "failed to update resources") + } + return &runtime.UpdateContainerResourcesResponse{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/container_update_resources_windows.go containerd-1.5.9/pkg/cri/server/container_update_resources_windows.go --- containerd-1.2.6/pkg/cri/server/container_update_resources_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/container_update_resources_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/errdefs" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// UpdateContainerResources updates ContainerConfig of the container. +// TODO(windows): Figure out whether windows support this. +func (c *criService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (*runtime.UpdateContainerResourcesResponse, error) { + return nil, errdefs.ErrNotImplemented +} diff -Nru containerd-1.2.6/pkg/cri/server/events.go containerd-1.5.9/pkg/cri/server/events.go --- containerd-1.2.6/pkg/cri/server/events.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/events.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,542 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "sync" + "time" + + "github.com/containerd/containerd" + eventtypes "github.com/containerd/containerd/api/events" + containerdio "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/events" + "github.com/containerd/typeurl" + gogotypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + "k8s.io/apimachinery/pkg/util/clock" + + "github.com/containerd/containerd/pkg/cri/constants" + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +const ( + backOffInitDuration = 1 * time.Second + backOffMaxDuration = 5 * time.Minute + backOffExpireCheckDuration = 1 * time.Second + + // handleEventTimeout is the timeout for handling 1 event. Event monitor + // handles events in serial, if one event blocks the event monitor, no + // other events can be handled. + // Add a timeout for each event handling, events that timeout will be requeued and + // handled again in the future. + handleEventTimeout = 10 * time.Second +) + +// eventMonitor monitors containerd event and updates internal state correspondingly. +type eventMonitor struct { + c *criService + ch <-chan *events.Envelope + errCh <-chan error + ctx context.Context + cancel context.CancelFunc + backOff *backOff +} + +type backOff struct { + // queuePoolMu is mutex used to protect the queuePool map + queuePoolMu sync.Mutex + + queuePool map[string]*backOffQueue + // tickerMu is mutex used to protect the ticker. + tickerMu sync.Mutex + ticker *time.Ticker + minDuration time.Duration + maxDuration time.Duration + checkDuration time.Duration + clock clock.Clock +} + +type backOffQueue struct { + events []interface{} + expireTime time.Time + duration time.Duration + clock clock.Clock +} + +// Create new event monitor. New event monitor will start subscribing containerd event. All events +// happen after it should be monitored. +func newEventMonitor(c *criService) *eventMonitor { + ctx, cancel := context.WithCancel(context.Background()) + return &eventMonitor{ + c: c, + ctx: ctx, + cancel: cancel, + backOff: newBackOff(), + } +} + +// subscribe starts to subscribe containerd events. +func (em *eventMonitor) subscribe(subscriber events.Subscriber) { + // note: filters are any match, if you want any match but not in namespace foo + // then you have to manually filter namespace foo + filters := []string{ + `topic=="/tasks/oom"`, + `topic~="/images/"`, + } + em.ch, em.errCh = subscriber.Subscribe(em.ctx, filters...) +} + +// startSandboxExitMonitor starts an exit monitor for a given sandbox. +func (em *eventMonitor) startSandboxExitMonitor(ctx context.Context, id string, pid uint32, exitCh <-chan containerd.ExitStatus) <-chan struct{} { + stopCh := make(chan struct{}) + go func() { + defer close(stopCh) + select { + case exitRes := <-exitCh: + exitStatus, exitedAt, err := exitRes.Result() + if err != nil { + logrus.WithError(err).Errorf("failed to get task exit status for %q", id) + exitStatus = unknownExitCode + exitedAt = time.Now() + } + + e := &eventtypes.TaskExit{ + ContainerID: id, + ID: id, + Pid: pid, + ExitStatus: exitStatus, + ExitedAt: exitedAt, + } + + logrus.Debugf("received exit event %+v", e) + + err = func() error { + dctx := ctrdutil.NamespacedContext() + dctx, dcancel := context.WithTimeout(dctx, handleEventTimeout) + defer dcancel() + + sb, err := em.c.sandboxStore.Get(e.ID) + if err == nil { + if err := handleSandboxExit(dctx, e, sb); err != nil { + return err + } + return nil + } else if err != store.ErrNotExist { + return errors.Wrapf(err, "failed to get sandbox %s", e.ID) + } + return nil + }() + if err != nil { + logrus.WithError(err).Errorf("failed to handle sandbox TaskExit event %+v", e) + em.backOff.enBackOff(id, e) + } + return + case <-ctx.Done(): + } + }() + return stopCh +} + +// startContainerExitMonitor starts an exit monitor for a given container. +func (em *eventMonitor) startContainerExitMonitor(ctx context.Context, id string, pid uint32, exitCh <-chan containerd.ExitStatus) <-chan struct{} { + stopCh := make(chan struct{}) + go func() { + defer close(stopCh) + select { + case exitRes := <-exitCh: + exitStatus, exitedAt, err := exitRes.Result() + if err != nil { + logrus.WithError(err).Errorf("failed to get task exit status for %q", id) + exitStatus = unknownExitCode + exitedAt = time.Now() + } + + e := &eventtypes.TaskExit{ + ContainerID: id, + ID: id, + Pid: pid, + ExitStatus: exitStatus, + ExitedAt: exitedAt, + } + + logrus.Debugf("received exit event %+v", e) + + err = func() error { + dctx := ctrdutil.NamespacedContext() + dctx, dcancel := context.WithTimeout(dctx, handleEventTimeout) + defer dcancel() + + cntr, err := em.c.containerStore.Get(e.ID) + if err == nil { + if err := handleContainerExit(dctx, e, cntr); err != nil { + return err + } + return nil + } else if err != store.ErrNotExist { + return errors.Wrapf(err, "failed to get container %s", e.ID) + } + return nil + }() + if err != nil { + logrus.WithError(err).Errorf("failed to handle container TaskExit event %+v", e) + em.backOff.enBackOff(id, e) + } + return + case <-ctx.Done(): + } + }() + return stopCh +} + +func convertEvent(e *gogotypes.Any) (string, interface{}, error) { + id := "" + evt, err := typeurl.UnmarshalAny(e) + if err != nil { + return "", nil, errors.Wrap(err, "failed to unmarshalany") + } + + switch e := evt.(type) { + case *eventtypes.TaskOOM: + id = e.ContainerID + case *eventtypes.ImageCreate: + id = e.Name + case *eventtypes.ImageUpdate: + id = e.Name + case *eventtypes.ImageDelete: + id = e.Name + default: + return "", nil, errors.New("unsupported event") + } + return id, evt, nil +} + +// start starts the event monitor which monitors and handles all subscribed events. +// It returns an error channel for the caller to wait for stop errors from the +// event monitor. +// +// NOTE: +// 1. start must be called after subscribe. +// 2. The task exit event has been handled in individual startSandboxExitMonitor +// or startContainerExitMonitor goroutine at the first. If the goroutine fails, +// it puts the event into backoff retry queue and event monitor will handle +// it later. +func (em *eventMonitor) start() <-chan error { + errCh := make(chan error) + if em.ch == nil || em.errCh == nil { + panic("event channel is nil") + } + backOffCheckCh := em.backOff.start() + go func() { + defer close(errCh) + for { + select { + case e := <-em.ch: + logrus.Debugf("Received containerd event timestamp - %v, namespace - %q, topic - %q", e.Timestamp, e.Namespace, e.Topic) + if e.Namespace != constants.K8sContainerdNamespace { + logrus.Debugf("Ignoring events in namespace - %q", e.Namespace) + break + } + id, evt, err := convertEvent(e.Event) + if err != nil { + logrus.WithError(err).Errorf("Failed to convert event %+v", e) + break + } + if em.backOff.isInBackOff(id) { + logrus.Infof("Events for %q is in backoff, enqueue event %+v", id, evt) + em.backOff.enBackOff(id, evt) + break + } + if err := em.handleEvent(evt); err != nil { + logrus.WithError(err).Errorf("Failed to handle event %+v for %s", evt, id) + em.backOff.enBackOff(id, evt) + } + case err := <-em.errCh: + // Close errCh in defer directly if there is no error. + if err != nil { + logrus.WithError(err).Errorf("Failed to handle event stream") + errCh <- err + } + return + case <-backOffCheckCh: + ids := em.backOff.getExpiredIDs() + for _, id := range ids { + queue := em.backOff.deBackOff(id) + for i, any := range queue.events { + if err := em.handleEvent(any); err != nil { + logrus.WithError(err).Errorf("Failed to handle backOff event %+v for %s", any, id) + em.backOff.reBackOff(id, queue.events[i:], queue.duration) + break + } + } + } + } + } + }() + return errCh +} + +// stop stops the event monitor. It will close the event channel. +// Once event monitor is stopped, it can't be started. +func (em *eventMonitor) stop() { + em.backOff.stop() + em.cancel() +} + +// handleEvent handles a containerd event. +func (em *eventMonitor) handleEvent(any interface{}) error { + ctx := ctrdutil.NamespacedContext() + ctx, cancel := context.WithTimeout(ctx, handleEventTimeout) + defer cancel() + + switch e := any.(type) { + case *eventtypes.TaskExit: + logrus.Infof("TaskExit event %+v", e) + // Use ID instead of ContainerID to rule out TaskExit event for exec. + cntr, err := em.c.containerStore.Get(e.ID) + if err == nil { + if err := handleContainerExit(ctx, e, cntr); err != nil { + return errors.Wrap(err, "failed to handle container TaskExit event") + } + return nil + } else if err != store.ErrNotExist { + return errors.Wrap(err, "can't find container for TaskExit event") + } + sb, err := em.c.sandboxStore.Get(e.ID) + if err == nil { + if err := handleSandboxExit(ctx, e, sb); err != nil { + return errors.Wrap(err, "failed to handle sandbox TaskExit event") + } + return nil + } else if err != store.ErrNotExist { + return errors.Wrap(err, "can't find sandbox for TaskExit event") + } + return nil + case *eventtypes.TaskOOM: + logrus.Infof("TaskOOM event %+v", e) + // For TaskOOM, we only care which container it belongs to. + cntr, err := em.c.containerStore.Get(e.ContainerID) + if err != nil { + if err != store.ErrNotExist { + return errors.Wrap(err, "can't find container for TaskOOM event") + } + return nil + } + err = cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { + status.Reason = oomExitReason + return status, nil + }) + if err != nil { + return errors.Wrap(err, "failed to update container status for TaskOOM event") + } + case *eventtypes.ImageCreate: + logrus.Infof("ImageCreate event %+v", e) + return em.c.updateImage(ctx, e.Name) + case *eventtypes.ImageUpdate: + logrus.Infof("ImageUpdate event %+v", e) + return em.c.updateImage(ctx, e.Name) + case *eventtypes.ImageDelete: + logrus.Infof("ImageDelete event %+v", e) + return em.c.updateImage(ctx, e.Name) + } + + return nil +} + +// handleContainerExit handles TaskExit event for container. +func handleContainerExit(ctx context.Context, e *eventtypes.TaskExit, cntr containerstore.Container) error { + // Attach container IO so that `Delete` could cleanup the stream properly. + task, err := cntr.Container.Task(ctx, + func(*containerdio.FIFOSet) (containerdio.IO, error) { + // We can't directly return cntr.IO here, because + // even if cntr.IO is nil, the cio.IO interface + // is not. + // See https://tour.golang.org/methods/12: + // Note that an interface value that holds a nil + // concrete value is itself non-nil. + if cntr.IO != nil { + return cntr.IO, nil + } + return nil, nil + }, + ) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to load task for container") + } + } else { + // TODO(random-liu): [P1] This may block the loop, we may want to spawn a worker + if _, err = task.Delete(ctx, WithNRISandboxDelete(cntr.SandboxID), containerd.WithProcessKill); err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to stop container") + } + // Move on to make sure container status is updated. + } + } + err = cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { + if status.FinishedAt == 0 { + status.Pid = 0 + status.FinishedAt = e.ExitedAt.UnixNano() + status.ExitCode = int32(e.ExitStatus) + } + + // Unknown state can only transit to EXITED state, so we need + // to handle unknown state here. + if status.Unknown { + logrus.Debugf("Container %q transited from UNKNOWN to EXITED", cntr.ID) + status.Unknown = false + } + return status, nil + }) + if err != nil { + return errors.Wrap(err, "failed to update container state") + } + // Using channel to propagate the information of container stop + cntr.Stop() + return nil +} + +// handleSandboxExit handles TaskExit event for sandbox. +func handleSandboxExit(ctx context.Context, e *eventtypes.TaskExit, sb sandboxstore.Sandbox) error { + // No stream attached to sandbox container. + task, err := sb.Container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to load task for sandbox") + } + } else { + // TODO(random-liu): [P1] This may block the loop, we may want to spawn a worker + if _, err = task.Delete(ctx, WithNRISandboxDelete(sb.ID), containerd.WithProcessKill); err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to stop sandbox") + } + // Move on to make sure container status is updated. + } + } + err = sb.Status.Update(func(status sandboxstore.Status) (sandboxstore.Status, error) { + status.State = sandboxstore.StateNotReady + status.Pid = 0 + return status, nil + }) + if err != nil { + return errors.Wrap(err, "failed to update sandbox state") + } + // Using channel to propagate the information of sandbox stop + sb.Stop() + return nil +} + +func newBackOff() *backOff { + return &backOff{ + queuePool: map[string]*backOffQueue{}, + minDuration: backOffInitDuration, + maxDuration: backOffMaxDuration, + checkDuration: backOffExpireCheckDuration, + clock: clock.RealClock{}, + } +} + +func (b *backOff) getExpiredIDs() []string { + b.queuePoolMu.Lock() + defer b.queuePoolMu.Unlock() + + var ids []string + for id, q := range b.queuePool { + if q.isExpire() { + ids = append(ids, id) + } + } + return ids +} + +func (b *backOff) isInBackOff(key string) bool { + b.queuePoolMu.Lock() + defer b.queuePoolMu.Unlock() + + if _, ok := b.queuePool[key]; ok { + return true + } + return false +} + +// enBackOff start to backOff and put event to the tail of queue +func (b *backOff) enBackOff(key string, evt interface{}) { + b.queuePoolMu.Lock() + defer b.queuePoolMu.Unlock() + + if queue, ok := b.queuePool[key]; ok { + queue.events = append(queue.events, evt) + return + } + b.queuePool[key] = newBackOffQueue([]interface{}{evt}, b.minDuration, b.clock) +} + +// enBackOff get out the whole queue +func (b *backOff) deBackOff(key string) *backOffQueue { + b.queuePoolMu.Lock() + defer b.queuePoolMu.Unlock() + + queue := b.queuePool[key] + delete(b.queuePool, key) + return queue +} + +// enBackOff start to backOff again and put events to the queue +func (b *backOff) reBackOff(key string, events []interface{}, oldDuration time.Duration) { + b.queuePoolMu.Lock() + defer b.queuePoolMu.Unlock() + + duration := 2 * oldDuration + if duration > b.maxDuration { + duration = b.maxDuration + } + b.queuePool[key] = newBackOffQueue(events, duration, b.clock) +} + +func (b *backOff) start() <-chan time.Time { + b.tickerMu.Lock() + defer b.tickerMu.Unlock() + b.ticker = time.NewTicker(b.checkDuration) + return b.ticker.C +} + +func (b *backOff) stop() { + b.tickerMu.Lock() + defer b.tickerMu.Unlock() + if b.ticker != nil { + b.ticker.Stop() + } +} + +func newBackOffQueue(events []interface{}, init time.Duration, c clock.Clock) *backOffQueue { + return &backOffQueue{ + events: events, + duration: init, + expireTime: c.Now().Add(init), + clock: c, + } +} + +func (q *backOffQueue) isExpire() bool { + // return time.Now >= expireTime + return !q.clock.Now().Before(q.expireTime) +} diff -Nru containerd-1.2.6/pkg/cri/server/events_test.go containerd-1.5.9/pkg/cri/server/events_test.go --- containerd-1.2.6/pkg/cri/server/events_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/events_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + eventtypes "github.com/containerd/containerd/api/events" + "github.com/containerd/typeurl" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/util/clock" +) + +// TestBackOff tests the logic of backOff struct. +func TestBackOff(t *testing.T) { + testStartTime := time.Now() + testClock := clock.NewFakeClock(testStartTime) + inputQueues := map[string]*backOffQueue{ + "container1": { + events: []interface{}{ + &eventtypes.TaskOOM{ContainerID: "container1"}, + &eventtypes.TaskOOM{ContainerID: "container1"}, + }, + }, + "container2": { + events: []interface{}{ + &eventtypes.TaskOOM{ContainerID: "container2"}, + &eventtypes.TaskOOM{ContainerID: "container2"}, + }, + }, + } + expectedQueues := map[string]*backOffQueue{ + "container2": { + events: []interface{}{ + &eventtypes.TaskOOM{ContainerID: "container2"}, + &eventtypes.TaskOOM{ContainerID: "container2"}, + }, + expireTime: testClock.Now().Add(backOffInitDuration), + duration: backOffInitDuration, + clock: testClock, + }, + "container1": { + events: []interface{}{ + &eventtypes.TaskOOM{ContainerID: "container1"}, + &eventtypes.TaskOOM{ContainerID: "container1"}, + }, + expireTime: testClock.Now().Add(backOffInitDuration), + duration: backOffInitDuration, + clock: testClock, + }, + } + + t.Logf("Should be able to backOff a event") + actual := newBackOff() + actual.clock = testClock + for k, queue := range inputQueues { + for _, event := range queue.events { + actual.enBackOff(k, event) + } + } + assert.Equal(t, actual.queuePool, expectedQueues) + + t.Logf("Should be able to check if the container is in backOff state") + for k, queue := range inputQueues { + for _, e := range queue.events { + any, err := typeurl.MarshalAny(e) + assert.NoError(t, err) + key, _, err := convertEvent(any) + assert.NoError(t, err) + assert.Equal(t, k, key) + assert.Equal(t, actual.isInBackOff(key), true) + } + } + + t.Logf("Should be able to check that a container isn't in backOff state") + notExistKey := "containerNotExist" + assert.Equal(t, actual.isInBackOff(notExistKey), false) + + t.Logf("No containers should be expired") + assert.Empty(t, actual.getExpiredIDs()) + + t.Logf("Should be able to get all keys which are expired for backOff") + testClock.Sleep(backOffInitDuration) + actKeyList := actual.getExpiredIDs() + assert.Equal(t, len(inputQueues), len(actKeyList)) + for k := range inputQueues { + assert.Contains(t, actKeyList, k) + } + + t.Logf("Should be able to get out all backOff events") + doneQueues := map[string]*backOffQueue{} + for k := range inputQueues { + actQueue := actual.deBackOff(k) + doneQueues[k] = actQueue + assert.Equal(t, actQueue, expectedQueues[k]) + } + + t.Logf("Should not get out the event again after having got out the backOff event") + for k := range inputQueues { + var expect *backOffQueue + actQueue := actual.deBackOff(k) + assert.Equal(t, actQueue, expect) + } + + t.Logf("Should be able to reBackOff") + for k, queue := range doneQueues { + failEventIndex := 1 + events := queue.events[failEventIndex:] + actual.reBackOff(k, events, queue.duration) + actQueue := actual.deBackOff(k) + expQueue := &backOffQueue{ + events: events, + expireTime: testClock.Now().Add(2 * queue.duration), + duration: 2 * queue.duration, + clock: testClock, + } + assert.Equal(t, actQueue, expQueue) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers.go containerd-1.5.9/pkg/cri/server/helpers.go --- containerd-1.2.6/pkg/cri/server/helpers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,431 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "fmt" + "path" + "path/filepath" + "strconv" + "strings" + + runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + clabels "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/reference/docker" + "github.com/containerd/containerd/runtime/linux/runctypes" + runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/typeurl" + imagedigest "github.com/opencontainers/go-digest" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + criconfig "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" +) + +const ( + // errorStartReason is the exit reason when fails to start container. + errorStartReason = "StartError" + // errorStartExitCode is the exit code when fails to start container. + // 128 is the same with Docker's behavior. + // TODO(windows): Figure out what should be used for windows. + errorStartExitCode = 128 + // completeExitReason is the exit reason when container exits with code 0. + completeExitReason = "Completed" + // errorExitReason is the exit reason when container exits with code non-zero. + errorExitReason = "Error" + // oomExitReason is the exit reason when process in container is oom killed. + oomExitReason = "OOMKilled" + + // sandboxesDir contains all sandbox root. A sandbox root is the running + // directory of the sandbox, all files created for the sandbox will be + // placed under this directory. + sandboxesDir = "sandboxes" + // containersDir contains all container root. + containersDir = "containers" + // Delimiter used to construct container/sandbox names. + nameDelimiter = "_" + + // criContainerdPrefix is common prefix for cri-containerd + criContainerdPrefix = "io.cri-containerd" + // containerKindLabel is a label key indicating container is sandbox container or application container + containerKindLabel = criContainerdPrefix + ".kind" + // containerKindSandbox is a label value indicating container is sandbox container + containerKindSandbox = "sandbox" + // containerKindContainer is a label value indicating container is application container + containerKindContainer = "container" + // imageLabelKey is the label key indicating the image is managed by cri plugin. + imageLabelKey = criContainerdPrefix + ".image" + // imageLabelValue is the label value indicating the image is managed by cri plugin. + imageLabelValue = "managed" + // sandboxMetadataExtension is an extension name that identify metadata of sandbox in CreateContainerRequest + sandboxMetadataExtension = criContainerdPrefix + ".sandbox.metadata" + // containerMetadataExtension is an extension name that identify metadata of container in CreateContainerRequest + containerMetadataExtension = criContainerdPrefix + ".container.metadata" + + // defaultIfName is the default network interface for the pods + defaultIfName = "eth0" + + // runtimeRunhcsV1 is the runtime type for runhcs. + runtimeRunhcsV1 = "io.containerd.runhcs.v1" +) + +// makeSandboxName generates sandbox name from sandbox metadata. The name +// generated is unique as long as sandbox metadata is unique. +func makeSandboxName(s *runtime.PodSandboxMetadata) string { + return strings.Join([]string{ + s.Name, // 0 + s.Namespace, // 1 + s.Uid, // 2 + fmt.Sprintf("%d", s.Attempt), // 3 + }, nameDelimiter) +} + +// makeContainerName generates container name from sandbox and container metadata. +// The name generated is unique as long as the sandbox container combination is +// unique. +func makeContainerName(c *runtime.ContainerMetadata, s *runtime.PodSandboxMetadata) string { + return strings.Join([]string{ + c.Name, // 0 + s.Name, // 1: pod name + s.Namespace, // 2: pod namespace + s.Uid, // 3: pod uid + fmt.Sprintf("%d", c.Attempt), // 4 + }, nameDelimiter) +} + +// getSandboxRootDir returns the root directory for managing sandbox files, +// e.g. hosts files. +func (c *criService) getSandboxRootDir(id string) string { + return filepath.Join(c.config.RootDir, sandboxesDir, id) +} + +// getVolatileSandboxRootDir returns the root directory for managing volatile sandbox files, +// e.g. named pipes. +func (c *criService) getVolatileSandboxRootDir(id string) string { + return filepath.Join(c.config.StateDir, sandboxesDir, id) +} + +// getContainerRootDir returns the root directory for managing container files, +// e.g. state checkpoint. +func (c *criService) getContainerRootDir(id string) string { + return filepath.Join(c.config.RootDir, containersDir, id) +} + +// getVolatileContainerRootDir returns the root directory for managing volatile container files, +// e.g. named pipes. +func (c *criService) getVolatileContainerRootDir(id string) string { + return filepath.Join(c.config.StateDir, containersDir, id) +} + +// criContainerStateToString formats CRI container state to string. +func criContainerStateToString(state runtime.ContainerState) string { + return runtime.ContainerState_name[int32(state)] +} + +// getRepoDigestAngTag returns image repoDigest and repoTag of the named image reference. +func getRepoDigestAndTag(namedRef docker.Named, digest imagedigest.Digest, schema1 bool) (string, string) { + var repoTag, repoDigest string + if _, ok := namedRef.(docker.NamedTagged); ok { + repoTag = namedRef.String() + } + if _, ok := namedRef.(docker.Canonical); ok { + repoDigest = namedRef.String() + } else if !schema1 { + // digest is not actual repo digest for schema1 image. + repoDigest = namedRef.Name() + "@" + digest.String() + } + return repoDigest, repoTag +} + +// localResolve resolves image reference locally and returns corresponding image metadata. It +// returns store.ErrNotExist if the reference doesn't exist. +func (c *criService) localResolve(refOrID string) (imagestore.Image, error) { + getImageID := func(refOrId string) string { + if _, err := imagedigest.Parse(refOrID); err == nil { + return refOrID + } + return func(ref string) string { + // ref is not image id, try to resolve it locally. + // TODO(random-liu): Handle this error better for debugging. + normalized, err := docker.ParseDockerRef(ref) + if err != nil { + return "" + } + id, err := c.imageStore.Resolve(normalized.String()) + if err != nil { + return "" + } + return id + }(refOrID) + } + + imageID := getImageID(refOrID) + if imageID == "" { + // Try to treat ref as imageID + imageID = refOrID + } + return c.imageStore.Get(imageID) +} + +// toContainerdImage converts an image object in image store to containerd image handler. +func (c *criService) toContainerdImage(ctx context.Context, image imagestore.Image) (containerd.Image, error) { + // image should always have at least one reference. + if len(image.References) == 0 { + return nil, errors.Errorf("invalid image with no reference %q", image.ID) + } + return c.client.GetImage(ctx, image.References[0]) +} + +// getUserFromImage gets uid or user name of the image user. +// If user is numeric, it will be treated as uid; or else, it is treated as user name. +func getUserFromImage(user string) (*int64, string) { + // return both empty if user is not specified in the image. + if user == "" { + return nil, "" + } + // split instances where the id may contain user:group + user = strings.Split(user, ":")[0] + // user could be either uid or user name. Try to interpret as numeric uid. + uid, err := strconv.ParseInt(user, 10, 64) + if err != nil { + // If user is non numeric, assume it's user name. + return nil, user + } + // If user is a numeric uid. + return &uid, "" +} + +// ensureImageExists returns corresponding metadata of the image reference, if image is not +// pulled yet, the function will pull the image. +func (c *criService) ensureImageExists(ctx context.Context, ref string, config *runtime.PodSandboxConfig) (*imagestore.Image, error) { + image, err := c.localResolve(ref) + if err != nil && err != store.ErrNotExist { + return nil, errors.Wrapf(err, "failed to get image %q", ref) + } + if err == nil { + return &image, nil + } + // Pull image to ensure the image exists + resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}, SandboxConfig: config}) + if err != nil { + return nil, errors.Wrapf(err, "failed to pull image %q", ref) + } + imageID := resp.GetImageRef() + newImage, err := c.imageStore.Get(imageID) + if err != nil { + // It's still possible that someone removed the image right after it is pulled. + return nil, errors.Wrapf(err, "failed to get image %q after pulling", imageID) + } + return &newImage, nil +} + +// validateTargetContainer checks that a container is a valid +// target for a container using PID NamespaceMode_TARGET. +// The target container must be in the same sandbox and must be running. +// Returns the target container for convenience. +func (c *criService) validateTargetContainer(sandboxID, targetContainerID string) (containerstore.Container, error) { + targetContainer, err := c.containerStore.Get(targetContainerID) + if err != nil { + return containerstore.Container{}, errors.Wrapf(err, "container %q does not exist", targetContainerID) + } + + targetSandboxID := targetContainer.Metadata.SandboxID + if targetSandboxID != sandboxID { + return containerstore.Container{}, + errors.Errorf("container %q (sandbox %s) does not belong to sandbox %s", targetContainerID, targetSandboxID, sandboxID) + } + + status := targetContainer.Status.Get() + if state := status.State(); state != runtime.ContainerState_CONTAINER_RUNNING { + return containerstore.Container{}, errors.Errorf("container %q is not running - in state %s", targetContainerID, state) + } + + return targetContainer, nil +} + +// isInCRIMounts checks whether a destination is in CRI mount list. +func isInCRIMounts(dst string, mounts []*runtime.Mount) bool { + for _, m := range mounts { + if filepath.Clean(m.ContainerPath) == filepath.Clean(dst) { + return true + } + } + return false +} + +// filterLabel returns a label filter. Use `%q` here because containerd +// filter needs extra quote to work properly. +func filterLabel(k, v string) string { + return fmt.Sprintf("labels.%q==%q", k, v) +} + +// buildLabel builds the labels from config to be passed to containerd +func buildLabels(configLabels, imageConfigLabels map[string]string, containerType string) map[string]string { + labels := make(map[string]string) + + for k, v := range imageConfigLabels { + if err := clabels.Validate(k, v); err == nil { + labels[k] = v + } else { + // In case the image label is invalid, we output a warning and skip adding it to the + // container. + logrus.WithError(err).Warnf("unable to add image label with key %s to the container", k) + } + } + // labels from the CRI request (config) will override labels in the image config + for k, v := range configLabels { + labels[k] = v + } + labels[containerKindLabel] = containerType + return labels +} + +// toRuntimeAuthConfig converts cri plugin auth config to runtime auth config. +func toRuntimeAuthConfig(a criconfig.AuthConfig) *runtime.AuthConfig { + return &runtime.AuthConfig{ + Username: a.Username, + Password: a.Password, + Auth: a.Auth, + IdentityToken: a.IdentityToken, + } +} + +// parseImageReferences parses a list of arbitrary image references and returns +// the repotags and repodigests +func parseImageReferences(refs []string) ([]string, []string) { + var tags, digests []string + for _, ref := range refs { + parsed, err := docker.ParseAnyReference(ref) + if err != nil { + continue + } + if _, ok := parsed.(docker.Canonical); ok { + digests = append(digests, parsed.String()) + } else if _, ok := parsed.(docker.Tagged); ok { + tags = append(tags, parsed.String()) + } + } + return tags, digests +} + +// generateRuntimeOptions generates runtime options from cri plugin config. +func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { + if r.Options == nil { + if r.Type != plugin.RuntimeLinuxV1 { + return nil, nil + } + // This is a legacy config, generate runctypes.RuncOptions. + return &runctypes.RuncOptions{ + Runtime: r.Engine, + RuntimeRoot: r.Root, + SystemdCgroup: c.SystemdCgroup, + }, nil + } + optionsTree, err := toml.TreeFromMap(r.Options) + if err != nil { + return nil, err + } + options := getRuntimeOptionsType(r.Type) + if err := optionsTree.Unmarshal(options); err != nil { + return nil, err + } + return options, nil +} + +// getRuntimeOptionsType gets empty runtime options by the runtime type name. +func getRuntimeOptionsType(t string) interface{} { + switch t { + case plugin.RuntimeRuncV1: + fallthrough + case plugin.RuntimeRuncV2: + return &runcoptions.Options{} + case plugin.RuntimeLinuxV1: + return &runctypes.RuncOptions{} + case runtimeRunhcsV1: + return &runhcsoptions.Options{} + default: + return &runtimeoptions.Options{} + } +} + +// getRuntimeOptions get runtime options from container metadata. +func getRuntimeOptions(c containers.Container) (interface{}, error) { + if c.Runtime.Options == nil { + return nil, nil + } + opts, err := typeurl.UnmarshalAny(c.Runtime.Options) + if err != nil { + return nil, err + } + return opts, nil +} + +const ( + // unknownExitCode is the exit code when exit reason is unknown. + unknownExitCode = 255 + // unknownExitReason is the exit reason when exit reason is unknown. + unknownExitReason = "Unknown" +) + +// unknownContainerStatus returns the default container status when its status is unknown. +func unknownContainerStatus() containerstore.Status { + return containerstore.Status{ + CreatedAt: 0, + StartedAt: 0, + FinishedAt: 0, + ExitCode: unknownExitCode, + Reason: unknownExitReason, + Unknown: true, + } +} + +// unknownSandboxStatus returns the default sandbox status when its status is unknown. +func unknownSandboxStatus() sandboxstore.Status { + return sandboxstore.Status{ + State: sandboxstore.StateUnknown, + } +} + +// getPassthroughAnnotations filters requested pod annotations by comparing +// against permitted annotations for the given runtime. +func getPassthroughAnnotations(podAnnotations map[string]string, + runtimePodAnnotations []string) (passthroughAnnotations map[string]string) { + passthroughAnnotations = make(map[string]string) + + for podAnnotationKey, podAnnotationValue := range podAnnotations { + for _, pattern := range runtimePodAnnotations { + // Use path.Match instead of filepath.Match here. + // filepath.Match treated `\\` as path separator + // on windows, which is not what we want. + if ok, _ := path.Match(pattern, podAnnotationKey); ok { + passthroughAnnotations[podAnnotationKey] = podAnnotationValue + } + } + } + return passthroughAnnotations +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_linux.go containerd-1.5.9/pkg/cri/server/helpers_linux.go --- containerd-1.2.6/pkg/cri/server/helpers_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,278 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "fmt" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strings" + "syscall" + "time" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/apparmor" + "github.com/containerd/containerd/pkg/seccomp" + "github.com/containerd/containerd/pkg/seutil" + "github.com/moby/sys/mountinfo" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" + "golang.org/x/sys/unix" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +const ( + // defaultSandboxOOMAdj is default omm adj for sandbox container. (kubernetes#47938). + defaultSandboxOOMAdj = -998 + // defaultShmSize is the default size of the sandbox shm. + defaultShmSize = int64(1024 * 1024 * 64) + // relativeRootfsPath is the rootfs path relative to bundle path. + relativeRootfsPath = "rootfs" + // devShm is the default path of /dev/shm. + devShm = "/dev/shm" + // etcHosts is the default path of /etc/hosts file. + etcHosts = "/etc/hosts" + // etcHostname is the default path of /etc/hostname file. + etcHostname = "/etc/hostname" + // resolvConfPath is the abs path of resolv.conf on host or container. + resolvConfPath = "/etc/resolv.conf" + // hostnameEnv is the key for HOSTNAME env. + hostnameEnv = "HOSTNAME" +) + +// getCgroupsPath generates container cgroups path. +func getCgroupsPath(cgroupsParent, id string) string { + base := path.Base(cgroupsParent) + if strings.HasSuffix(base, ".slice") { + // For a.slice/b.slice/c.slice, base is c.slice. + // runc systemd cgroup path format is "slice:prefix:name". + return strings.Join([]string{base, "cri-containerd", id}, ":") + } + return filepath.Join(cgroupsParent, id) +} + +// getSandboxHostname returns the hostname file path inside the sandbox root directory. +func (c *criService) getSandboxHostname(id string) string { + return filepath.Join(c.getSandboxRootDir(id), "hostname") +} + +// getSandboxHosts returns the hosts file path inside the sandbox root directory. +func (c *criService) getSandboxHosts(id string) string { + return filepath.Join(c.getSandboxRootDir(id), "hosts") +} + +// getResolvPath returns resolv.conf filepath for specified sandbox. +func (c *criService) getResolvPath(id string) string { + return filepath.Join(c.getSandboxRootDir(id), "resolv.conf") +} + +// getSandboxDevShm returns the shm file path inside the sandbox root directory. +func (c *criService) getSandboxDevShm(id string) string { + return filepath.Join(c.getVolatileSandboxRootDir(id), "shm") +} + +func toLabel(selinuxOptions *runtime.SELinuxOption) ([]string, error) { + var labels []string + + if selinuxOptions == nil { + return nil, nil + } + if err := checkSelinuxLevel(selinuxOptions.Level); err != nil { + return nil, err + } + if selinuxOptions.User != "" { + labels = append(labels, "user:"+selinuxOptions.User) + } + if selinuxOptions.Role != "" { + labels = append(labels, "role:"+selinuxOptions.Role) + } + if selinuxOptions.Type != "" { + labels = append(labels, "type:"+selinuxOptions.Type) + } + if selinuxOptions.Level != "" { + labels = append(labels, "level:"+selinuxOptions.Level) + } + + return labels, nil +} + +func initLabelsFromOpt(selinuxOpts *runtime.SELinuxOption) (string, string, error) { + labels, err := toLabel(selinuxOpts) + if err != nil { + return "", "", err + } + return label.InitLabels(labels) +} + +func checkSelinuxLevel(level string) error { + if len(level) == 0 { + return nil + } + + matched, err := regexp.MatchString(`^s\d(-s\d)??(:c\d{1,4}(\.c\d{1,4})?(,c\d{1,4}(\.c\d{1,4})?)*)?$`, level) + if err != nil { + return errors.Wrapf(err, "the format of 'level' %q is not correct", level) + } + if !matched { + return fmt.Errorf("the format of 'level' %q is not correct", level) + } + return nil +} + +// apparmorEnabled returns true if apparmor is enabled, supported by the host, +// if apparmor_parser is installed, and if we are not running docker-in-docker. +func (c *criService) apparmorEnabled() bool { + if c.config.DisableApparmor { + return false + } + return apparmor.HostSupports() +} + +func (c *criService) seccompEnabled() bool { + return seccomp.IsEnabled() +} + +// openLogFile opens/creates a container log file. +func openLogFile(path string) (*os.File, error) { + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return nil, err + } + return os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) +} + +// unmountRecursive unmounts the target and all mounts underneath, starting with +// the deepest mount first. +func unmountRecursive(ctx context.Context, target string) error { + toUnmount, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) + if err != nil { + return err + } + + // Make the deepest mount be first + sort.Slice(toUnmount, func(i, j int) bool { + return len(toUnmount[i].Mountpoint) > len(toUnmount[j].Mountpoint) + }) + + for i, m := range toUnmount { + if err := mount.UnmountAll(m.Mountpoint, unix.MNT_DETACH); err != nil { + if i == len(toUnmount)-1 { // last mount + return err + } + // This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem + log.G(ctx).WithError(err).Debugf("failed to unmount submount %s", m.Mountpoint) + } + } + return nil +} + +// ensureRemoveAll wraps `os.RemoveAll` to check for specific errors that can +// often be remedied. +// Only use `ensureRemoveAll` if you really want to make every effort to remove +// a directory. +// +// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there +// can be a race between reading directory entries and then actually attempting +// to remove everything in the directory. +// These types of errors do not need to be returned since it's ok for the dir to +// be gone we can just retry the remove operation. +// +// This should not return a `os.ErrNotExist` kind of error under any circumstances +func ensureRemoveAll(ctx context.Context, dir string) error { + notExistErr := make(map[string]bool) + + // track retries + exitOnErr := make(map[string]int) + maxRetry := 50 + + // Attempt to unmount anything beneath this dir first. + if err := unmountRecursive(ctx, dir); err != nil { + log.G(ctx).WithError(err).Debugf("failed to do initial unmount of %s", dir) + } + + for { + err := os.RemoveAll(dir) + if err == nil { + return nil + } + + pe, ok := err.(*os.PathError) + if !ok { + return err + } + + if os.IsNotExist(err) { + if notExistErr[pe.Path] { + return err + } + notExistErr[pe.Path] = true + + // There is a race where some subdir can be removed but after the + // parent dir entries have been read. + // So the path could be from `os.Remove(subdir)` + // If the reported non-existent path is not the passed in `dir` we + // should just retry, but otherwise return with no error. + if pe.Path == dir { + return nil + } + continue + } + + if pe.Err != syscall.EBUSY { + return err + } + if e := mount.Unmount(pe.Path, unix.MNT_DETACH); e != nil { + return errors.Wrapf(e, "error while removing %s", dir) + } + + if exitOnErr[pe.Path] == maxRetry { + return err + } + exitOnErr[pe.Path]++ + time.Sleep(100 * time.Millisecond) + } +} + +var vmbasedRuntimes = []string{ + "io.containerd.kata", +} + +func isVMBasedRuntime(runtimeType string) bool { + for _, rt := range vmbasedRuntimes { + if strings.Contains(runtimeType, rt) { + return true + } + } + return false +} + +func modifyProcessLabel(runtimeType string, spec *specs.Spec) error { + if !isVMBasedRuntime(runtimeType) { + return nil + } + l, err := seutil.ChangeToKVM(spec.Process.SelinuxLabel) + if err != nil { + return errors.Wrap(err, "failed to get selinux kvm label") + } + spec.Process.SelinuxLabel = l + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_linux_test.go containerd-1.5.9/pkg/cri/server/helpers_linux_test.go --- containerd-1.2.6/pkg/cri/server/helpers_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,106 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + "golang.org/x/sys/unix" +) + +func TestGetCgroupsPath(t *testing.T) { + testID := "test-id" + for desc, test := range map[string]struct { + cgroupsParent string + expected string + }{ + "should support regular cgroup path": { + cgroupsParent: "/a/b", + expected: "/a/b/test-id", + }, + "should support systemd cgroup path": { + cgroupsParent: "/a.slice/b.slice", + expected: "b.slice:cri-containerd:test-id", + }, + "should support tailing slash for regular cgroup path": { + cgroupsParent: "/a/b/", + expected: "/a/b/test-id", + }, + "should support tailing slash for systemd cgroup path": { + cgroupsParent: "/a.slice/b.slice/", + expected: "b.slice:cri-containerd:test-id", + }, + "should treat root cgroup as regular cgroup path": { + cgroupsParent: "/", + expected: "/test-id", + }, + } { + t.Logf("TestCase %q", desc) + got := getCgroupsPath(test.cgroupsParent, testID) + assert.Equal(t, test.expected, got) + } +} + +func TestEnsureRemoveAllWithMount(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("skipping test that requires root") + } + + dir1, err := ioutil.TempDir("", "test-ensure-removeall-with-dir1") + if err != nil { + t.Fatal(err) + } + dir2, err := ioutil.TempDir("", "test-ensure-removeall-with-dir2") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir2) + + bindDir := filepath.Join(dir1, "bind") + if err := os.MkdirAll(bindDir, 0755); err != nil { + t.Fatal(err) + } + + if err := unix.Mount(dir2, bindDir, "none", unix.MS_BIND, ""); err != nil { + t.Fatal(err) + } + + done := make(chan struct{}) + go func() { + err = ensureRemoveAll(context.Background(), dir1) + close(done) + }() + + select { + case <-done: + if err != nil { + t.Fatal(err) + } + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for EnsureRemoveAll to finish") + } + + if _, err := os.Stat(dir1); !os.IsNotExist(err) { + t.Fatalf("expected %q to not exist", dir1) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_other.go containerd-1.5.9/pkg/cri/server/helpers_other.go --- containerd-1.2.6/pkg/cri/server/helpers_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,43 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "os" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// openLogFile opens/creates a container log file. +func openLogFile(path string) (*os.File, error) { + return os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) +} + +// ensureRemoveAll wraps `os.RemoveAll` to check for specific errors that can +// often be remedied. +// Only use `ensureRemoveAll` if you really want to make every effort to remove +// a directory. +func ensureRemoveAll(ctx context.Context, dir string) error { + return os.RemoveAll(dir) +} + +func modifyProcessLabel(runtimeType string, spec *specs.Spec) error { + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_selinux_linux_test.go containerd-1.5.9/pkg/cri/server/helpers_selinux_linux_test.go --- containerd-1.2.6/pkg/cri/server/helpers_selinux_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_selinux_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,157 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + "github.com/opencontainers/selinux/go-selinux" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestInitSelinuxOpts(t *testing.T) { + if !selinux.GetEnabled() { + t.Skip("selinux is not enabled") + } + + for desc, test := range map[string]struct { + selinuxOpt *runtime.SELinuxOption + processLabel string + mountLabel string + expectErr bool + }{ + "Should return empty strings for processLabel and mountLabel when selinuxOpt is nil": { + selinuxOpt: nil, + processLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}", + mountLabel: ".*:c[0-9]{1,3},c[0-9]{1,3}", + }, + "Should overlay fields on processLabel when selinuxOpt has been initialized partially": { + selinuxOpt: &runtime.SELinuxOption{ + User: "", + Role: "user_r", + Type: "", + Level: "s0:c1,c2", + }, + processLabel: "system_u:user_r:(container_file_t|svirt_lxc_net_t):s0:c1,c2", + mountLabel: "system_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2", + }, + "Should be resolved correctly when selinuxOpt has been initialized completely": { + selinuxOpt: &runtime.SELinuxOption{ + User: "user_u", + Role: "user_r", + Type: "user_t", + Level: "s0:c1,c2", + }, + processLabel: "user_u:user_r:user_t:s0:c1,c2", + mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0:c1,c2", + }, + "Should be resolved correctly when selinuxOpt has been initialized with level=''": { + selinuxOpt: &runtime.SELinuxOption{ + User: "user_u", + Role: "user_r", + Type: "user_t", + Level: "", + }, + processLabel: "user_u:user_r:user_t:s0:c[0-9]{1,3},c[0-9]{1,3}", + mountLabel: "user_u:object_r:(container_file_t|svirt_sandbox_file_t):s0", + }, + "Should return error when the format of 'level' is not correct": { + selinuxOpt: &runtime.SELinuxOption{ + User: "user_u", + Role: "user_r", + Type: "user_t", + Level: "s0,c1,c2", + }, + expectErr: true, + }, + } { + t.Run(desc, func(t *testing.T) { + processLabel, mountLabel, err := initLabelsFromOpt(test.selinuxOpt) + if test.expectErr { + assert.Error(t, err) + } else { + assert.Regexp(t, test.processLabel, processLabel) + assert.Regexp(t, test.mountLabel, mountLabel) + } + }) + } +} + +func TestCheckSelinuxLevel(t *testing.T) { + for desc, test := range map[string]struct { + level string + expectNoMatch bool + }{ + "s0": { + level: "s0", + }, + "s0-s0": { + level: "s0-s0", + }, + "s0:c0": { + level: "s0:c0", + }, + "s0:c0.c3": { + level: "s0:c0.c3", + }, + "s0:c0,c3": { + level: "s0:c0,c3", + }, + "s0-s0:c0,c3": { + level: "s0-s0:c0,c3", + }, + "s0-s0:c0,c3.c6": { + level: "s0-s0:c0,c3.c6", + }, + "s0-s0:c0,c3.c6,c8.c10": { + level: "s0-s0:c0,c3.c6,c8.c10", + }, + "s0-s0:c0,c3.c6,c8,c10": { + level: "s0-s0:c0,c3.c6", + }, + "s0,c0,c3": { + level: "s0,c0,c3", + expectNoMatch: true, + }, + "s0:c0.c3.c6": { + level: "s0:c0.c3.c6", + expectNoMatch: true, + }, + "s0-s0,c0,c3": { + level: "s0-s0,c0,c3", + expectNoMatch: true, + }, + "s0-s0:c0.c3.c6": { + level: "s0-s0:c0.c3.c6", + expectNoMatch: true, + }, + "s0-s0:c0,c3.c6.c8": { + level: "s0-s0:c0,c3.c6.c8", + expectNoMatch: true, + }, + } { + t.Run(desc, func(t *testing.T) { + err := checkSelinuxLevel(test.level) + if test.expectNoMatch { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_test.go containerd-1.5.9/pkg/cri/server/helpers_test.go --- containerd-1.2.6/pkg/cri/server/helpers_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,604 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "io/ioutil" + "strings" + "testing" + "time" + + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/reference/docker" + "github.com/containerd/containerd/runtime/linux/runctypes" + runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" + imagedigest "github.com/opencontainers/go-digest" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pelletier/go-toml" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + criconfig "github.com/containerd/containerd/pkg/cri/config" + "github.com/containerd/containerd/pkg/cri/store" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" +) + +// TestGetUserFromImage tests the logic of getting image uid or user name of image user. +func TestGetUserFromImage(t *testing.T) { + newI64 := func(i int64) *int64 { return &i } + for c, test := range map[string]struct { + user string + uid *int64 + name string + }{ + "no gid": { + user: "0", + uid: newI64(0), + }, + "uid/gid": { + user: "0:1", + uid: newI64(0), + }, + "empty user": { + user: "", + }, + "multiple separators": { + user: "1:2:3", + uid: newI64(1), + }, + "root username": { + user: "root:root", + name: "root", + }, + "username": { + user: "test:test", + name: "test", + }, + } { + t.Logf("TestCase - %q", c) + actualUID, actualName := getUserFromImage(test.user) + assert.Equal(t, test.uid, actualUID) + assert.Equal(t, test.name, actualName) + } +} + +func TestGetRepoDigestAndTag(t *testing.T) { + digest := imagedigest.Digest("sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582") + for desc, test := range map[string]struct { + ref string + schema1 bool + expectedRepoDigest string + expectedRepoTag string + }{ + "repo tag should be empty if original ref has no tag": { + ref: "gcr.io/library/busybox@" + digest.String(), + expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), + }, + "repo tag should not be empty if original ref has tag": { + ref: "gcr.io/library/busybox:latest", + expectedRepoDigest: "gcr.io/library/busybox@" + digest.String(), + expectedRepoTag: "gcr.io/library/busybox:latest", + }, + "repo digest should be empty if original ref is schema1 and has no digest": { + ref: "gcr.io/library/busybox:latest", + schema1: true, + expectedRepoDigest: "", + expectedRepoTag: "gcr.io/library/busybox:latest", + }, + "repo digest should not be empty if original ref is schema1 but has digest": { + ref: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", + schema1: true, + expectedRepoDigest: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59594", + expectedRepoTag: "", + }, + } { + t.Logf("TestCase %q", desc) + named, err := docker.ParseDockerRef(test.ref) + assert.NoError(t, err) + repoDigest, repoTag := getRepoDigestAndTag(named, digest, test.schema1) + assert.Equal(t, test.expectedRepoDigest, repoDigest) + assert.Equal(t, test.expectedRepoTag, repoTag) + } +} + +func TestBuildLabels(t *testing.T) { + imageConfigLabels := map[string]string{ + "a": "z", + "d": "y", + "long-label": strings.Repeat("example", 10000), + } + configLabels := map[string]string{ + "a": "b", + "c": "d", + } + newLabels := buildLabels(configLabels, imageConfigLabels, containerKindSandbox) + assert.Len(t, newLabels, 4) + assert.Equal(t, "b", newLabels["a"]) + assert.Equal(t, "d", newLabels["c"]) + assert.Equal(t, "y", newLabels["d"]) + assert.Equal(t, containerKindSandbox, newLabels[containerKindLabel]) + assert.NotContains(t, newLabels, "long-label") + + newLabels["a"] = "e" + assert.Empty(t, configLabels[containerKindLabel], "should not add new labels into original label") + assert.Equal(t, "b", configLabels["a"], "change in new labels should not affect original label") +} + +func TestParseImageReferences(t *testing.T) { + refs := []string{ + "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + "gcr.io/library/busybox:1.2", + "sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + "arbitrary-ref", + } + expectedTags := []string{ + "gcr.io/library/busybox:1.2", + } + expectedDigests := []string{"gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582"} + tags, digests := parseImageReferences(refs) + assert.Equal(t, expectedTags, tags) + assert.Equal(t, expectedDigests, digests) +} + +func TestLocalResolve(t *testing.T) { + image := imagestore.Image{ + ID: "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113799", + ChainID: "test-chain-id-1", + References: []string{ + "docker.io/library/busybox:latest", + "docker.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + Size: 10, + } + c := newTestCRIService() + var err error + c.imageStore, err = imagestore.NewFakeStore([]imagestore.Image{image}) + assert.NoError(t, err) + + for _, ref := range []string{ + "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113799", + "busybox", + "busybox:latest", + "busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + "library/busybox", + "library/busybox:latest", + "library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + "docker.io/busybox", + "docker.io/busybox:latest", + "docker.io/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + "docker.io/library/busybox", + "docker.io/library/busybox:latest", + "docker.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + } { + img, err := c.localResolve(ref) + assert.NoError(t, err) + assert.Equal(t, image, img) + } + img, err := c.localResolve("randomid") + assert.Equal(t, store.ErrNotExist, err) + assert.Equal(t, imagestore.Image{}, img) +} + +func TestGenerateRuntimeOptions(t *testing.T) { + nilOpts := ` +systemd_cgroup = true +[containerd] + no_pivot = true + default_runtime_name = "default" +[containerd.runtimes.legacy] + runtime_type = "` + plugin.RuntimeLinuxV1 + `" +[containerd.runtimes.runc] + runtime_type = "` + plugin.RuntimeRuncV1 + `" +[containerd.runtimes.runcv2] + runtime_type = "` + plugin.RuntimeRuncV2 + `" +` + nonNilOpts := ` +systemd_cgroup = true +[containerd] + no_pivot = true + default_runtime_name = "default" +[containerd.runtimes.legacy] + runtime_type = "` + plugin.RuntimeLinuxV1 + `" +[containerd.runtimes.legacy.options] + Runtime = "legacy" + RuntimeRoot = "/legacy" +[containerd.runtimes.runc] + runtime_type = "` + plugin.RuntimeRuncV1 + `" +[containerd.runtimes.runc.options] + BinaryName = "runc" + Root = "/runc" + NoNewKeyring = true +[containerd.runtimes.runcv2] + runtime_type = "` + plugin.RuntimeRuncV2 + `" +[containerd.runtimes.runcv2.options] + BinaryName = "runc" + Root = "/runcv2" + NoNewKeyring = true +` + var nilOptsConfig, nonNilOptsConfig criconfig.Config + tree, err := toml.Load(nilOpts) + require.NoError(t, err) + err = tree.Unmarshal(&nilOptsConfig) + require.NoError(t, err) + require.Len(t, nilOptsConfig.Runtimes, 3) + + tree, err = toml.Load(nonNilOpts) + require.NoError(t, err) + err = tree.Unmarshal(&nonNilOptsConfig) + require.NoError(t, err) + require.Len(t, nonNilOptsConfig.Runtimes, 3) + + for desc, test := range map[string]struct { + r criconfig.Runtime + c criconfig.Config + expectedOptions interface{} + }{ + "when options is nil, should return nil option for io.containerd.runc.v1": { + r: nilOptsConfig.Runtimes["runc"], + c: nilOptsConfig, + expectedOptions: nil, + }, + "when options is nil, should return nil option for io.containerd.runc.v2": { + r: nilOptsConfig.Runtimes["runcv2"], + c: nilOptsConfig, + expectedOptions: nil, + }, + "when options is nil, should use legacy fields for legacy runtime": { + r: nilOptsConfig.Runtimes["legacy"], + c: nilOptsConfig, + expectedOptions: &runctypes.RuncOptions{ + SystemdCgroup: true, + }, + }, + "when options is not nil, should be able to decode for io.containerd.runc.v1": { + r: nonNilOptsConfig.Runtimes["runc"], + c: nonNilOptsConfig, + expectedOptions: &runcoptions.Options{ + BinaryName: "runc", + Root: "/runc", + NoNewKeyring: true, + }, + }, + "when options is not nil, should be able to decode for io.containerd.runc.v2": { + r: nonNilOptsConfig.Runtimes["runcv2"], + c: nonNilOptsConfig, + expectedOptions: &runcoptions.Options{ + BinaryName: "runc", + Root: "/runcv2", + NoNewKeyring: true, + }, + }, + "when options is not nil, should be able to decode for legacy runtime": { + r: nonNilOptsConfig.Runtimes["legacy"], + c: nonNilOptsConfig, + expectedOptions: &runctypes.RuncOptions{ + Runtime: "legacy", + RuntimeRoot: "/legacy", + }, + }, + } { + t.Run(desc, func(t *testing.T) { + opts, err := generateRuntimeOptions(test.r, test.c) + assert.NoError(t, err) + assert.Equal(t, test.expectedOptions, opts) + }) + } +} + +func TestEnvDeduplication(t *testing.T) { + for desc, test := range map[string]struct { + existing []string + kv [][2]string + expected []string + }{ + "single env": { + kv: [][2]string{ + {"a", "b"}, + }, + expected: []string{"a=b"}, + }, + "multiple envs": { + kv: [][2]string{ + {"a", "b"}, + {"c", "d"}, + {"e", "f"}, + }, + expected: []string{ + "a=b", + "c=d", + "e=f", + }, + }, + "env override": { + kv: [][2]string{ + {"k1", "v1"}, + {"k2", "v2"}, + {"k3", "v3"}, + {"k3", "v4"}, + {"k1", "v5"}, + {"k4", "v6"}, + }, + expected: []string{ + "k1=v5", + "k2=v2", + "k3=v4", + "k4=v6", + }, + }, + "existing env": { + existing: []string{ + "k1=v1", + "k2=v2", + "k3=v3", + }, + kv: [][2]string{ + {"k3", "v4"}, + {"k2", "v5"}, + {"k4", "v6"}, + }, + expected: []string{ + "k1=v1", + "k2=v5", + "k3=v4", + "k4=v6", + }, + }, + } { + t.Logf("TestCase %q", desc) + var spec runtimespec.Spec + if len(test.existing) > 0 { + spec.Process = &runtimespec.Process{ + Env: test.existing, + } + } + for _, kv := range test.kv { + oci.WithEnv([]string{kv[0] + "=" + kv[1]})(context.Background(), nil, nil, &spec) + } + assert.Equal(t, test.expected, spec.Process.Env) + } +} + +func TestPassThroughAnnotationsFilter(t *testing.T) { + for desc, test := range map[string]struct { + podAnnotations map[string]string + runtimePodAnnotations []string + passthroughAnnotations map[string]string + }{ + "should support direct match": { + podAnnotations: map[string]string{"c": "d", "d": "e"}, + runtimePodAnnotations: []string{"c"}, + passthroughAnnotations: map[string]string{"c": "d"}, + }, + "should support wildcard match": { + podAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + runtimePodAnnotations: []string{"*.f", "z*g", "y.c*"}, + passthroughAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "y.ca": "b", + }, + }, + "should support wildcard match all": { + podAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + runtimePodAnnotations: []string{"*"}, + passthroughAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + }, + "should support match including path separator": { + podAnnotations: map[string]string{ + "matchend.com/end": "1", + "matchend.com/end1": "2", + "matchend.com/1end": "3", + "matchmid.com/mid": "4", + "matchmid.com/mi1d": "5", + "matchmid.com/mid1": "6", + "matchhead.com/head": "7", + "matchhead.com/1head": "8", + "matchhead.com/head1": "9", + "matchall.com/abc": "10", + "matchall.com/def": "11", + "end/matchend": "12", + "end1/matchend": "13", + "1end/matchend": "14", + "mid/matchmid": "15", + "mi1d/matchmid": "16", + "mid1/matchmid": "17", + "head/matchhead": "18", + "1head/matchhead": "19", + "head1/matchhead": "20", + "abc/matchall": "21", + "def/matchall": "22", + "match1/match2": "23", + "nomatch/nomatch": "24", + }, + runtimePodAnnotations: []string{ + "matchend.com/end*", + "matchmid.com/mi*d", + "matchhead.com/*head", + "matchall.com/*", + "end*/matchend", + "mi*d/matchmid", + "*head/matchhead", + "*/matchall", + "match*/match*", + }, + passthroughAnnotations: map[string]string{ + "matchend.com/end": "1", + "matchend.com/end1": "2", + "matchmid.com/mid": "4", + "matchmid.com/mi1d": "5", + "matchhead.com/head": "7", + "matchhead.com/1head": "8", + "matchall.com/abc": "10", + "matchall.com/def": "11", + "end/matchend": "12", + "end1/matchend": "13", + "mid/matchmid": "15", + "mi1d/matchmid": "16", + "head/matchhead": "18", + "1head/matchhead": "19", + "abc/matchall": "21", + "def/matchall": "22", + "match1/match2": "23", + }, + }, + } { + t.Run(desc, func(t *testing.T) { + passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) + assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) + }) + } +} + +func TestEnsureRemoveAllNotExist(t *testing.T) { + // should never return an error for a non-existent path + if err := ensureRemoveAll(context.Background(), "/non/existent/path"); err != nil { + t.Fatal(err) + } +} + +func TestEnsureRemoveAllWithDir(t *testing.T) { + dir, err := ioutil.TempDir("", "test-ensure-removeall-with-dir") + if err != nil { + t.Fatal(err) + } + if err := ensureRemoveAll(context.Background(), dir); err != nil { + t.Fatal(err) + } +} + +func TestEnsureRemoveAllWithFile(t *testing.T) { + tmp, err := ioutil.TempFile("", "test-ensure-removeall-with-dir") + if err != nil { + t.Fatal(err) + } + tmp.Close() + if err := ensureRemoveAll(context.Background(), tmp.Name()); err != nil { + t.Fatal(err) + } +} + +// Helper function for setting up an environment to test PID namespace targeting. +func addContainer(c *criService, containerID, sandboxID string, PID uint32, createdAt, startedAt, finishedAt int64) error { + meta := containerstore.Metadata{ + ID: containerID, + SandboxID: sandboxID, + } + status := containerstore.Status{ + Pid: PID, + CreatedAt: createdAt, + StartedAt: startedAt, + FinishedAt: finishedAt, + } + container, err := containerstore.NewContainer(meta, + containerstore.WithFakeStatus(status), + ) + if err != nil { + return err + } + return c.containerStore.Add(container) +} + +func TestValidateTargetContainer(t *testing.T) { + testSandboxID := "test-sandbox-uid" + + // The existing container that will be targeted. + testTargetContainerID := "test-target-container" + testTargetContainerPID := uint32(4567) + + // A container that has finished running and cannot be targeted. + testStoppedContainerID := "stopped-target-container" + testStoppedContainerPID := uint32(6789) + + // A container from another pod. + testOtherContainerSandboxID := "other-sandbox-uid" + testOtherContainerID := "other-target-container" + testOtherContainerPID := uint32(7890) + + // Container create/start/stop times. + createdAt := time.Now().Add(-15 * time.Second).UnixNano() + startedAt := time.Now().Add(-10 * time.Second).UnixNano() + finishedAt := time.Now().Add(-5 * time.Second).UnixNano() + + c := newTestCRIService() + + // Create a target container. + err := addContainer(c, testTargetContainerID, testSandboxID, testTargetContainerPID, createdAt, startedAt, 0) + require.NoError(t, err, "error creating test target container") + + // Create a stopped container. + err = addContainer(c, testStoppedContainerID, testSandboxID, testStoppedContainerPID, createdAt, startedAt, finishedAt) + require.NoError(t, err, "error creating test stopped container") + + // Create a container in another pod. + err = addContainer(c, testOtherContainerID, testOtherContainerSandboxID, testOtherContainerPID, createdAt, startedAt, 0) + require.NoError(t, err, "error creating test container in other pod") + + for desc, test := range map[string]struct { + targetContainerID string + expectError bool + }{ + "target container in pod": { + targetContainerID: testTargetContainerID, + expectError: false, + }, + "target stopped container in pod": { + targetContainerID: testStoppedContainerID, + expectError: true, + }, + "target container does not exist": { + targetContainerID: "no-container-with-this-id", + expectError: true, + }, + "target container in other pod": { + targetContainerID: testOtherContainerID, + expectError: true, + }, + } { + t.Run(desc, func(t *testing.T) { + targetContainer, err := c.validateTargetContainer(testSandboxID, test.targetContainerID) + if test.expectError { + require.Error(t, err, "target should have been invalid but no error") + return + } + require.NoErrorf(t, err, "target should have been valid but got error") + + assert.Equal(t, test.targetContainerID, targetContainer.ID, "returned target container does not have expected ID") + }) + } + +} diff -Nru containerd-1.2.6/pkg/cri/server/helpers_windows.go containerd-1.5.9/pkg/cri/server/helpers_windows.go --- containerd-1.2.6/pkg/cri/server/helpers_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/helpers_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,170 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "os" + "path/filepath" + "syscall" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// openLogFile opens/creates a container log file. +// It specifies `FILE_SHARE_DELETE` option to make sure +// log files can be rotated by kubelet. +// TODO(windows): Use golang support after 1.14. (https://github.com/golang/go/issues/32088) +func openLogFile(path string) (*os.File, error) { + path = fixLongPath(path) + if len(path) == 0 { + return nil, syscall.ERROR_FILE_NOT_FOUND + } + pathp, err := syscall.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + createmode := uint32(syscall.OPEN_ALWAYS) + access := uint32(syscall.FILE_APPEND_DATA) + sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE) + h, err := syscall.CreateFile(pathp, access, sharemode, nil, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0) + if err != nil { + return nil, err + } + return os.NewFile(uintptr(h), path), nil +} + +// Copyright (c) 2009 The Go Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// fixLongPath returns the extended-length (\\?\-prefixed) form of +// path when needed, in order to avoid the default 260 character file +// path limit imposed by Windows. If path is not easily converted to +// the extended-length form (for example, if path is a relative path +// or contains .. elements), or is short enough, fixLongPath returns +// path unmodified. +// +// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath +// +// This is copied from https://golang.org/src/path/filepath/path_windows.go. +func fixLongPath(path string) string { + // Do nothing (and don't allocate) if the path is "short". + // Empirically (at least on the Windows Server 2013 builder), + // the kernel is arbitrarily okay with < 248 bytes. That + // matches what the docs above say: + // "When using an API to create a directory, the specified + // path cannot be so long that you cannot append an 8.3 file + // name (that is, the directory name cannot exceed MAX_PATH + // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. + // + // The MSDN docs appear to say that a normal path that is 248 bytes long + // will work; empirically the path must be less then 248 bytes long. + if len(path) < 248 { + // Don't fix. (This is how Go 1.7 and earlier worked, + // not automatically generating the \\?\ form) + return path + } + + // The extended form begins with \\?\, as in + // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. + // The extended form disables evaluation of . and .. path + // elements and disables the interpretation of / as equivalent + // to \. The conversion here rewrites / to \ and elides + // . elements as well as trailing or duplicate separators. For + // simplicity it avoids the conversion entirely for relative + // paths or paths containing .. elements. For now, + // \\server\share paths are not converted to + // \\?\UNC\server\share paths because the rules for doing so + // are less well-specified. + if len(path) >= 2 && path[:2] == `\\` { + // Don't canonicalize UNC paths. + return path + } + if !filepath.IsAbs(path) { + // Relative path + return path + } + + const prefix = `\\?` + + pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) + copy(pathbuf, prefix) + n := len(path) + r, w := 0, len(prefix) + for r < n { + switch { + case os.IsPathSeparator(path[r]): + // empty block + r++ + case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): + // /./ + r++ + case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): + // /../ is currently unhandled + return path + default: + pathbuf[w] = '\\' + w++ + for ; r < n && !os.IsPathSeparator(path[r]); r++ { + pathbuf[w] = path[r] + w++ + } + } + } + // A drive's root directory needs a trailing \ + if w == len(`\\?\c:`) { + pathbuf[w] = '\\' + w++ + } + return string(pathbuf[:w]) +} + +// ensureRemoveAll is a wrapper for os.RemoveAll on Windows. +func ensureRemoveAll(_ context.Context, dir string) error { + return os.RemoveAll(dir) +} + +func modifyProcessLabel(runtimeType string, spec *specs.Spec) error { + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/imagefs_info.go containerd-1.5.9/pkg/cri/server/imagefs_info.go --- containerd-1.2.6/pkg/cri/server/imagefs_info.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/imagefs_info.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "time" + + "golang.org/x/net/context" + + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// ImageFsInfo returns information of the filesystem that is used to store images. +// TODO(windows): Usage for windows is always 0 right now. Support this for windows. +func (c *criService) ImageFsInfo(ctx context.Context, r *runtime.ImageFsInfoRequest) (*runtime.ImageFsInfoResponse, error) { + snapshots := c.snapshotStore.List() + timestamp := time.Now().UnixNano() + var usedBytes, inodesUsed uint64 + for _, sn := range snapshots { + // Use the oldest timestamp as the timestamp of imagefs info. + if sn.Timestamp < timestamp { + timestamp = sn.Timestamp + } + usedBytes += sn.Size + inodesUsed += sn.Inodes + } + // TODO(random-liu): Handle content store + return &runtime.ImageFsInfoResponse{ + ImageFilesystems: []*runtime.FilesystemUsage{ + { + Timestamp: timestamp, + FsId: &runtime.FilesystemIdentifier{Mountpoint: c.imageFSPath}, + UsedBytes: &runtime.UInt64Value{Value: usedBytes}, + InodesUsed: &runtime.UInt64Value{Value: inodesUsed}, + }, + }, + }, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/imagefs_info_test.go containerd-1.5.9/pkg/cri/server/imagefs_info_test.go --- containerd-1.2.6/pkg/cri/server/imagefs_info_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/imagefs_info_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,70 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + snapshot "github.com/containerd/containerd/snapshots" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" +) + +func TestImageFsInfo(t *testing.T) { + c := newTestCRIService() + snapshots := []snapshotstore.Snapshot{ + { + Key: "key1", + Kind: snapshot.KindActive, + Size: 10, + Inodes: 100, + Timestamp: 234567, + }, + { + Key: "key2", + Kind: snapshot.KindCommitted, + Size: 20, + Inodes: 200, + Timestamp: 123456, + }, + { + Key: "key3", + Kind: snapshot.KindView, + Size: 0, + Inodes: 0, + Timestamp: 345678, + }, + } + expected := &runtime.FilesystemUsage{ + Timestamp: 123456, + FsId: &runtime.FilesystemIdentifier{Mountpoint: testImageFSPath}, + UsedBytes: &runtime.UInt64Value{Value: 30}, + InodesUsed: &runtime.UInt64Value{Value: 300}, + } + for _, sn := range snapshots { + c.snapshotStore.Add(sn) + } + resp, err := c.ImageFsInfo(context.Background(), &runtime.ImageFsInfoRequest{}) + require.NoError(t, err) + stats := resp.GetImageFilesystems() + assert.Len(t, stats, 1) + assert.Equal(t, expected, stats[0]) +} diff -Nru containerd-1.2.6/pkg/cri/server/image_list.go containerd-1.5.9/pkg/cri/server/image_list.go --- containerd-1.2.6/pkg/cri/server/image_list.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_list.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// ListImages lists existing images. +// TODO(random-liu): Add image list filters after CRI defines this more clear, and kubelet +// actually needs it. +func (c *criService) ListImages(ctx context.Context, r *runtime.ListImagesRequest) (*runtime.ListImagesResponse, error) { + imagesInStore := c.imageStore.List() + + var images []*runtime.Image + for _, image := range imagesInStore { + // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot + // doesn't exist? + images = append(images, toCRIImage(image)) + } + + return &runtime.ListImagesResponse{Images: images}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/image_list_test.go containerd-1.5.9/pkg/cri/server/image_list_test.go --- containerd-1.2.6/pkg/cri/server/image_list_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_list_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,113 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + imagestore "github.com/containerd/containerd/pkg/cri/store/image" +) + +func TestListImages(t *testing.T) { + c := newTestCRIService() + imagesInStore := []imagestore.Image{ + { + ID: "sha256:1123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ChainID: "test-chainid-1", + References: []string{ + "gcr.io/library/busybox:latest", + "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + Size: 1000, + ImageSpec: imagespec.Image{ + Config: imagespec.ImageConfig{ + User: "root", + }, + }, + }, + { + ID: "sha256:2123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ChainID: "test-chainid-2", + References: []string{ + "gcr.io/library/alpine:latest", + "gcr.io/library/alpine@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + Size: 2000, + ImageSpec: imagespec.Image{ + Config: imagespec.ImageConfig{ + User: "1234:1234", + }, + }, + }, + { + ID: "sha256:3123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ChainID: "test-chainid-3", + References: []string{ + "gcr.io/library/ubuntu:latest", + "gcr.io/library/ubuntu@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + Size: 3000, + ImageSpec: imagespec.Image{ + Config: imagespec.ImageConfig{ + User: "nobody", + }, + }, + }, + } + expect := []*runtime.Image{ + { + Id: "sha256:1123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + RepoTags: []string{"gcr.io/library/busybox:latest"}, + RepoDigests: []string{"gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582"}, + Size_: uint64(1000), + Username: "root", + }, + { + Id: "sha256:2123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + RepoTags: []string{"gcr.io/library/alpine:latest"}, + RepoDigests: []string{"gcr.io/library/alpine@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582"}, + Size_: uint64(2000), + Uid: &runtime.Int64Value{Value: 1234}, + }, + { + Id: "sha256:3123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + RepoTags: []string{"gcr.io/library/ubuntu:latest"}, + RepoDigests: []string{"gcr.io/library/ubuntu@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582"}, + Size_: uint64(3000), + Username: "nobody", + }, + } + + var err error + c.imageStore, err = imagestore.NewFakeStore(imagesInStore) + assert.NoError(t, err) + + resp, err := c.ListImages(context.Background(), &runtime.ListImagesRequest{}) + assert.NoError(t, err) + require.NotNil(t, resp) + images := resp.GetImages() + assert.Len(t, images, len(expect)) + for _, i := range expect { + assert.Contains(t, images, i) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/image_pull.go containerd-1.5.9/pkg/cri/server/image_pull.go --- containerd-1.2.6/pkg/cri/server/image_pull.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_pull.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,563 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "crypto/tls" + "crypto/x509" + "encoding/base64" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "path/filepath" + "strings" + "time" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + containerdimages "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/log" + distribution "github.com/containerd/containerd/reference/docker" + "github.com/containerd/containerd/remotes/docker" + "github.com/containerd/containerd/remotes/docker/config" + "github.com/containerd/imgcrypt" + "github.com/containerd/imgcrypt/images/encryption" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + criconfig "github.com/containerd/containerd/pkg/cri/config" +) + +// For image management: +// 1) We have an in-memory metadata index to: +// a. Maintain ImageID -> RepoTags, ImageID -> RepoDigset relationships; ImageID +// is the digest of image config, which conforms to oci image spec. +// b. Cache constant and useful information such as image chainID, config etc. +// c. An image will be added into the in-memory metadata only when it's successfully +// pulled and unpacked. +// +// 2) We use containerd image metadata store and content store: +// a. To resolve image reference (digest/tag) locally. During pulling image, we +// normalize the image reference provided by user, and put it into image metadata +// store with resolved descriptor. For the other operations, if image id is provided, +// we'll access the in-memory metadata index directly; if image reference is +// provided, we'll normalize it, resolve it in containerd image metadata store +// to get the image id. +// b. As the backup of in-memory metadata in 1). During startup, the in-memory +// metadata could be re-constructed from image metadata store + content store. +// +// Several problems with current approach: +// 1) An entry in containerd image metadata store doesn't mean a "READY" (successfully +// pulled and unpacked) image. E.g. during pulling, the client gets killed. In that case, +// if we saw an image without snapshots or with in-complete contents during startup, +// should we re-pull the image? Or should we remove the entry? +// +// yanxuean: We can't delete image directly, because we don't know if the image +// is pulled by us. There are resource leakage. +// +// 2) Containerd suggests user to add entry before pulling the image. However if +// an error occurs during the pulling, should we remove the entry from metadata +// store? Or should we leave it there until next startup (resource leakage)? +// +// 3) The cri plugin only exposes "READY" (successfully pulled and unpacked) images +// to the user, which are maintained in the in-memory metadata index. However, it's +// still possible that someone else removes the content or snapshot by-pass the cri plugin, +// how do we detect that and update the in-memory metadata correspondingly? Always +// check whether corresponding snapshot is ready when reporting image status? +// +// 4) Is the content important if we cached necessary information in-memory +// after we pull the image? How to manage the disk usage of contents? If some +// contents are missing but snapshots are ready, is the image still "READY"? + +// PullImage pulls an image with authentication config. +func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (*runtime.PullImageResponse, error) { + imageRef := r.GetImage().GetImage() + namedRef, err := distribution.ParseDockerRef(imageRef) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse image reference %q", imageRef) + } + ref := namedRef.String() + if ref != imageRef { + log.G(ctx).Debugf("PullImage using normalized image ref: %q", ref) + } + var ( + resolver = docker.NewResolver(docker.ResolverOptions{ + Headers: c.config.Registry.Headers, + Hosts: c.registryHosts(ctx, r.GetAuth()), + }) + isSchema1 bool + imageHandler containerdimages.HandlerFunc = func(_ context.Context, + desc imagespec.Descriptor) ([]imagespec.Descriptor, error) { + if desc.MediaType == containerdimages.MediaTypeDockerSchema1Manifest { + isSchema1 = true + } + return nil, nil + } + ) + + pullOpts := []containerd.RemoteOpt{ + containerd.WithSchema1Conversion, + containerd.WithResolver(resolver), + containerd.WithPullSnapshotter(c.config.ContainerdConfig.Snapshotter), + containerd.WithPullUnpack, + containerd.WithPullLabel(imageLabelKey, imageLabelValue), + containerd.WithMaxConcurrentDownloads(c.config.MaxConcurrentDownloads), + containerd.WithImageHandler(imageHandler), + } + + pullOpts = append(pullOpts, c.encryptedImagesPullOpts()...) + if !c.config.ContainerdConfig.DisableSnapshotAnnotations { + pullOpts = append(pullOpts, + containerd.WithImageHandlerWrapper(appendInfoHandlerWrapper(ref))) + } + + if c.config.ContainerdConfig.DiscardUnpackedLayers { + // Allows GC to clean layers up from the content store after unpacking + pullOpts = append(pullOpts, + containerd.WithChildLabelMap(containerdimages.ChildGCLabelsFilterLayers)) + } + + image, err := c.client.Pull(ctx, ref, pullOpts...) + if err != nil { + return nil, errors.Wrapf(err, "failed to pull and unpack image %q", ref) + } + + configDesc, err := image.Config(ctx) + if err != nil { + return nil, errors.Wrap(err, "get image config descriptor") + } + imageID := configDesc.Digest.String() + + repoDigest, repoTag := getRepoDigestAndTag(namedRef, image.Target().Digest, isSchema1) + for _, r := range []string{imageID, repoTag, repoDigest} { + if r == "" { + continue + } + if err := c.createImageReference(ctx, r, image.Target()); err != nil { + return nil, errors.Wrapf(err, "failed to create image reference %q", r) + } + // Update image store to reflect the newest state in containerd. + // No need to use `updateImage`, because the image reference must + // have been managed by the cri plugin. + if err := c.imageStore.Update(ctx, r); err != nil { + return nil, errors.Wrapf(err, "failed to update image store %q", r) + } + } + + log.G(ctx).Debugf("Pulled image %q with image id %q, repo tag %q, repo digest %q", imageRef, imageID, + repoTag, repoDigest) + // NOTE(random-liu): the actual state in containerd is the source of truth, even we maintain + // in-memory image store, it's only for in-memory indexing. The image could be removed + // by someone else anytime, before/during/after we create the metadata. We should always + // check the actual state in containerd before using the image or returning status of the + // image. + return &runtime.PullImageResponse{ImageRef: imageID}, nil +} + +// ParseAuth parses AuthConfig and returns username and password/secret required by containerd. +func ParseAuth(auth *runtime.AuthConfig, host string) (string, string, error) { + if auth == nil { + return "", "", nil + } + if auth.ServerAddress != "" { + // Do not return the auth info when server address doesn't match. + u, err := url.Parse(auth.ServerAddress) + if err != nil { + return "", "", errors.Wrap(err, "parse server address") + } + if host != u.Host { + return "", "", nil + } + } + if auth.Username != "" { + return auth.Username, auth.Password, nil + } + if auth.IdentityToken != "" { + return "", auth.IdentityToken, nil + } + if auth.Auth != "" { + decLen := base64.StdEncoding.DecodedLen(len(auth.Auth)) + decoded := make([]byte, decLen) + _, err := base64.StdEncoding.Decode(decoded, []byte(auth.Auth)) + if err != nil { + return "", "", err + } + fields := strings.SplitN(string(decoded), ":", 2) + if len(fields) != 2 { + return "", "", errors.Errorf("invalid decoded auth: %q", decoded) + } + user, passwd := fields[0], fields[1] + return user, strings.Trim(passwd, "\x00"), nil + } + // TODO(random-liu): Support RegistryToken. + // An empty auth config is valid for anonymous registry + return "", "", nil +} + +// createImageReference creates image reference inside containerd image store. +// Note that because create and update are not finished in one transaction, there could be race. E.g. +// the image reference is deleted by someone else after create returns already exists, but before update +// happens. +func (c *criService) createImageReference(ctx context.Context, name string, desc imagespec.Descriptor) error { + img := containerdimages.Image{ + Name: name, + Target: desc, + // Add a label to indicate that the image is managed by the cri plugin. + Labels: map[string]string{imageLabelKey: imageLabelValue}, + } + // TODO(random-liu): Figure out which is the more performant sequence create then update or + // update then create. + oldImg, err := c.client.ImageService().Create(ctx, img) + if err == nil || !errdefs.IsAlreadyExists(err) { + return err + } + if oldImg.Target.Digest == img.Target.Digest && oldImg.Labels[imageLabelKey] == imageLabelValue { + return nil + } + _, err = c.client.ImageService().Update(ctx, img, "target", "labels") + return err +} + +// updateImage updates image store to reflect the newest state of an image reference +// in containerd. If the reference is not managed by the cri plugin, the function also +// generates necessary metadata for the image and make it managed. +func (c *criService) updateImage(ctx context.Context, r string) error { + img, err := c.client.GetImage(ctx, r) + if err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "get image by reference") + } + if err == nil && img.Labels()[imageLabelKey] != imageLabelValue { + // Make sure the image has the image id as its unique + // identifier that references the image in its lifetime. + configDesc, err := img.Config(ctx) + if err != nil { + return errors.Wrap(err, "get image id") + } + id := configDesc.Digest.String() + if err := c.createImageReference(ctx, id, img.Target()); err != nil { + return errors.Wrapf(err, "create image id reference %q", id) + } + if err := c.imageStore.Update(ctx, id); err != nil { + return errors.Wrapf(err, "update image store for %q", id) + } + // The image id is ready, add the label to mark the image as managed. + if err := c.createImageReference(ctx, r, img.Target()); err != nil { + return errors.Wrap(err, "create managed label") + } + } + // If the image is not found, we should continue updating the cache, + // so that the image can be removed from the cache. + if err := c.imageStore.Update(ctx, r); err != nil { + return errors.Wrapf(err, "update image store for %q", r) + } + return nil +} + +// getTLSConfig returns a TLSConfig configured with a CA/Cert/Key specified by registryTLSConfig +func (c *criService) getTLSConfig(registryTLSConfig criconfig.TLSConfig) (*tls.Config, error) { + var ( + tlsConfig = &tls.Config{} + cert tls.Certificate + err error + ) + if registryTLSConfig.CertFile != "" && registryTLSConfig.KeyFile == "" { + return nil, errors.Errorf("cert file %q was specified, but no corresponding key file was specified", registryTLSConfig.CertFile) + } + if registryTLSConfig.CertFile == "" && registryTLSConfig.KeyFile != "" { + return nil, errors.Errorf("key file %q was specified, but no corresponding cert file was specified", registryTLSConfig.KeyFile) + } + if registryTLSConfig.CertFile != "" && registryTLSConfig.KeyFile != "" { + cert, err = tls.LoadX509KeyPair(registryTLSConfig.CertFile, registryTLSConfig.KeyFile) + if err != nil { + return nil, errors.Wrap(err, "failed to load cert file") + } + if len(cert.Certificate) != 0 { + tlsConfig.Certificates = []tls.Certificate{cert} + } + tlsConfig.BuildNameToCertificate() // nolint:staticcheck + } + + if registryTLSConfig.CAFile != "" { + caCertPool, err := x509.SystemCertPool() + if err != nil { + return nil, errors.Wrap(err, "failed to get system cert pool") + } + caCert, err := ioutil.ReadFile(registryTLSConfig.CAFile) + if err != nil { + return nil, errors.Wrap(err, "failed to load CA file") + } + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig.RootCAs = caCertPool + } + + tlsConfig.InsecureSkipVerify = registryTLSConfig.InsecureSkipVerify + return tlsConfig, nil +} + +func hostDirFromRoots(roots []string) func(string) (string, error) { + rootfn := make([]func(string) (string, error), len(roots)) + for i := range roots { + rootfn[i] = config.HostDirFromRoot(roots[i]) + } + return func(host string) (dir string, err error) { + for _, fn := range rootfn { + dir, err = fn(host) + if (err != nil && !errdefs.IsNotFound(err)) || (dir != "") { + break + } + } + return + } +} + +// registryHosts is the registry hosts to be used by the resolver. +func (c *criService) registryHosts(ctx context.Context, auth *runtime.AuthConfig) docker.RegistryHosts { + paths := filepath.SplitList(c.config.Registry.ConfigPath) + if len(paths) > 0 { + hostOptions := config.HostOptions{} + hostOptions.Credentials = func(host string) (string, string, error) { + hostauth := auth + if hostauth == nil { + config := c.config.Registry.Configs[host] + if config.Auth != nil { + hostauth = toRuntimeAuthConfig(*config.Auth) + } + } + return ParseAuth(hostauth, host) + } + hostOptions.HostDir = hostDirFromRoots(paths) + + return config.ConfigureHosts(ctx, hostOptions) + } + + return func(host string) ([]docker.RegistryHost, error) { + var registries []docker.RegistryHost + + endpoints, err := c.registryEndpoints(host) + if err != nil { + return nil, errors.Wrap(err, "get registry endpoints") + } + for _, e := range endpoints { + u, err := url.Parse(e) + if err != nil { + return nil, errors.Wrapf(err, "parse registry endpoint %q from mirrors", e) + } + + var ( + transport = newTransport() + client = &http.Client{Transport: transport} + config = c.config.Registry.Configs[u.Host] + ) + + if config.TLS != nil { + transport.TLSClientConfig, err = c.getTLSConfig(*config.TLS) + if err != nil { + return nil, errors.Wrapf(err, "get TLSConfig for registry %q", e) + } + } + + // Make a copy of `auth`, so that different authorizers would not reference + // the same auth variable. + auth := auth + if auth == nil && config.Auth != nil { + auth = toRuntimeAuthConfig(*config.Auth) + } + authorizer := docker.NewDockerAuthorizer( + docker.WithAuthClient(client), + docker.WithAuthCreds(func(host string) (string, string, error) { + return ParseAuth(auth, host) + })) + + if u.Path == "" { + u.Path = "/v2" + } + + registries = append(registries, docker.RegistryHost{ + Client: client, + Authorizer: authorizer, + Host: u.Host, + Scheme: u.Scheme, + Path: u.Path, + Capabilities: docker.HostCapabilityResolve | docker.HostCapabilityPull, + }) + } + return registries, nil + } +} + +// defaultScheme returns the default scheme for a registry host. +func defaultScheme(host string) string { + if h, _, err := net.SplitHostPort(host); err == nil { + host = h + } + if host == "localhost" || host == "127.0.0.1" || host == "::1" { + return "http" + } + return "https" +} + +// addDefaultScheme returns the endpoint with default scheme +func addDefaultScheme(endpoint string) (string, error) { + if strings.Contains(endpoint, "://") { + return endpoint, nil + } + ue := "dummy://" + endpoint + u, err := url.Parse(ue) + if err != nil { + return "", err + } + return fmt.Sprintf("%s://%s", defaultScheme(u.Host), endpoint), nil +} + +// registryEndpoints returns endpoints for a given host. +// It adds default registry endpoint if it does not exist in the passed-in endpoint list. +// It also supports wildcard host matching with `*`. +func (c *criService) registryEndpoints(host string) ([]string, error) { + var endpoints []string + _, ok := c.config.Registry.Mirrors[host] + if ok { + endpoints = c.config.Registry.Mirrors[host].Endpoints + } else { + endpoints = c.config.Registry.Mirrors["*"].Endpoints + } + defaultHost, err := docker.DefaultHost(host) + if err != nil { + return nil, errors.Wrap(err, "get default host") + } + for i := range endpoints { + en, err := addDefaultScheme(endpoints[i]) + if err != nil { + return nil, errors.Wrap(err, "parse endpoint url") + } + endpoints[i] = en + } + for _, e := range endpoints { + u, err := url.Parse(e) + if err != nil { + return nil, errors.Wrap(err, "parse endpoint url") + } + if u.Host == host { + // Do not add default if the endpoint already exists. + return endpoints, nil + } + } + return append(endpoints, defaultScheme(defaultHost)+"://"+defaultHost), nil +} + +// newTransport returns a new HTTP transport used to pull image. +// TODO(random-liu): Create a library and share this code with `ctr`. +func newTransport() *http.Transport { + return &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + FallbackDelay: 300 * time.Millisecond, + }).DialContext, + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 5 * time.Second, + } +} + +// encryptedImagesPullOpts returns the necessary list of pull options required +// for decryption of encrypted images based on the cri decryption configuration. +func (c *criService) encryptedImagesPullOpts() []containerd.RemoteOpt { + if c.config.ImageDecryption.KeyModel == criconfig.KeyModelNode { + ltdd := imgcrypt.Payload{} + decUnpackOpt := encryption.WithUnpackConfigApplyOpts(encryption.WithDecryptedUnpack(<dd)) + opt := containerd.WithUnpackOpts([]containerd.UnpackOpt{decUnpackOpt}) + return []containerd.RemoteOpt{opt} + } + return nil +} + +const ( + // targetRefLabel is a label which contains image reference and will be passed + // to snapshotters. + targetRefLabel = "containerd.io/snapshot/cri.image-ref" + // targetManifestDigestLabel is a label which contains manifest digest and will be passed + // to snapshotters. + targetManifestDigestLabel = "containerd.io/snapshot/cri.manifest-digest" + // targetLayerDigestLabel is a label which contains layer digest and will be passed + // to snapshotters. + targetLayerDigestLabel = "containerd.io/snapshot/cri.layer-digest" + // targetImageLayersLabel is a label which contains layer digests contained in + // the target image and will be passed to snapshotters for preparing layers in + // parallel. Skipping some layers is allowed and only affects performance. + targetImageLayersLabel = "containerd.io/snapshot/cri.image-layers" +) + +// appendInfoHandlerWrapper makes a handler which appends some basic information +// of images like digests for manifest and their child layers as annotations during unpack. +// These annotations will be passed to snapshotters as labels. These labels will be +// used mainly by stargz-based snapshotters for querying image contents from the +// registry. +func appendInfoHandlerWrapper(ref string) func(f containerdimages.Handler) containerdimages.Handler { + return func(f containerdimages.Handler) containerdimages.Handler { + return containerdimages.HandlerFunc(func(ctx context.Context, desc imagespec.Descriptor) ([]imagespec.Descriptor, error) { + children, err := f.Handle(ctx, desc) + if err != nil { + return nil, err + } + switch desc.MediaType { + case imagespec.MediaTypeImageManifest, containerdimages.MediaTypeDockerSchema2Manifest: + for i := range children { + c := &children[i] + if containerdimages.IsLayerType(c.MediaType) { + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + c.Annotations[targetRefLabel] = ref + c.Annotations[targetLayerDigestLabel] = c.Digest.String() + c.Annotations[targetImageLayersLabel] = getLayers(ctx, targetImageLayersLabel, children[i:], labels.Validate) + c.Annotations[targetManifestDigestLabel] = desc.Digest.String() + } + } + } + return children, nil + }) + } +} + +// getLayers returns comma-separated digests based on the passed list of +// descriptors. The returned list contains as many digests as possible as well +// as meets the label validation. +func getLayers(ctx context.Context, key string, descs []imagespec.Descriptor, validate func(k, v string) error) (layers string) { + var item string + for _, l := range descs { + if containerdimages.IsLayerType(l.MediaType) { + item = l.Digest.String() + if layers != "" { + item = "," + item + } + // This avoids the label hits the size limitation. + if err := validate(key, layers+item); err != nil { + log.G(ctx).WithError(err).WithField("label", key).Debugf("%q is omitted in the layers list", l.Digest.String()) + break + } + layers += item + } + } + return +} diff -Nru containerd-1.2.6/pkg/cri/server/image_pull_test.go containerd-1.5.9/pkg/cri/server/image_pull_test.go --- containerd-1.2.6/pkg/cri/server/image_pull_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_pull_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,379 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "testing" + + digest "github.com/opencontainers/go-digest" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + criconfig "github.com/containerd/containerd/pkg/cri/config" +) + +func TestParseAuth(t *testing.T) { + testUser := "username" + testPasswd := "password" + testAuthLen := base64.StdEncoding.EncodedLen(len(testUser + ":" + testPasswd)) + testAuth := make([]byte, testAuthLen) + base64.StdEncoding.Encode(testAuth, []byte(testUser+":"+testPasswd)) + invalidAuth := make([]byte, testAuthLen) + base64.StdEncoding.Encode(invalidAuth, []byte(testUser+"@"+testPasswd)) + for desc, test := range map[string]struct { + auth *runtime.AuthConfig + host string + expectedUser string + expectedSecret string + expectErr bool + }{ + "should not return error if auth config is nil": {}, + "should not return error if empty auth is provided for access to anonymous registry": { + auth: &runtime.AuthConfig{}, + expectErr: false, + }, + "should support identity token": { + auth: &runtime.AuthConfig{IdentityToken: "abcd"}, + expectedSecret: "abcd", + }, + "should support username and password": { + auth: &runtime.AuthConfig{ + Username: testUser, + Password: testPasswd, + }, + expectedUser: testUser, + expectedSecret: testPasswd, + }, + "should support auth": { + auth: &runtime.AuthConfig{Auth: string(testAuth)}, + expectedUser: testUser, + expectedSecret: testPasswd, + }, + "should return error for invalid auth": { + auth: &runtime.AuthConfig{Auth: string(invalidAuth)}, + expectErr: true, + }, + "should return empty auth if server address doesn't match": { + auth: &runtime.AuthConfig{ + Username: testUser, + Password: testPasswd, + ServerAddress: "https://registry-1.io", + }, + host: "registry-2.io", + expectedUser: "", + expectedSecret: "", + }, + "should return auth if server address matches": { + auth: &runtime.AuthConfig{ + Username: testUser, + Password: testPasswd, + ServerAddress: "https://registry-1.io", + }, + host: "registry-1.io", + expectedUser: testUser, + expectedSecret: testPasswd, + }, + "should return auth if server address is not specified": { + auth: &runtime.AuthConfig{ + Username: testUser, + Password: testPasswd, + }, + host: "registry-1.io", + expectedUser: testUser, + expectedSecret: testPasswd, + }, + } { + t.Logf("TestCase %q", desc) + u, s, err := ParseAuth(test.auth, test.host) + assert.Equal(t, test.expectErr, err != nil) + assert.Equal(t, test.expectedUser, u) + assert.Equal(t, test.expectedSecret, s) + } +} + +func TestRegistryEndpoints(t *testing.T) { + for desc, test := range map[string]struct { + mirrors map[string]criconfig.Mirror + host string + expected []string + }{ + "no mirror configured": { + mirrors: map[string]criconfig.Mirror{ + "registry-1.io": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-3.io", + }, + }, + "mirror configured": { + mirrors: map[string]criconfig.Mirror{ + "registry-3.io": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io", + }, + }, + "wildcard mirror configured": { + mirrors: map[string]criconfig.Mirror{ + "*": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io", + }, + }, + "host should take precedence if both host and wildcard mirrors are configured": { + mirrors: map[string]criconfig.Mirror{ + "*": { + Endpoints: []string{ + "https://registry-1.io", + }, + }, + "registry-3.io": { + Endpoints: []string{ + "https://registry-2.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-2.io", + "https://registry-3.io", + }, + }, + "default endpoint in list with http": { + mirrors: map[string]criconfig.Mirror{ + "registry-3.io": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + "http://registry-3.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-1.io", + "https://registry-2.io", + "http://registry-3.io", + }, + }, + "default endpoint in list with https": { + mirrors: map[string]criconfig.Mirror{ + "registry-3.io": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io", + }, + }, + "default endpoint in list with path": { + mirrors: map[string]criconfig.Mirror{ + "registry-3.io": { + Endpoints: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io/path", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-1.io", + "https://registry-2.io", + "https://registry-3.io/path", + }, + }, + "miss scheme endpoint in list with path": { + mirrors: map[string]criconfig.Mirror{ + "registry-3.io": { + Endpoints: []string{ + "https://registry-3.io", + "registry-1.io", + "127.0.0.1:1234", + }, + }, + }, + host: "registry-3.io", + expected: []string{ + "https://registry-3.io", + "https://registry-1.io", + "http://127.0.0.1:1234", + }, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + c.config.Registry.Mirrors = test.mirrors + got, err := c.registryEndpoints(test.host) + assert.NoError(t, err) + assert.Equal(t, test.expected, got) + } +} + +func TestDefaultScheme(t *testing.T) { + for desc, test := range map[string]struct { + host string + expected string + }{ + "should use http by default for localhost": { + host: "localhost", + expected: "http", + }, + "should use http by default for localhost with port": { + host: "localhost:8080", + expected: "http", + }, + "should use http by default for 127.0.0.1": { + host: "127.0.0.1", + expected: "http", + }, + "should use http by default for 127.0.0.1 with port": { + host: "127.0.0.1:8080", + expected: "http", + }, + "should use http by default for ::1": { + host: "::1", + expected: "http", + }, + "should use http by default for ::1 with port": { + host: "[::1]:8080", + expected: "http", + }, + "should use https by default for remote host": { + host: "remote", + expected: "https", + }, + "should use https by default for remote host with port": { + host: "remote:8080", + expected: "https", + }, + "should use https by default for remote ip": { + host: "8.8.8.8", + expected: "https", + }, + "should use https by default for remote ip with port": { + host: "8.8.8.8:8080", + expected: "https", + }, + } { + t.Logf("TestCase %q", desc) + got := defaultScheme(test.host) + assert.Equal(t, test.expected, got) + } +} + +func TestEncryptedImagePullOpts(t *testing.T) { + for desc, test := range map[string]struct { + keyModel string + expectedOpts int + }{ + "node key model should return one unpack opt": { + keyModel: criconfig.KeyModelNode, + expectedOpts: 1, + }, + "no key model selected should default to node key model": { + keyModel: "", + expectedOpts: 0, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + c.config.ImageDecryption.KeyModel = test.keyModel + got := len(c.encryptedImagesPullOpts()) + assert.Equal(t, test.expectedOpts, got) + } +} + +func TestImageLayersLabel(t *testing.T) { + sampleKey := "sampleKey" + sampleDigest, err := digest.Parse("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + assert.NoError(t, err) + sampleMaxSize := 300 + sampleValidate := func(k, v string) error { + if (len(k) + len(v)) > sampleMaxSize { + return fmt.Errorf("invalid: %q: %q", k, v) + } + return nil + } + + tests := []struct { + name string + layersNum int + wantNum int + }{ + { + name: "valid number of layers", + layersNum: 2, + wantNum: 2, + }, + { + name: "many layers", + layersNum: 5, // hits sampleMaxSize (300 chars). + wantNum: 4, // layers should be omitted for avoiding invalid label. + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var sampleLayers []imagespec.Descriptor + for i := 0; i < tt.layersNum; i++ { + sampleLayers = append(sampleLayers, imagespec.Descriptor{ + MediaType: imagespec.MediaTypeImageLayerGzip, + Digest: sampleDigest, + }) + } + gotS := getLayers(context.Background(), sampleKey, sampleLayers, sampleValidate) + got := len(strings.Split(gotS, ",")) + assert.Equal(t, tt.wantNum, got) + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/image_remove.go containerd-1.5.9/pkg/cri/server/image_remove.go --- containerd-1.2.6/pkg/cri/server/image_remove.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_remove.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,65 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" +) + +// RemoveImage removes the image. +// TODO(random-liu): Update CRI to pass image reference instead of ImageSpec. (See +// kubernetes/kubernetes#46255) +// TODO(random-liu): We should change CRI to distinguish image id and image spec. +// Remove the whole image no matter the it's image id or reference. This is the +// semantic defined in CRI now. +func (c *criService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequest) (*runtime.RemoveImageResponse, error) { + image, err := c.localResolve(r.GetImage().GetImage()) + if err != nil { + if err == store.ErrNotExist { + // return empty without error when image not found. + return &runtime.RemoveImageResponse{}, nil + } + return nil, errors.Wrapf(err, "can not resolve %q locally", r.GetImage().GetImage()) + } + + // Remove all image references. + for i, ref := range image.References { + var opts []images.DeleteOpt + if i == len(image.References)-1 { + // Delete the last image reference synchronously to trigger garbage collection. + // This is best effort. It is possible that the image reference is deleted by + // someone else before this point. + opts = []images.DeleteOpt{images.SynchronousDelete()} + } + err = c.client.ImageService().Delete(ctx, ref, opts...) + if err == nil || errdefs.IsNotFound(err) { + // Update image store to reflect the newest state in containerd. + if err := c.imageStore.Update(ctx, ref); err != nil { + return nil, errors.Wrapf(err, "failed to update image reference %q for %q", ref, image.ID) + } + continue + } + return nil, errors.Wrapf(err, "failed to delete image reference %q for %q", ref, image.ID) + } + return &runtime.RemoveImageResponse{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/image_status.go containerd-1.5.9/pkg/cri/server/image_status.go --- containerd-1.2.6/pkg/cri/server/image_status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + + "github.com/containerd/containerd/log" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" +) + +// ImageStatus returns the status of the image, returns nil if the image isn't present. +// TODO(random-liu): We should change CRI to distinguish image id and image spec. (See +// kubernetes/kubernetes#46255) +func (c *criService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequest) (*runtime.ImageStatusResponse, error) { + image, err := c.localResolve(r.GetImage().GetImage()) + if err != nil { + if err == store.ErrNotExist { + // return empty without error when image not found. + return &runtime.ImageStatusResponse{}, nil + } + return nil, errors.Wrapf(err, "can not resolve %q locally", r.GetImage().GetImage()) + } + // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot + // doesn't exist? + + runtimeImage := toCRIImage(image) + info, err := c.toCRIImageInfo(ctx, &image, r.GetVerbose()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate image info") + } + + return &runtime.ImageStatusResponse{ + Image: runtimeImage, + Info: info, + }, nil +} + +// toCRIImage converts internal image object to CRI runtime.Image. +func toCRIImage(image imagestore.Image) *runtime.Image { + repoTags, repoDigests := parseImageReferences(image.References) + runtimeImage := &runtime.Image{ + Id: image.ID, + RepoTags: repoTags, + RepoDigests: repoDigests, + Size_: uint64(image.Size), + } + uid, username := getUserFromImage(image.ImageSpec.Config.User) + if uid != nil { + runtimeImage.Uid = &runtime.Int64Value{Value: *uid} + } + runtimeImage.Username = username + + return runtimeImage +} + +// TODO (mikebrow): discuss moving this struct and / or constants for info map for some or all of these fields to CRI +type verboseImageInfo struct { + ChainID string `json:"chainID"` + ImageSpec imagespec.Image `json:"imageSpec"` +} + +// toCRIImageInfo converts internal image object information to CRI image status response info map. +func (c *criService) toCRIImageInfo(ctx context.Context, image *imagestore.Image, verbose bool) (map[string]string, error) { + if !verbose { + return nil, nil + } + + info := make(map[string]string) + + imi := &verboseImageInfo{ + ChainID: image.ChainID, + ImageSpec: image.ImageSpec, + } + + m, err := json.Marshal(imi) + if err == nil { + info["info"] = string(m) + } else { + log.G(ctx).WithError(err).Errorf("failed to marshal info %v", imi) + info["info"] = err.Error() + } + + return info, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/image_status_test.go containerd-1.5.9/pkg/cri/server/image_status_test.go --- containerd-1.2.6/pkg/cri/server/image_status_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/image_status_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + imagestore "github.com/containerd/containerd/pkg/cri/store/image" +) + +func TestImageStatus(t *testing.T) { + testID := "sha256:d848ce12891bf78792cda4a23c58984033b0c397a55e93a1556202222ecc5ed4" + image := imagestore.Image{ + ID: testID, + ChainID: "test-chain-id", + References: []string{ + "gcr.io/library/busybox:latest", + "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + Size: 1234, + ImageSpec: imagespec.Image{ + Config: imagespec.ImageConfig{ + User: "user:group", + }, + }, + } + expected := &runtime.Image{ + Id: testID, + RepoTags: []string{"gcr.io/library/busybox:latest"}, + RepoDigests: []string{"gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582"}, + Size_: uint64(1234), + Username: "user", + } + + c := newTestCRIService() + t.Logf("should return nil image spec without error for non-exist image") + resp, err := c.ImageStatus(context.Background(), &runtime.ImageStatusRequest{ + Image: &runtime.ImageSpec{Image: testID}, + }) + assert.NoError(t, err) + require.NotNil(t, resp) + assert.Nil(t, resp.GetImage()) + + c.imageStore, err = imagestore.NewFakeStore([]imagestore.Image{image}) + assert.NoError(t, err) + + t.Logf("should return correct image status for exist image") + resp, err = c.ImageStatus(context.Background(), &runtime.ImageStatusRequest{ + Image: &runtime.ImageSpec{Image: testID}, + }) + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Equal(t, expected, resp.GetImage()) +} diff -Nru containerd-1.2.6/pkg/cri/server/instrumented_service.go containerd-1.5.9/pkg/cri/server/instrumented_service.go --- containerd-1.2.6/pkg/cri/server/instrumented_service.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/instrumented_service.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,488 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "errors" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +// instrumentedService wraps service with containerd namespace and logs. +type instrumentedService struct { + c *criService +} + +func newInstrumentedService(c *criService) grpcServices { + return &instrumentedService{c: c} +} + +// checkInitialized returns error if the server is not fully initialized. +// GRPC service request handlers should return error before server is fully +// initialized. +// NOTE(random-liu): All following functions MUST check initialized at the beginning. +func (in *instrumentedService) checkInitialized() error { + if in.c.initialized.IsSet() { + return nil + } + return errors.New("server is not initialized yet") +} + +func (in *instrumentedService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (res *runtime.RunPodSandboxResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("RunPodsandbox for %+v", r.GetConfig().GetMetadata()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("RunPodSandbox for %+v failed, error", r.GetConfig().GetMetadata()) + } else { + log.G(ctx).Infof("RunPodSandbox for %+v returns sandbox id %q", r.GetConfig().GetMetadata(), res.GetPodSandboxId()) + } + }() + res, err = in.c.RunPodSandbox(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ListPodSandbox(ctx context.Context, r *runtime.ListPodSandboxRequest) (res *runtime.ListPodSandboxResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ListPodSandbox with filter %+v", r.GetFilter()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("ListPodSandbox failed") + } else { + log.G(ctx).Tracef("ListPodSandbox returns pod sandboxes %+v", res.GetItems()) + } + }() + res, err = in.c.ListPodSandbox(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) PodSandboxStatus(ctx context.Context, r *runtime.PodSandboxStatusRequest) (res *runtime.PodSandboxStatusResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("PodSandboxStatus for %q", r.GetPodSandboxId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("PodSandboxStatus for %q failed", r.GetPodSandboxId()) + } else { + log.G(ctx).Tracef("PodSandboxStatus for %q returns status %+v", r.GetPodSandboxId(), res.GetStatus()) + } + }() + res, err = in.c.PodSandboxStatus(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandboxRequest) (_ *runtime.StopPodSandboxResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("StopPodSandbox for %q", r.GetPodSandboxId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("StopPodSandbox for %q failed", r.GetPodSandboxId()) + } else { + log.G(ctx).Infof("StopPodSandbox for %q returns successfully", r.GetPodSandboxId()) + } + }() + res, err := in.c.StopPodSandbox(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodSandboxRequest) (_ *runtime.RemovePodSandboxResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("RemovePodSandbox for %q", r.GetPodSandboxId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("RemovePodSandbox for %q failed", r.GetPodSandboxId()) + } else { + log.G(ctx).Infof("RemovePodSandbox %q returns successfully", r.GetPodSandboxId()) + } + }() + res, err := in.c.RemovePodSandbox(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) PortForward(ctx context.Context, r *runtime.PortForwardRequest) (res *runtime.PortForwardResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("Portforward for %q port %v", r.GetPodSandboxId(), r.GetPort()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("Portforward for %q failed", r.GetPodSandboxId()) + } else { + log.G(ctx).Infof("Portforward for %q returns URL %q", r.GetPodSandboxId(), res.GetUrl()) + } + }() + res, err = in.c.PortForward(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) CreateContainer(ctx context.Context, r *runtime.CreateContainerRequest) (res *runtime.CreateContainerResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("CreateContainer within sandbox %q for container %+v", + r.GetPodSandboxId(), r.GetConfig().GetMetadata()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("CreateContainer within sandbox %q for %+v failed", + r.GetPodSandboxId(), r.GetConfig().GetMetadata()) + } else { + log.G(ctx).Infof("CreateContainer within sandbox %q for %+v returns container id %q", + r.GetPodSandboxId(), r.GetConfig().GetMetadata(), res.GetContainerId()) + } + }() + res, err = in.c.CreateContainer(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (_ *runtime.StartContainerResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("StartContainer for %q", r.GetContainerId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("StartContainer for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Infof("StartContainer for %q returns successfully", r.GetContainerId()) + } + }() + res, err := in.c.StartContainer(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ListContainers(ctx context.Context, r *runtime.ListContainersRequest) (res *runtime.ListContainersResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ListContainers with filter %+v", r.GetFilter()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ListContainers with filter %+v failed", r.GetFilter()) + } else { + log.G(ctx).Tracef("ListContainers with filter %+v returns containers %+v", + r.GetFilter(), res.GetContainers()) + } + }() + res, err = in.c.ListContainers(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ContainerStatus(ctx context.Context, r *runtime.ContainerStatusRequest) (res *runtime.ContainerStatusResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ContainerStatus for %q", r.GetContainerId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ContainerStatus for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Tracef("ContainerStatus for %q returns status %+v", r.GetContainerId(), res.GetStatus()) + } + }() + res, err = in.c.ContainerStatus(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) StopContainer(ctx context.Context, r *runtime.StopContainerRequest) (res *runtime.StopContainerResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("StopContainer for %q with timeout %d (s)", r.GetContainerId(), r.GetTimeout()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("StopContainer for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Infof("StopContainer for %q returns successfully", r.GetContainerId()) + } + }() + res, err = in.c.StopContainer(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (res *runtime.RemoveContainerResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("RemoveContainer for %q", r.GetContainerId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("RemoveContainer for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Infof("RemoveContainer for %q returns successfully", r.GetContainerId()) + } + }() + res, err = in.c.RemoveContainer(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (res *runtime.ExecSyncResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("ExecSync for %q with command %+v and timeout %d (s)", r.GetContainerId(), r.GetCmd(), r.GetTimeout()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ExecSync for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Debugf("ExecSync for %q returns with exit code %d", r.GetContainerId(), res.GetExitCode()) + } + }() + res, err = in.c.ExecSync(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) Exec(ctx context.Context, r *runtime.ExecRequest) (res *runtime.ExecResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("Exec for %q with command %+v, tty %v and stdin %v", + r.GetContainerId(), r.GetCmd(), r.GetTty(), r.GetStdin()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("Exec for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Debugf("Exec for %q returns URL %q", r.GetContainerId(), res.GetUrl()) + } + }() + res, err = in.c.Exec(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) Attach(ctx context.Context, r *runtime.AttachRequest) (res *runtime.AttachResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("Attach for %q with tty %v and stdin %v", r.GetContainerId(), r.GetTty(), r.GetStdin()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("Attach for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Debugf("Attach for %q returns URL %q", r.GetContainerId(), res.Url) + } + }() + res, err = in.c.Attach(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (res *runtime.UpdateContainerResourcesResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("UpdateContainerResources for %q with %+v", r.GetContainerId(), r.GetLinux()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("UpdateContainerResources for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Infof("UpdateContainerResources for %q returns successfully", r.GetContainerId()) + } + }() + res, err = in.c.UpdateContainerResources(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (res *runtime.PullImageResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("PullImage %q", r.GetImage().GetImage()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("PullImage %q failed", r.GetImage().GetImage()) + } else { + log.G(ctx).Infof("PullImage %q returns image reference %q", + r.GetImage().GetImage(), res.GetImageRef()) + } + }() + res, err = in.c.PullImage(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ListImages(ctx context.Context, r *runtime.ListImagesRequest) (res *runtime.ListImagesResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ListImages with filter %+v", r.GetFilter()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ListImages with filter %+v failed", r.GetFilter()) + } else { + log.G(ctx).Tracef("ListImages with filter %+v returns image list %+v", + r.GetFilter(), res.GetImages()) + } + }() + res, err = in.c.ListImages(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequest) (res *runtime.ImageStatusResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ImageStatus for %q", r.GetImage().GetImage()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ImageStatus for %q failed", r.GetImage().GetImage()) + } else { + log.G(ctx).Tracef("ImageStatus for %q returns image status %+v", + r.GetImage().GetImage(), res.GetImage()) + } + }() + res, err = in.c.ImageStatus(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequest) (_ *runtime.RemoveImageResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Infof("RemoveImage %q", r.GetImage().GetImage()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("RemoveImage %q failed", r.GetImage().GetImage()) + } else { + log.G(ctx).Infof("RemoveImage %q returns successfully", r.GetImage().GetImage()) + } + }() + res, err := in.c.RemoveImage(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ImageFsInfo(ctx context.Context, r *runtime.ImageFsInfoRequest) (res *runtime.ImageFsInfoResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("ImageFsInfo") + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("ImageFsInfo failed") + } else { + log.G(ctx).Debugf("ImageFsInfo returns filesystem info %+v", res.ImageFilesystems) + } + }() + res, err = in.c.ImageFsInfo(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ContainerStats(ctx context.Context, r *runtime.ContainerStatsRequest) (res *runtime.ContainerStatsResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("ContainerStats for %q", r.GetContainerId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ContainerStats for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Debugf("ContainerStats for %q returns stats %+v", r.GetContainerId(), res.GetStats()) + } + }() + res, err = in.c.ContainerStats(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ListContainerStats(ctx context.Context, r *runtime.ListContainerStatsRequest) (res *runtime.ListContainerStatsResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("ListContainerStats with filter %+v", r.GetFilter()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("ListContainerStats failed") + } else { + log.G(ctx).Tracef("ListContainerStats returns stats %+v", res.GetStats()) + } + }() + res, err = in.c.ListContainerStats(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) Status(ctx context.Context, r *runtime.StatusRequest) (res *runtime.StatusResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("Status") + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("Status failed") + } else { + log.G(ctx).Tracef("Status returns status %+v", res.GetStatus()) + } + }() + res, err = in.c.Status(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) Version(ctx context.Context, r *runtime.VersionRequest) (res *runtime.VersionResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Tracef("Version with client side version %q", r.GetVersion()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("Version failed") + } else { + log.G(ctx).Tracef("Version returns %+v", res) + } + }() + res, err = in.c.Version(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateRuntimeConfigRequest) (res *runtime.UpdateRuntimeConfigResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("UpdateRuntimeConfig with config %+v", r.GetRuntimeConfig()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Error("UpdateRuntimeConfig failed") + } else { + log.G(ctx).Debug("UpdateRuntimeConfig returns returns successfully") + } + }() + res, err = in.c.UpdateRuntimeConfig(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} + +func (in *instrumentedService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (res *runtime.ReopenContainerLogResponse, err error) { + if err := in.checkInitialized(); err != nil { + return nil, err + } + log.G(ctx).Debugf("ReopenContainerLog for %q", r.GetContainerId()) + defer func() { + if err != nil { + log.G(ctx).WithError(err).Errorf("ReopenContainerLog for %q failed", r.GetContainerId()) + } else { + log.G(ctx).Debugf("ReopenContainerLog for %q returns successfully", r.GetContainerId()) + } + }() + res, err = in.c.ReopenContainerLog(ctrdutil.WithNamespace(ctx), r) + return res, errdefs.ToGRPC(err) +} diff -Nru containerd-1.2.6/pkg/cri/server/opts.go containerd-1.5.9/pkg/cri/server/opts.go --- containerd-1.2.6/pkg/cri/server/opts.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,51 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/log" + "github.com/containerd/nri" + v1 "github.com/containerd/nri/types/v1" +) + +// WithNRISandboxDelete calls delete for a sandbox'd task +func WithNRISandboxDelete(sandboxID string) containerd.ProcessDeleteOpts { + return func(ctx context.Context, p containerd.Process) error { + task, ok := p.(containerd.Task) + if !ok { + return nil + } + nric, err := nri.New() + if err != nil { + log.G(ctx).WithError(err).Error("unable to create nri client") + return nil + } + if nric == nil { + return nil + } + sb := &nri.Sandbox{ + ID: sandboxID, + } + if _, err := nric.InvokeWithSandbox(ctx, task, v1.Delete, sb); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to delete nri for %q", task.ID()) + } + return nil + } +} diff -Nru containerd-1.2.6/pkg/cri/server/restart.go containerd-1.5.9/pkg/cri/server/restart.go --- containerd-1.2.6/pkg/cri/server/restart.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/restart.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,483 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io/ioutil" + "os" + "path/filepath" + goruntime "runtime" + "time" + + "github.com/containerd/containerd" + containerdio "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + containerdimages "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/platforms" + "github.com/containerd/typeurl" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + "github.com/containerd/containerd/pkg/netns" +) + +// NOTE: The recovery logic has following assumption: when the cri plugin is down: +// 1) Files (e.g. root directory, netns) and checkpoint maintained by the plugin MUST NOT be +// touched. Or else, recovery logic for those containers/sandboxes may return error. +// 2) Containerd containers may be deleted, but SHOULD NOT be added. Or else, recovery logic +// for the newly added container/sandbox will return error, because there is no corresponding root +// directory created. +// 3) Containerd container tasks may exit or be stopped, deleted. Even though current logic could +// tolerant tasks being created or started, we prefer that not to happen. + +// recover recovers system state from containerd and status checkpoint. +func (c *criService) recover(ctx context.Context) error { + // Recover all sandboxes. + sandboxes, err := c.client.Containers(ctx, filterLabel(containerKindLabel, containerKindSandbox)) + if err != nil { + return errors.Wrap(err, "failed to list sandbox containers") + } + for _, sandbox := range sandboxes { + sb, err := c.loadSandbox(ctx, sandbox) + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to load sandbox %q", sandbox.ID()) + continue + } + log.G(ctx).Debugf("Loaded sandbox %+v", sb) + if err := c.sandboxStore.Add(sb); err != nil { + return errors.Wrapf(err, "failed to add sandbox %q to store", sandbox.ID()) + } + if err := c.sandboxNameIndex.Reserve(sb.Name, sb.ID); err != nil { + return errors.Wrapf(err, "failed to reserve sandbox name %q", sb.Name) + } + } + + // Recover all containers. + containers, err := c.client.Containers(ctx, filterLabel(containerKindLabel, containerKindContainer)) + if err != nil { + return errors.Wrap(err, "failed to list containers") + } + for _, container := range containers { + cntr, err := c.loadContainer(ctx, container) + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to load container %q", container.ID()) + continue + } + log.G(ctx).Debugf("Loaded container %+v", cntr) + if err := c.containerStore.Add(cntr); err != nil { + return errors.Wrapf(err, "failed to add container %q to store", container.ID()) + } + if err := c.containerNameIndex.Reserve(cntr.Name, cntr.ID); err != nil { + return errors.Wrapf(err, "failed to reserve container name %q", cntr.Name) + } + } + + // Recover all images. + cImages, err := c.client.ListImages(ctx) + if err != nil { + return errors.Wrap(err, "failed to list images") + } + c.loadImages(ctx, cImages) + + // It's possible that containerd containers are deleted unexpectedly. In that case, + // we can't even get metadata, we should cleanup orphaned sandbox/container directories + // with best effort. + + // Cleanup orphaned sandbox and container directories without corresponding containerd container. + for _, cleanup := range []struct { + cntrs []containerd.Container + base string + errMsg string + }{ + { + cntrs: sandboxes, + base: filepath.Join(c.config.RootDir, sandboxesDir), + errMsg: "failed to cleanup orphaned sandbox directories", + }, + { + cntrs: sandboxes, + base: filepath.Join(c.config.StateDir, sandboxesDir), + errMsg: "failed to cleanup orphaned volatile sandbox directories", + }, + { + cntrs: containers, + base: filepath.Join(c.config.RootDir, containersDir), + errMsg: "failed to cleanup orphaned container directories", + }, + { + cntrs: containers, + base: filepath.Join(c.config.StateDir, containersDir), + errMsg: "failed to cleanup orphaned volatile container directories", + }, + } { + if err := cleanupOrphanedIDDirs(ctx, cleanup.cntrs, cleanup.base); err != nil { + return errors.Wrap(err, cleanup.errMsg) + } + } + return nil +} + +// loadContainerTimeout is the default timeout for loading a container/sandbox. +// One container/sandbox hangs (e.g. containerd#2438) should not affect other +// containers/sandboxes. +// Most CRI container/sandbox related operations are per container, the ones +// which handle multiple containers at a time are: +// * ListPodSandboxes: Don't talk with containerd services. +// * ListContainers: Don't talk with containerd services. +// * ListContainerStats: Not in critical code path, a default timeout will +// be applied at CRI level. +// * Recovery logic: We should set a time for each container/sandbox recovery. +// * Event monitor: We should set a timeout for each container/sandbox event handling. +const loadContainerTimeout = 10 * time.Second + +// loadContainer loads container from containerd and status checkpoint. +func (c *criService) loadContainer(ctx context.Context, cntr containerd.Container) (containerstore.Container, error) { + ctx, cancel := context.WithTimeout(ctx, loadContainerTimeout) + defer cancel() + id := cntr.ID() + containerDir := c.getContainerRootDir(id) + volatileContainerDir := c.getVolatileContainerRootDir(id) + var container containerstore.Container + // Load container metadata. + exts, err := cntr.Extensions(ctx) + if err != nil { + return container, errors.Wrap(err, "failed to get container extensions") + } + ext, ok := exts[containerMetadataExtension] + if !ok { + return container, errors.Errorf("metadata extension %q not found", containerMetadataExtension) + } + data, err := typeurl.UnmarshalAny(&ext) + if err != nil { + return container, errors.Wrapf(err, "failed to unmarshal metadata extension %q", ext) + } + meta := data.(*containerstore.Metadata) + + // Load status from checkpoint. + status, err := containerstore.LoadStatus(containerDir, id) + if err != nil { + log.G(ctx).WithError(err).Warnf("Failed to load container status for %q", id) + status = unknownContainerStatus() + } + + var containerIO *cio.ContainerIO + err = func() error { + // Load up-to-date status from containerd. + t, err := cntr.Task(ctx, func(fifos *containerdio.FIFOSet) (_ containerdio.IO, err error) { + stdoutWC, stderrWC, err := c.createContainerLoggers(meta.LogPath, meta.Config.GetTty()) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + if stdoutWC != nil { + stdoutWC.Close() + } + if stderrWC != nil { + stderrWC.Close() + } + } + }() + containerIO, err = cio.NewContainerIO(id, + cio.WithFIFOs(fifos), + ) + if err != nil { + return nil, err + } + containerIO.AddOutput("log", stdoutWC, stderrWC) + containerIO.Pipe() + return containerIO, nil + }) + if err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to load task") + } + var s containerd.Status + var notFound bool + if errdefs.IsNotFound(err) { + // Task is not found. + notFound = true + } else { + // Task is found. Get task status. + s, err = t.Status(ctx) + if err != nil { + // It's still possible that task is deleted during this window. + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to get task status") + } + notFound = true + } + } + if notFound { + // Task is not created or has been deleted, use the checkpointed status + // to generate container status. + switch status.State() { + case runtime.ContainerState_CONTAINER_CREATED: + // NOTE: Another possibility is that we've tried to start the container, but + // containerd got restarted during that. In that case, we still + // treat the container as `CREATED`. + containerIO, err = cio.NewContainerIO(id, + cio.WithNewFIFOs(volatileContainerDir, meta.Config.GetTty(), meta.Config.GetStdin()), + ) + if err != nil { + return errors.Wrap(err, "failed to create container io") + } + case runtime.ContainerState_CONTAINER_RUNNING: + // Container was in running state, but its task has been deleted, + // set unknown exited state. Container io is not needed in this case. + status.FinishedAt = time.Now().UnixNano() + status.ExitCode = unknownExitCode + status.Reason = unknownExitReason + default: + // Container is in exited/unknown state, return the status as it is. + } + } else { + // Task status is found. Update container status based on the up-to-date task status. + switch s.Status { + case containerd.Created: + // Task has been created, but not started yet. This could only happen if containerd + // gets restarted during container start. + // Container must be in `CREATED` state. + if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to delete task") + } + if status.State() != runtime.ContainerState_CONTAINER_CREATED { + return errors.Errorf("unexpected container state for created task: %q", status.State()) + } + case containerd.Running: + // Task is running. Container must be in `RUNNING` state, based on our assumption that + // "task should not be started when containerd is down". + switch status.State() { + case runtime.ContainerState_CONTAINER_EXITED: + return errors.Errorf("unexpected container state for running task: %q", status.State()) + case runtime.ContainerState_CONTAINER_RUNNING: + default: + // This may happen if containerd gets restarted after task is started, but + // before status is checkpointed. + status.StartedAt = time.Now().UnixNano() + status.Pid = t.Pid() + } + // Wait for the task for exit monitor. + // wait is a long running background request, no timeout needed. + exitCh, err := t.Wait(ctrdutil.NamespacedContext()) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to wait for task") + } + // Container was in running state, but its task has been deleted, + // set unknown exited state. + status.FinishedAt = time.Now().UnixNano() + status.ExitCode = unknownExitCode + status.Reason = unknownExitReason + } else { + // Start exit monitor. + c.eventMonitor.startContainerExitMonitor(context.Background(), id, status.Pid, exitCh) + } + case containerd.Stopped: + // Task is stopped. Updata status and delete the task. + if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to delete task") + } + status.FinishedAt = s.ExitTime.UnixNano() + status.ExitCode = int32(s.ExitStatus) + default: + return errors.Errorf("unexpected task status %q", s.Status) + } + } + return nil + }() + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to load container status for %q", id) + // Only set the unknown field in this case, because other fields may + // contain useful information loaded from the checkpoint. + status.Unknown = true + } + opts := []containerstore.Opts{ + containerstore.WithStatus(status, containerDir), + containerstore.WithContainer(cntr), + } + // containerIO could be nil for container in unknown state. + if containerIO != nil { + opts = append(opts, containerstore.WithContainerIO(containerIO)) + } + return containerstore.NewContainer(*meta, opts...) +} + +// loadSandbox loads sandbox from containerd. +func (c *criService) loadSandbox(ctx context.Context, cntr containerd.Container) (sandboxstore.Sandbox, error) { + ctx, cancel := context.WithTimeout(ctx, loadContainerTimeout) + defer cancel() + var sandbox sandboxstore.Sandbox + // Load sandbox metadata. + exts, err := cntr.Extensions(ctx) + if err != nil { + return sandbox, errors.Wrap(err, "failed to get sandbox container extensions") + } + ext, ok := exts[sandboxMetadataExtension] + if !ok { + return sandbox, errors.Errorf("metadata extension %q not found", sandboxMetadataExtension) + } + data, err := typeurl.UnmarshalAny(&ext) + if err != nil { + return sandbox, errors.Wrapf(err, "failed to unmarshal metadata extension %q", ext) + } + meta := data.(*sandboxstore.Metadata) + + s, err := func() (sandboxstore.Status, error) { + status := unknownSandboxStatus() + // Load sandbox created timestamp. + info, err := cntr.Info(ctx) + if err != nil { + return status, errors.Wrap(err, "failed to get sandbox container info") + } + status.CreatedAt = info.CreatedAt + + // Load sandbox state. + t, err := cntr.Task(ctx, nil) + if err != nil && !errdefs.IsNotFound(err) { + return status, errors.Wrap(err, "failed to load task") + } + var taskStatus containerd.Status + var notFound bool + if errdefs.IsNotFound(err) { + // Task is not found. + notFound = true + } else { + // Task is found. Get task status. + taskStatus, err = t.Status(ctx) + if err != nil { + // It's still possible that task is deleted during this window. + if !errdefs.IsNotFound(err) { + return status, errors.Wrap(err, "failed to get task status") + } + notFound = true + } + } + if notFound { + // Task does not exist, set sandbox state as NOTREADY. + status.State = sandboxstore.StateNotReady + } else { + if taskStatus.Status == containerd.Running { + // Wait for the task for sandbox monitor. + // wait is a long running background request, no timeout needed. + exitCh, err := t.Wait(ctrdutil.NamespacedContext()) + if err != nil { + if !errdefs.IsNotFound(err) { + return status, errors.Wrap(err, "failed to wait for task") + } + status.State = sandboxstore.StateNotReady + } else { + // Task is running, set sandbox state as READY. + status.State = sandboxstore.StateReady + status.Pid = t.Pid() + c.eventMonitor.startSandboxExitMonitor(context.Background(), meta.ID, status.Pid, exitCh) + } + } else { + // Task is not running. Delete the task and set sandbox state as NOTREADY. + if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { + return status, errors.Wrap(err, "failed to delete task") + } + status.State = sandboxstore.StateNotReady + } + } + return status, nil + }() + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to load sandbox status for %q", cntr.ID()) + } + + sandbox = sandboxstore.NewSandbox(*meta, s) + sandbox.Container = cntr + + // Load network namespace. + if goruntime.GOOS != "windows" && + meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE { + // Don't need to load netns for host network sandbox. + return sandbox, nil + } + sandbox.NetNS = netns.LoadNetNS(meta.NetNSPath) + + // It doesn't matter whether task is running or not. If it is running, sandbox + // status will be `READY`; if it is not running, sandbox status will be `NOT_READY`, + // kubelet will stop the sandbox which will properly cleanup everything. + return sandbox, nil +} + +// loadImages loads images from containerd. +func (c *criService) loadImages(ctx context.Context, cImages []containerd.Image) { + snapshotter := c.config.ContainerdConfig.Snapshotter + for _, i := range cImages { + ok, _, _, _, err := containerdimages.Check(ctx, i.ContentStore(), i.Target(), platforms.Default()) + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to check image content readiness for %q", i.Name()) + continue + } + if !ok { + log.G(ctx).Warnf("The image content readiness for %q is not ok", i.Name()) + continue + } + // Checking existence of top-level snapshot for each image being recovered. + unpacked, err := i.IsUnpacked(ctx, snapshotter) + if err != nil { + log.G(ctx).WithError(err).Warnf("Failed to check whether image is unpacked for image %s", i.Name()) + continue + } + if !unpacked { + log.G(ctx).Warnf("The image %s is not unpacked.", i.Name()) + // TODO(random-liu): Consider whether we should try unpack here. + } + if err := c.updateImage(ctx, i.Name()); err != nil { + log.G(ctx).WithError(err).Warnf("Failed to update reference for image %q", i.Name()) + continue + } + log.G(ctx).Debugf("Loaded image %q", i.Name()) + } +} + +func cleanupOrphanedIDDirs(ctx context.Context, cntrs []containerd.Container, base string) error { + // Cleanup orphaned id directories. + dirs, err := ioutil.ReadDir(base) + if err != nil && !os.IsNotExist(err) { + return errors.Wrap(err, "failed to read base directory") + } + idsMap := make(map[string]containerd.Container) + for _, cntr := range cntrs { + idsMap[cntr.ID()] = cntr + } + for _, d := range dirs { + if !d.IsDir() { + log.G(ctx).Warnf("Invalid file %q found in base directory %q", d.Name(), base) + continue + } + if _, ok := idsMap[d.Name()]; ok { + // Do not remove id directory if corresponding container is found. + continue + } + dir := filepath.Join(base, d.Name()) + if err := ensureRemoveAll(ctx, dir); err != nil { + log.G(ctx).WithError(err).Warnf("Failed to remove id directory %q", dir) + } else { + log.G(ctx).Debugf("Cleanup orphaned id directory %q", dir) + } + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_list.go containerd-1.5.9/pkg/cri/server/sandbox_list.go --- containerd-1.2.6/pkg/cri/server/sandbox_list.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_list.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,101 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +// ListPodSandbox returns a list of Sandbox. +func (c *criService) ListPodSandbox(ctx context.Context, r *runtime.ListPodSandboxRequest) (*runtime.ListPodSandboxResponse, error) { + // List all sandboxes from store. + sandboxesInStore := c.sandboxStore.List() + var sandboxes []*runtime.PodSandbox + for _, sandboxInStore := range sandboxesInStore { + sandboxes = append(sandboxes, toCRISandbox( + sandboxInStore.Metadata, + sandboxInStore.Status.Get(), + )) + } + + sandboxes = c.filterCRISandboxes(sandboxes, r.GetFilter()) + return &runtime.ListPodSandboxResponse{Items: sandboxes}, nil +} + +// toCRISandbox converts sandbox metadata into CRI pod sandbox. +func toCRISandbox(meta sandboxstore.Metadata, status sandboxstore.Status) *runtime.PodSandbox { + // Set sandbox state to NOTREADY by default. + state := runtime.PodSandboxState_SANDBOX_NOTREADY + if status.State == sandboxstore.StateReady { + state = runtime.PodSandboxState_SANDBOX_READY + } + return &runtime.PodSandbox{ + Id: meta.ID, + Metadata: meta.Config.GetMetadata(), + State: state, + CreatedAt: status.CreatedAt.UnixNano(), + Labels: meta.Config.GetLabels(), + Annotations: meta.Config.GetAnnotations(), + RuntimeHandler: meta.RuntimeHandler, + } +} + +func (c *criService) normalizePodSandboxFilter(filter *runtime.PodSandboxFilter) { + if sb, err := c.sandboxStore.Get(filter.GetId()); err == nil { + filter.Id = sb.ID + } +} + +// filterCRISandboxes filters CRISandboxes. +func (c *criService) filterCRISandboxes(sandboxes []*runtime.PodSandbox, filter *runtime.PodSandboxFilter) []*runtime.PodSandbox { + if filter == nil { + return sandboxes + } + + c.normalizePodSandboxFilter(filter) + filtered := []*runtime.PodSandbox{} + for _, s := range sandboxes { + // Filter by id + if filter.GetId() != "" && filter.GetId() != s.Id { + continue + } + // Filter by state + if filter.GetState() != nil && filter.GetState().GetState() != s.State { + continue + } + // Filter by label + if filter.GetLabelSelector() != nil { + match := true + for k, v := range filter.GetLabelSelector() { + got, ok := s.Labels[k] + if !ok || got != v { + match = false + break + } + } + if !match { + continue + } + } + filtered = append(filtered, s) + } + + return filtered +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_list_test.go containerd-1.5.9/pkg/cri/server/sandbox_list_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_list_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_list_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,208 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +func TestToCRISandbox(t *testing.T) { + config := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-name", + Uid: "test-uid", + Namespace: "test-ns", + Attempt: 1, + }, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + } + createdAt := time.Now() + meta := sandboxstore.Metadata{ + ID: "test-id", + Name: "test-name", + Config: config, + NetNSPath: "test-netns", + RuntimeHandler: "test-runtime-handler", + } + expect := &runtime.PodSandbox{ + Id: "test-id", + Metadata: config.GetMetadata(), + CreatedAt: createdAt.UnixNano(), + Labels: config.GetLabels(), + Annotations: config.GetAnnotations(), + RuntimeHandler: "test-runtime-handler", + } + for desc, test := range map[string]struct { + state sandboxstore.State + expectedState runtime.PodSandboxState + }{ + "sandbox state ready": { + state: sandboxstore.StateReady, + expectedState: runtime.PodSandboxState_SANDBOX_READY, + }, + "sandbox state not ready": { + state: sandboxstore.StateNotReady, + expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, + }, + "sandbox state unknown": { + state: sandboxstore.StateUnknown, + expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, + }, + } { + status := sandboxstore.Status{ + CreatedAt: createdAt, + State: test.state, + } + expect.State = test.expectedState + s := toCRISandbox(meta, status) + assert.Equal(t, expect, s, desc) + } +} + +func TestFilterSandboxes(t *testing.T) { + c := newTestCRIService() + sandboxes := []sandboxstore.Sandbox{ + sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: "1abcdef", + Name: "sandboxname-1", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "podname-1", + Uid: "uid-1", + Namespace: "ns-1", + Attempt: 1, + }, + }, + RuntimeHandler: "test-runtime-handler", + }, + sandboxstore.Status{ + CreatedAt: time.Now(), + State: sandboxstore.StateReady, + }, + ), + sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: "2abcdef", + Name: "sandboxname-2", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "podname-2", + Uid: "uid-2", + Namespace: "ns-2", + Attempt: 2, + }, + Labels: map[string]string{"a": "b"}, + }, + RuntimeHandler: "test-runtime-handler", + }, + sandboxstore.Status{ + CreatedAt: time.Now(), + State: sandboxstore.StateNotReady, + }, + ), + sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: "3abcdef", + Name: "sandboxname-3", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "podname-2", + Uid: "uid-2", + Namespace: "ns-2", + Attempt: 2, + }, + Labels: map[string]string{"c": "d"}, + }, + RuntimeHandler: "test-runtime-handler", + }, + sandboxstore.Status{ + CreatedAt: time.Now(), + State: sandboxstore.StateReady, + }, + ), + } + + // Create PodSandbox + testSandboxes := []*runtime.PodSandbox{} + for _, sb := range sandboxes { + testSandboxes = append(testSandboxes, toCRISandbox(sb.Metadata, sb.Status.Get())) + } + + // Inject test sandbox metadata + for _, sb := range sandboxes { + assert.NoError(t, c.sandboxStore.Add(sb)) + } + + for desc, test := range map[string]struct { + filter *runtime.PodSandboxFilter + expect []*runtime.PodSandbox + }{ + "no filter": { + expect: testSandboxes, + }, + "id filter": { + filter: &runtime.PodSandboxFilter{Id: "2abcdef"}, + expect: []*runtime.PodSandbox{testSandboxes[1]}, + }, + "truncid filter": { + filter: &runtime.PodSandboxFilter{Id: "2"}, + expect: []*runtime.PodSandbox{testSandboxes[1]}, + }, + "state filter": { + filter: &runtime.PodSandboxFilter{ + State: &runtime.PodSandboxStateValue{ + State: runtime.PodSandboxState_SANDBOX_READY, + }, + }, + expect: []*runtime.PodSandbox{testSandboxes[0], testSandboxes[2]}, + }, + "label filter": { + filter: &runtime.PodSandboxFilter{ + LabelSelector: map[string]string{"a": "b"}, + }, + expect: []*runtime.PodSandbox{testSandboxes[1]}, + }, + "mixed filter not matched": { + filter: &runtime.PodSandboxFilter{ + Id: "1", + LabelSelector: map[string]string{"a": "b"}, + }, + expect: []*runtime.PodSandbox{}, + }, + "mixed filter matched": { + filter: &runtime.PodSandboxFilter{ + State: &runtime.PodSandboxStateValue{ + State: runtime.PodSandboxState_SANDBOX_READY, + }, + LabelSelector: map[string]string{"c": "d"}, + }, + expect: []*runtime.PodSandbox{testSandboxes[2]}, + }, + } { + t.Logf("TestCase: %s", desc) + filtered := c.filterCRISandboxes(testSandboxes, test.filter) + assert.Equal(t, test.expect, filtered, desc) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_portforward.go containerd-1.5.9/pkg/cri/server/sandbox_portforward.go --- containerd-1.2.6/pkg/cri/server/sandbox_portforward.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_portforward.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address. +func (c *criService) PortForward(ctx context.Context, r *runtime.PortForwardRequest) (retRes *runtime.PortForwardResponse, retErr error) { + sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) + if err != nil { + return nil, errors.Wrapf(err, "failed to find sandbox %q", r.GetPodSandboxId()) + } + if sandbox.Status.Get().State != sandboxstore.StateReady { + return nil, errors.New("sandbox container is not running") + } + // TODO(random-liu): Verify that ports are exposed. + return c.streamServer.GetPortForward(r) +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_portforward_linux.go containerd-1.5.9/pkg/cri/server/sandbox_portforward_linux.go --- containerd-1.2.6/pkg/cri/server/sandbox_portforward_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_portforward_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,138 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "fmt" + "io" + "net" + "time" + + "github.com/containerd/containerd/log" + "github.com/containernetworking/plugins/pkg/ns" + "github.com/pkg/errors" + "golang.org/x/net/context" + + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// portForward uses netns to enter the sandbox namespace, and forwards a stream inside the +// the namespace to a specific port. It keeps forwarding until it exits or client disconnect. +func (c *criService) portForward(ctx context.Context, id string, port int32, stream io.ReadWriteCloser) error { + s, err := c.sandboxStore.Get(id) + if err != nil { + return errors.Wrapf(err, "failed to find sandbox %q in store", id) + } + + var netNSDo func(func(ns.NetNS) error) error + // netNSPath is the network namespace path for logging. + var netNSPath string + securityContext := s.Config.GetLinux().GetSecurityContext() + hostNet := securityContext.GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE + if !hostNet { + if closed, err := s.NetNS.Closed(); err != nil { + return errors.Wrapf(err, "failed to check netwok namespace closed for sandbox %q", id) + } else if closed { + return errors.Errorf("network namespace for sandbox %q is closed", id) + } + netNSDo = s.NetNS.Do + netNSPath = s.NetNS.GetPath() + } else { + // Run the function directly for host network. + netNSDo = func(do func(_ ns.NetNS) error) error { + return do(nil) + } + netNSPath = "host" + } + + log.G(ctx).Infof("Executing port forwarding in network namespace %q", netNSPath) + err = netNSDo(func(_ ns.NetNS) error { + defer stream.Close() + // localhost can resolve to both IPv4 and IPv6 addresses in dual-stack systems + // but the application can be listening in one of the IP families only. + // golang has enabled RFC 6555 Fast Fallback (aka HappyEyeballs) by default in 1.12 + // It means that if a host resolves to both IPv6 and IPv4, it will try to connect to any + // of those addresses and use the working connection. + // However, the implementation uses go routines to start both connections in parallel, + // and this cases that the connection is done outside the namespace, so we try to connect + // serially. + // We try IPv4 first to keep current behavior and we fallback to IPv6 if the connection fails. + // xref https://github.com/golang/go/issues/44922 + var conn net.Conn + conn, err := net.Dial("tcp4", fmt.Sprintf("localhost:%d", port)) + if err != nil { + var errV6 error + conn, errV6 = net.Dial("tcp6", fmt.Sprintf("localhost:%d", port)) + if errV6 != nil { + return fmt.Errorf("failed to connect to localhost:%d inside namespace %q, IPv4: %v IPv6 %v ", port, id, err, errV6) + } + } + defer conn.Close() + + errCh := make(chan error, 2) + // Copy from the the namespace port connection to the client stream + go func() { + log.G(ctx).Debugf("PortForward copying data from namespace %q port %d to the client stream", id, port) + _, err := io.Copy(stream, conn) + errCh <- err + }() + + // Copy from the client stream to the namespace port connection + go func() { + log.G(ctx).Debugf("PortForward copying data from client stream to namespace %q port %d", id, port) + _, err := io.Copy(conn, stream) + errCh <- err + }() + + // Wait until the first error is returned by one of the connections + // we use errFwd to store the result of the port forwarding operation + // if the context is cancelled close everything and return + var errFwd error + select { + case errFwd = <-errCh: + log.G(ctx).Debugf("PortForward stop forwarding in one direction in network namespace %q port %d: %v", id, port, errFwd) + case <-ctx.Done(): + log.G(ctx).Debugf("PortForward cancelled in network namespace %q port %d: %v", id, port, ctx.Err()) + return ctx.Err() + } + // give a chance to terminate gracefully or timeout + // after 1s + // https://linux.die.net/man/1/socat + const timeout = time.Second + select { + case e := <-errCh: + if errFwd == nil { + errFwd = e + } + log.G(ctx).Debugf("PortForward stopped forwarding in both directions in network namespace %q port %d: %v", id, port, e) + case <-time.After(timeout): + log.G(ctx).Debugf("PortForward timed out waiting to close the connection in network namespace %q port %d", id, port) + case <-ctx.Done(): + log.G(ctx).Debugf("PortForward cancelled in network namespace %q port %d: %v", id, port, ctx.Err()) + errFwd = ctx.Err() + } + + return errFwd + }) + + if err != nil { + return errors.Wrapf(err, "failed to execute portforward in network namespace %q", netNSPath) + } + log.G(ctx).Infof("Finish port forwarding for %q port %d", id, port) + + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_portforward_other.go containerd-1.5.9/pkg/cri/server/sandbox_portforward_other.go --- containerd-1.2.6/pkg/cri/server/sandbox_portforward_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_portforward_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io" + + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + "golang.org/x/net/context" +) + +// portForward uses netns to enter the sandbox namespace, and forwards a stream inside the +// the namespace to a specific port. It keeps forwarding until it exits or client disconnect. +func (c *criService) portForward(ctx context.Context, id string, port int32, stream io.ReadWriteCloser) error { + return errors.Wrap(errdefs.ErrNotImplemented, "port forward") +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_portforward_windows.go containerd-1.5.9/pkg/cri/server/sandbox_portforward_windows.go --- containerd-1.2.6/pkg/cri/server/sandbox_portforward_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_portforward_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,80 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "bytes" + "fmt" + "io" + + "github.com/pkg/errors" + "golang.org/x/net/context" + "k8s.io/utils/exec" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + "github.com/containerd/containerd/pkg/ioutil" +) + +func (c *criService) portForward(ctx context.Context, id string, port int32, stream io.ReadWriter) error { + stdout := ioutil.NewNopWriteCloser(stream) + stderrBuffer := new(bytes.Buffer) + stderr := ioutil.NewNopWriteCloser(stderrBuffer) + // localhost is resolved to 127.0.0.1 in ipv4, and ::1 in ipv6. + // Explicitly using ipv4 IP address in here to avoid flakiness. + cmd := []string{"wincat.exe", "127.0.0.1", fmt.Sprint(port)} + err := c.execInSandbox(ctx, id, cmd, stream, stdout, stderr) + if err != nil { + return errors.Wrapf(err, "failed to execute port forward in sandbox: %s", stderrBuffer.String()) + } + return nil +} + +func (c *criService) execInSandbox(ctx context.Context, sandboxID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser) error { + // Get sandbox from our sandbox store. + sb, err := c.sandboxStore.Get(sandboxID) + if err != nil { + return errors.Wrapf(err, "failed to find sandbox %q in store", sandboxID) + } + + // Check the sandbox state + state := sb.Status.Get().State + if state != sandboxstore.StateReady { + return errors.Errorf("sandbox is in %s state", fmt.Sprint(state)) + } + + opts := execOptions{ + cmd: cmd, + stdin: stdin, + stdout: stdout, + stderr: stderr, + tty: false, + resize: nil, + } + exitCode, err := c.execInternal(ctx, sb.Container, sandboxID, opts) + if err != nil { + return errors.Wrap(err, "failed to exec in sandbox") + } + if *exitCode == 0 { + return nil + } + return &exec.CodeExitError{ + Err: errors.Errorf("error executing command %v, exit code %d", cmd, *exitCode), + Code: int(*exitCode), + } +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_remove.go containerd-1.5.9/pkg/cri/server/sandbox_remove.go --- containerd-1.2.6/pkg/cri/server/sandbox_remove.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_remove.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,115 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +// RemovePodSandbox removes the sandbox. If there are running containers in the +// sandbox, they should be forcibly removed. +func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodSandboxRequest) (*runtime.RemovePodSandboxResponse, error) { + sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) + if err != nil { + if err != store.ErrNotExist { + return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q", + r.GetPodSandboxId()) + } + // Do not return error if the id doesn't exist. + log.G(ctx).Tracef("RemovePodSandbox called for sandbox %q that does not exist", + r.GetPodSandboxId()) + return &runtime.RemovePodSandboxResponse{}, nil + } + // Use the full sandbox id. + id := sandbox.ID + + // If the sandbox is still running or in an unknown state, forcibly stop it. + state := sandbox.Status.Get().State + if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown { + logrus.Infof("Forcibly stopping sandbox %q", id) + if err := c.stopPodSandbox(ctx, sandbox); err != nil { + return nil, errors.Wrapf(err, "failed to forcibly stop sandbox %q", id) + } + } + + // Return error if sandbox network namespace is not closed yet. + if sandbox.NetNS != nil { + nsPath := sandbox.NetNS.GetPath() + if closed, err := sandbox.NetNS.Closed(); err != nil { + return nil, errors.Wrapf(err, "failed to check sandbox network namespace %q closed", nsPath) + } else if !closed { + return nil, errors.Errorf("sandbox network namespace %q is not fully closed", nsPath) + } + } + + // Remove all containers inside the sandbox. + // NOTE(random-liu): container could still be created after this point, Kubelet should + // not rely on this behavior. + // TODO(random-liu): Introduce an intermediate state to avoid container creation after + // this point. + cntrs := c.containerStore.List() + for _, cntr := range cntrs { + if cntr.SandboxID != id { + continue + } + _, err = c.RemoveContainer(ctx, &runtime.RemoveContainerRequest{ContainerId: cntr.ID}) + if err != nil { + return nil, errors.Wrapf(err, "failed to remove container %q", cntr.ID) + } + } + + // Cleanup the sandbox root directories. + sandboxRootDir := c.getSandboxRootDir(id) + if err := ensureRemoveAll(ctx, sandboxRootDir); err != nil { + return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q", + sandboxRootDir) + } + volatileSandboxRootDir := c.getVolatileSandboxRootDir(id) + if err := ensureRemoveAll(ctx, volatileSandboxRootDir); err != nil { + return nil, errors.Wrapf(err, "failed to remove volatile sandbox root directory %q", + volatileSandboxRootDir) + } + + // Delete sandbox container. + if err := sandbox.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil { + if !errdefs.IsNotFound(err) { + return nil, errors.Wrapf(err, "failed to delete sandbox container %q", id) + } + log.G(ctx).Tracef("Remove called for sandbox container %q that does not exist", id) + } + + // Remove sandbox from sandbox store. Note that once the sandbox is successfully + // deleted: + // 1) ListPodSandbox will not include this sandbox. + // 2) PodSandboxStatus and StopPodSandbox will return error. + // 3) On-going operations which have held the reference will not be affected. + c.sandboxStore.Delete(id) + + // Release the sandbox name reserved for the sandbox. + c.sandboxNameIndex.ReleaseByKey(id) + + return &runtime.RemovePodSandboxResponse{}, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run.go containerd-1.5.9/pkg/cri/server/sandbox_run.go --- containerd-1.2.6/pkg/cri/server/sandbox_run.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,560 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + "math" + "path/filepath" + goruntime "runtime" + "strings" + + "github.com/containerd/containerd" + containerdio "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + cni "github.com/containerd/go-cni" + "github.com/containerd/nri" + v1 "github.com/containerd/nri/types/v1" + "github.com/containerd/typeurl" + "github.com/davecgh/go-spew/spew" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + criconfig "github.com/containerd/containerd/pkg/cri/config" + customopts "github.com/containerd/containerd/pkg/cri/opts" + "github.com/containerd/containerd/pkg/cri/server/bandwidth" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + "github.com/containerd/containerd/pkg/cri/util" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + "github.com/containerd/containerd/pkg/netns" + "github.com/containerd/containerd/snapshots" + selinux "github.com/opencontainers/selinux/go-selinux" +) + +func init() { + typeurl.Register(&sandboxstore.Metadata{}, + "github.com/containerd/cri/pkg/store/sandbox", "Metadata") +} + +// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure +// the sandbox is in ready state. +func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) { + config := r.GetConfig() + log.G(ctx).Debugf("Sandbox config %+v", config) + + // Generate unique id and name for the sandbox and reserve the name. + id := util.GenerateID() + metadata := config.GetMetadata() + if metadata == nil { + return nil, errors.New("sandbox config must include metadata") + } + name := makeSandboxName(metadata) + log.G(ctx).Debugf("Generated id %q for sandbox %q", id, name) + // Reserve the sandbox name to avoid concurrent `RunPodSandbox` request starting the + // same sandbox. + if err := c.sandboxNameIndex.Reserve(name, id); err != nil { + return nil, errors.Wrapf(err, "failed to reserve sandbox name %q", name) + } + defer func() { + // Release the name if the function returns with an error. + if retErr != nil { + c.sandboxNameIndex.ReleaseByName(name) + } + }() + + // Create initial internal sandbox object. + sandbox := sandboxstore.NewSandbox( + sandboxstore.Metadata{ + ID: id, + Name: name, + Config: config, + RuntimeHandler: r.GetRuntimeHandler(), + }, + sandboxstore.Status{ + State: sandboxstore.StateUnknown, + }, + ) + + // Ensure sandbox container image snapshot. + image, err := c.ensureImageExists(ctx, c.config.SandboxImage, config) + if err != nil { + return nil, errors.Wrapf(err, "failed to get sandbox image %q", c.config.SandboxImage) + } + containerdImage, err := c.toContainerdImage(ctx, *image) + if err != nil { + return nil, errors.Wrapf(err, "failed to get image from containerd %q", image.ID) + } + + ociRuntime, err := c.getSandboxRuntime(config, r.GetRuntimeHandler()) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox runtime") + } + log.G(ctx).Debugf("Use OCI %+v for sandbox %q", ociRuntime, id) + + podNetwork := true + // Pod network is always needed on windows. + if goruntime.GOOS != "windows" && + config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE { + // Pod network is not needed on linux with host network. + podNetwork = false + } + if podNetwork { + // If it is not in host network namespace then create a namespace and set the sandbox + // handle. NetNSPath in sandbox metadata and NetNS is non empty only for non host network + // namespaces. If the pod is in host network namespace then both are empty and should not + // be used. + var netnsMountDir string = "/var/run/netns" + if c.config.NetNSMountsUnderStateDir { + netnsMountDir = filepath.Join(c.config.StateDir, "netns") + } + sandbox.NetNS, err = netns.NewNetNS(netnsMountDir) + if err != nil { + return nil, errors.Wrapf(err, "failed to create network namespace for sandbox %q", id) + } + sandbox.NetNSPath = sandbox.NetNS.GetPath() + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + // Teardown network if an error is returned. + if err := c.teardownPodNetwork(deferCtx, sandbox); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to destroy network for sandbox %q", id) + } + + if err := sandbox.NetNS.Remove(); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to remove network namespace %s for sandbox %q", sandbox.NetNSPath, id) + } + sandbox.NetNSPath = "" + } + }() + + // Setup network for sandbox. + // Certain VM based solutions like clear containers (Issue containerd/cri-containerd#524) + // rely on the assumption that CRI shim will not be querying the network namespace to check the + // network states such as IP. + // In future runtime implementation should avoid relying on CRI shim implementation details. + // In this case however caching the IP will add a subtle performance enhancement by avoiding + // calls to network namespace of the pod to query the IP of the veth interface on every + // SandboxStatus request. + if err := c.setupPodNetwork(ctx, &sandbox); err != nil { + return nil, errors.Wrapf(err, "failed to setup network for sandbox %q", id) + } + } + + // Create sandbox container. + // NOTE: sandboxContainerSpec SHOULD NOT have side + // effect, e.g. accessing/creating files, so that we can test + // it safely. + spec, err := c.sandboxContainerSpec(id, config, &image.ImageSpec.Config, sandbox.NetNSPath, ociRuntime.PodAnnotations) + if err != nil { + return nil, errors.Wrap(err, "failed to generate sandbox container spec") + } + log.G(ctx).Debugf("Sandbox container %q spec: %#+v", id, spew.NewFormatter(spec)) + sandbox.ProcessLabel = spec.Process.SelinuxLabel + defer func() { + if retErr != nil { + selinux.ReleaseLabel(sandbox.ProcessLabel) + } + }() + + // handle any KVM based runtime + if err := modifyProcessLabel(ociRuntime.Type, spec); err != nil { + return nil, err + } + + if config.GetLinux().GetSecurityContext().GetPrivileged() { + // If privileged don't set selinux label, but we still record the MCS label so that + // the unused label can be freed later. + spec.Process.SelinuxLabel = "" + } + + // Generate spec options that will be applied to the spec later. + specOpts, err := c.sandboxContainerSpecOpts(config, &image.ImageSpec.Config) + if err != nil { + return nil, errors.Wrap(err, "failed to generate sanbdox container spec options") + } + + sandboxLabels := buildLabels(config.Labels, image.ImageSpec.Config.Labels, containerKindSandbox) + + runtimeOpts, err := generateRuntimeOptions(ociRuntime, c.config) + if err != nil { + return nil, errors.Wrap(err, "failed to generate runtime options") + } + + snapshotterOpt := snapshots.WithLabels(snapshots.FilterInheritedLabels(config.Annotations)) + opts := []containerd.NewContainerOpts{ + containerd.WithSnapshotter(c.config.ContainerdConfig.Snapshotter), + customopts.WithNewSnapshot(id, containerdImage, snapshotterOpt), + containerd.WithSpec(spec, specOpts...), + containerd.WithContainerLabels(sandboxLabels), + containerd.WithContainerExtension(sandboxMetadataExtension, &sandbox.Metadata), + containerd.WithRuntime(ociRuntime.Type, runtimeOpts)} + + container, err := c.client.NewContainer(ctx, id, opts...) + if err != nil { + return nil, errors.Wrap(err, "failed to create containerd container") + } + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + if err := container.Delete(deferCtx, containerd.WithSnapshotCleanup); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to delete containerd container %q", id) + } + } + }() + + // Create sandbox container root directories. + sandboxRootDir := c.getSandboxRootDir(id) + if err := c.os.MkdirAll(sandboxRootDir, 0755); err != nil { + return nil, errors.Wrapf(err, "failed to create sandbox root directory %q", + sandboxRootDir) + } + defer func() { + if retErr != nil { + // Cleanup the sandbox root directory. + if err := c.os.RemoveAll(sandboxRootDir); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to remove sandbox root directory %q", + sandboxRootDir) + } + } + }() + volatileSandboxRootDir := c.getVolatileSandboxRootDir(id) + if err := c.os.MkdirAll(volatileSandboxRootDir, 0755); err != nil { + return nil, errors.Wrapf(err, "failed to create volatile sandbox root directory %q", + volatileSandboxRootDir) + } + defer func() { + if retErr != nil { + // Cleanup the volatile sandbox root directory. + if err := c.os.RemoveAll(volatileSandboxRootDir); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to remove volatile sandbox root directory %q", + volatileSandboxRootDir) + } + } + }() + + // Setup files required for the sandbox. + if err = c.setupSandboxFiles(id, config); err != nil { + return nil, errors.Wrapf(err, "failed to setup sandbox files") + } + defer func() { + if retErr != nil { + if err = c.cleanupSandboxFiles(id, config); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to cleanup sandbox files in %q", + sandboxRootDir) + } + } + }() + + // Update sandbox created timestamp. + info, err := container.Info(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox container info") + } + + // Create sandbox task in containerd. + log.G(ctx).Tracef("Create sandbox container (id=%q, name=%q).", + id, name) + + taskOpts := c.taskOpts(ociRuntime.Type) + // We don't need stdio for sandbox container. + task, err := container.NewTask(ctx, containerdio.NullIO, taskOpts...) + if err != nil { + return nil, errors.Wrap(err, "failed to create containerd task") + } + defer func() { + if retErr != nil { + deferCtx, deferCancel := ctrdutil.DeferContext() + defer deferCancel() + // Cleanup the sandbox container if an error is returned. + if _, err := task.Delete(deferCtx, WithNRISandboxDelete(id), containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { + log.G(ctx).WithError(err).Errorf("Failed to delete sandbox container %q", id) + } + } + }() + + // wait is a long running background request, no timeout needed. + exitCh, err := task.Wait(ctrdutil.NamespacedContext()) + if err != nil { + return nil, errors.Wrap(err, "failed to wait for sandbox container task") + } + + nric, err := nri.New() + if err != nil { + return nil, errors.Wrap(err, "unable to create nri client") + } + if nric != nil { + nriSB := &nri.Sandbox{ + ID: id, + Labels: config.Labels, + } + if _, err := nric.InvokeWithSandbox(ctx, task, v1.Create, nriSB); err != nil { + return nil, errors.Wrap(err, "nri invoke") + } + } + + if err := task.Start(ctx); err != nil { + return nil, errors.Wrapf(err, "failed to start sandbox container task %q", id) + } + + if err := sandbox.Status.Update(func(status sandboxstore.Status) (sandboxstore.Status, error) { + // Set the pod sandbox as ready after successfully start sandbox container. + status.Pid = task.Pid() + status.State = sandboxstore.StateReady + status.CreatedAt = info.CreatedAt + return status, nil + }); err != nil { + return nil, errors.Wrap(err, "failed to update sandbox status") + } + + // Add sandbox into sandbox store in INIT state. + sandbox.Container = container + + if err := c.sandboxStore.Add(sandbox); err != nil { + return nil, errors.Wrapf(err, "failed to add sandbox %+v into store", sandbox) + } + + // start the monitor after adding sandbox into the store, this ensures + // that sandbox is in the store, when event monitor receives the TaskExit event. + // + // TaskOOM from containerd may come before sandbox is added to store, + // but we don't care about sandbox TaskOOM right now, so it is fine. + c.eventMonitor.startSandboxExitMonitor(context.Background(), id, task.Pid(), exitCh) + + return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil +} + +// setupPodNetwork setups up the network for a pod +func (c *criService) setupPodNetwork(ctx context.Context, sandbox *sandboxstore.Sandbox) error { + var ( + id = sandbox.ID + config = sandbox.Config + path = sandbox.NetNSPath + ) + if c.netPlugin == nil { + return errors.New("cni config not initialized") + } + + opts, err := cniNamespaceOpts(id, config) + if err != nil { + return errors.Wrap(err, "get cni namespace options") + } + + result, err := c.netPlugin.Setup(ctx, id, path, opts...) + if err != nil { + return err + } + logDebugCNIResult(ctx, id, result) + // Check if the default interface has IP config + if configs, ok := result.Interfaces[defaultIfName]; ok && len(configs.IPConfigs) > 0 { + sandbox.IP, sandbox.AdditionalIPs = selectPodIPs(configs.IPConfigs) + sandbox.CNIResult = result + return nil + } + return errors.Errorf("failed to find network info for sandbox %q", id) +} + +// cniNamespaceOpts get CNI namespace options from sandbox config. +func cniNamespaceOpts(id string, config *runtime.PodSandboxConfig) ([]cni.NamespaceOpts, error) { + opts := []cni.NamespaceOpts{ + cni.WithLabels(toCNILabels(id, config)), + cni.WithCapability(annotations.PodAnnotations, config.Annotations), + } + + portMappings := toCNIPortMappings(config.GetPortMappings()) + if len(portMappings) > 0 { + opts = append(opts, cni.WithCapabilityPortMap(portMappings)) + } + + // Will return an error if the bandwidth limitation has the wrong unit + // or an unreasonable value see validateBandwidthIsReasonable() + bandWidth, err := toCNIBandWidth(config.Annotations) + if err != nil { + return nil, err + } + if bandWidth != nil { + opts = append(opts, cni.WithCapabilityBandWidth(*bandWidth)) + } + + dns := toCNIDNS(config.GetDnsConfig()) + if dns != nil { + opts = append(opts, cni.WithCapabilityDNS(*dns)) + } + + return opts, nil +} + +// toCNILabels adds pod metadata into CNI labels. +func toCNILabels(id string, config *runtime.PodSandboxConfig) map[string]string { + return map[string]string{ + "K8S_POD_NAMESPACE": config.GetMetadata().GetNamespace(), + "K8S_POD_NAME": config.GetMetadata().GetName(), + "K8S_POD_INFRA_CONTAINER_ID": id, + "K8S_POD_UID": config.GetMetadata().GetUid(), + "IgnoreUnknown": "1", + } +} + +// toCNIBandWidth converts CRI annotations to CNI bandwidth. +func toCNIBandWidth(annotations map[string]string) (*cni.BandWidth, error) { + ingress, egress, err := bandwidth.ExtractPodBandwidthResources(annotations) + if err != nil { + return nil, errors.Wrap(err, "reading pod bandwidth annotations") + } + + if ingress == nil && egress == nil { + return nil, nil + } + + bandWidth := &cni.BandWidth{} + + if ingress != nil { + bandWidth.IngressRate = uint64(ingress.Value()) + bandWidth.IngressBurst = math.MaxUint32 + } + + if egress != nil { + bandWidth.EgressRate = uint64(egress.Value()) + bandWidth.EgressBurst = math.MaxUint32 + } + + return bandWidth, nil +} + +// toCNIPortMappings converts CRI port mappings to CNI. +func toCNIPortMappings(criPortMappings []*runtime.PortMapping) []cni.PortMapping { + var portMappings []cni.PortMapping + for _, mapping := range criPortMappings { + if mapping.HostPort <= 0 { + continue + } + portMappings = append(portMappings, cni.PortMapping{ + HostPort: mapping.HostPort, + ContainerPort: mapping.ContainerPort, + Protocol: strings.ToLower(mapping.Protocol.String()), + HostIP: mapping.HostIp, + }) + } + return portMappings +} + +// toCNIDNS converts CRI DNSConfig to CNI. +func toCNIDNS(dns *runtime.DNSConfig) *cni.DNS { + if dns == nil { + return nil + } + return &cni.DNS{ + Servers: dns.GetServers(), + Searches: dns.GetSearches(), + Options: dns.GetOptions(), + } +} + +// selectPodIPs select an ip from the ip list. It prefers ipv4 more than ipv6 +// and returns the additional ips +// TODO(random-liu): Revisit the ip order in the ipv6 beta stage. (cri#1278) +func selectPodIPs(ipConfigs []*cni.IPConfig) (string, []string) { + var ( + additionalIPs []string + ip string + ) + for _, c := range ipConfigs { + if c.IP.To4() != nil && ip == "" { + ip = c.IP.String() + } else { + additionalIPs = append(additionalIPs, c.IP.String()) + } + } + if ip != "" { + return ip, additionalIPs + } + if len(ipConfigs) == 1 { + return additionalIPs[0], nil + } + return additionalIPs[0], additionalIPs[1:] +} + +// untrustedWorkload returns true if the sandbox contains untrusted workload. +func untrustedWorkload(config *runtime.PodSandboxConfig) bool { + return config.GetAnnotations()[annotations.UntrustedWorkload] == "true" +} + +// hostAccessingSandbox returns true if the sandbox configuration +// requires additional host access for the sandbox. +func hostAccessingSandbox(config *runtime.PodSandboxConfig) bool { + securityContext := config.GetLinux().GetSecurityContext() + + namespaceOptions := securityContext.GetNamespaceOptions() + if namespaceOptions.GetNetwork() == runtime.NamespaceMode_NODE || + namespaceOptions.GetPid() == runtime.NamespaceMode_NODE || + namespaceOptions.GetIpc() == runtime.NamespaceMode_NODE { + return true + } + + return false +} + +// getSandboxRuntime returns the runtime configuration for sandbox. +// If the sandbox contains untrusted workload, runtime for untrusted workload will be returned, +// or else default runtime will be returned. +func (c *criService) getSandboxRuntime(config *runtime.PodSandboxConfig, runtimeHandler string) (criconfig.Runtime, error) { + if untrustedWorkload(config) { + // If the untrusted annotation is provided, runtimeHandler MUST be empty. + if runtimeHandler != "" && runtimeHandler != criconfig.RuntimeUntrusted { + return criconfig.Runtime{}, errors.New("untrusted workload with explicit runtime handler is not allowed") + } + + // If the untrusted workload is requesting access to the host/node, this request will fail. + // + // Note: If the workload is marked untrusted but requests privileged, this can be granted, as the + // runtime may support this. For example, in a virtual-machine isolated runtime, privileged + // is a supported option, granting the workload to access the entire guest VM instead of host. + // TODO(windows): Deprecate this so that we don't need to handle it for windows. + if hostAccessingSandbox(config) { + return criconfig.Runtime{}, errors.New("untrusted workload with host access is not allowed") + } + + runtimeHandler = criconfig.RuntimeUntrusted + } + + if runtimeHandler == "" { + runtimeHandler = c.config.ContainerdConfig.DefaultRuntimeName + } + + handler, ok := c.config.ContainerdConfig.Runtimes[runtimeHandler] + if !ok { + return criconfig.Runtime{}, errors.Errorf("no runtime for %q is configured", runtimeHandler) + } + return handler, nil +} + +func logDebugCNIResult(ctx context.Context, sandboxID string, result *cni.Result) { + if logrus.GetLevel() < logrus.DebugLevel { + return + } + cniResult, err := json.Marshal(result) + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to marshal CNI result for sandbox %q: %v", sandboxID, err) + return + } + log.G(ctx).Debugf("cni result for sandbox %q: %s", sandboxID, string(cniResult)) +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_linux.go containerd-1.5.9/pkg/cri/server/sandbox_run_linux.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,322 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "fmt" + "os" + "strings" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/plugin" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + selinux "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "golang.org/x/sys/unix" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + customopts "github.com/containerd/containerd/pkg/cri/opts" + osinterface "github.com/containerd/containerd/pkg/os" +) + +func (c *criService) sandboxContainerSpec(id string, config *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, nsPath string, runtimePodAnnotations []string) (_ *runtimespec.Spec, retErr error) { + // Creates a spec Generator with the default spec. + // TODO(random-liu): [P1] Compare the default settings with docker and containerd default. + specOpts := []oci.SpecOpts{ + oci.WithoutRunMount, + customopts.WithoutDefaultSecuritySettings, + customopts.WithRelativeRoot(relativeRootfsPath), + oci.WithEnv(imageConfig.Env), + oci.WithRootFSReadonly(), + oci.WithHostname(config.GetHostname()), + } + if imageConfig.WorkingDir != "" { + specOpts = append(specOpts, oci.WithProcessCwd(imageConfig.WorkingDir)) + } + + if len(imageConfig.Entrypoint) == 0 && len(imageConfig.Cmd) == 0 { + // Pause image must have entrypoint or cmd. + return nil, errors.Errorf("invalid empty entrypoint and cmd in image config %+v", imageConfig) + } + specOpts = append(specOpts, oci.WithProcessArgs(append(imageConfig.Entrypoint, imageConfig.Cmd...)...)) + + // Set cgroups parent. + if c.config.DisableCgroup { + specOpts = append(specOpts, customopts.WithDisabledCgroups) + } else { + if config.GetLinux().GetCgroupParent() != "" { + cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id) + specOpts = append(specOpts, oci.WithCgroup(cgroupsPath)) + } + } + + // When cgroup parent is not set, containerd-shim will create container in a child cgroup + // of the cgroup itself is in. + // TODO(random-liu): [P2] Set default cgroup path if cgroup parent is not specified. + + // Set namespace options. + var ( + securityContext = config.GetLinux().GetSecurityContext() + nsOptions = securityContext.GetNamespaceOptions() + ) + if nsOptions.GetNetwork() == runtime.NamespaceMode_NODE { + specOpts = append(specOpts, customopts.WithoutNamespace(runtimespec.NetworkNamespace)) + specOpts = append(specOpts, customopts.WithoutNamespace(runtimespec.UTSNamespace)) + } else { + specOpts = append(specOpts, oci.WithLinuxNamespace( + runtimespec.LinuxNamespace{ + Type: runtimespec.NetworkNamespace, + Path: nsPath, + })) + } + if nsOptions.GetPid() == runtime.NamespaceMode_NODE { + specOpts = append(specOpts, customopts.WithoutNamespace(runtimespec.PIDNamespace)) + } + if nsOptions.GetIpc() == runtime.NamespaceMode_NODE { + specOpts = append(specOpts, customopts.WithoutNamespace(runtimespec.IPCNamespace)) + } + + // It's fine to generate the spec before the sandbox /dev/shm + // is actually created. + sandboxDevShm := c.getSandboxDevShm(id) + if nsOptions.GetIpc() == runtime.NamespaceMode_NODE { + sandboxDevShm = devShm + } + specOpts = append(specOpts, oci.WithMounts([]runtimespec.Mount{ + { + Source: sandboxDevShm, + Destination: devShm, + Type: "bind", + Options: []string{"rbind", "ro"}, + }, + // Add resolv.conf for katacontainers to setup the DNS of pod VM properly. + { + Source: c.getResolvPath(id), + Destination: resolvConfPath, + Type: "bind", + Options: []string{"rbind", "ro"}, + }, + })) + + processLabel, mountLabel, err := initLabelsFromOpt(securityContext.GetSelinuxOptions()) + if err != nil { + return nil, errors.Wrapf(err, "failed to init selinux options %+v", securityContext.GetSelinuxOptions()) + } + defer func() { + if retErr != nil { + selinux.ReleaseLabel(processLabel) + } + }() + + supplementalGroups := securityContext.GetSupplementalGroups() + specOpts = append(specOpts, + customopts.WithSelinuxLabels(processLabel, mountLabel), + customopts.WithSupplementalGroups(supplementalGroups), + ) + + // Add sysctls + sysctls := config.GetLinux().GetSysctls() + specOpts = append(specOpts, customopts.WithSysctls(sysctls)) + + // Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile + + if !c.config.DisableCgroup { + specOpts = append(specOpts, customopts.WithDefaultSandboxShares) + } + specOpts = append(specOpts, customopts.WithPodOOMScoreAdj(int(defaultSandboxOOMAdj), c.config.RestrictOOMScoreAdj)) + + for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + runtimePodAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + specOpts = append(specOpts, + customopts.WithAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox), + customopts.WithAnnotation(annotations.SandboxID, id), + customopts.WithAnnotation(annotations.SandboxNamespace, config.GetMetadata().GetNamespace()), + customopts.WithAnnotation(annotations.SandboxName, config.GetMetadata().GetName()), + customopts.WithAnnotation(annotations.SandboxLogDir, config.GetLogDirectory()), + ) + + return c.runtimeSpec(id, "", specOpts...) +} + +// sandboxContainerSpecOpts generates OCI spec options for +// the sandbox container. +func (c *criService) sandboxContainerSpecOpts(config *runtime.PodSandboxConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + var ( + securityContext = config.GetLinux().GetSecurityContext() + specOpts []oci.SpecOpts + err error + ) + ssp := securityContext.GetSeccomp() + if ssp == nil { + ssp, err = generateSeccompSecurityProfile( + securityContext.GetSeccompProfilePath(), //nolint:staticcheck // Deprecated but we don't want to remove yet + c.config.UnsetSeccompProfile) + if err != nil { + return nil, errors.Wrap(err, "failed to generate seccomp spec opts") + } + } + seccompSpecOpts, err := c.generateSeccompSpecOpts( + ssp, + securityContext.GetPrivileged(), + c.seccompEnabled()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate seccomp spec opts") + } + if seccompSpecOpts != nil { + specOpts = append(specOpts, seccompSpecOpts) + } + + userstr, err := generateUserString( + "", + securityContext.GetRunAsUser(), + securityContext.GetRunAsGroup(), + ) + if err != nil { + return nil, errors.Wrap(err, "failed to generate user string") + } + if userstr == "" { + // Lastly, since no user override was passed via CRI try to set via OCI + // Image + userstr = imageConfig.User + } + if userstr != "" { + specOpts = append(specOpts, oci.WithUser(userstr)) + } + return specOpts, nil +} + +// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts, +// /etc/resolv.conf and /etc/hostname. +func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + sandboxEtcHostname := c.getSandboxHostname(id) + hostname := config.GetHostname() + if hostname == "" { + var err error + hostname, err = c.os.Hostname() + if err != nil { + return errors.Wrap(err, "failed to get hostname") + } + } + if err := c.os.WriteFile(sandboxEtcHostname, []byte(hostname+"\n"), 0644); err != nil { + return errors.Wrapf(err, "failed to write hostname to %q", sandboxEtcHostname) + } + + // TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet. + sandboxEtcHosts := c.getSandboxHosts(id) + if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil { + return errors.Wrapf(err, "failed to generate sandbox hosts file %q", sandboxEtcHosts) + } + + // Set DNS options. Maintain a resolv.conf for the sandbox. + var err error + resolvContent := "" + if dnsConfig := config.GetDnsConfig(); dnsConfig != nil { + resolvContent, err = parseDNSOptions(dnsConfig.Servers, dnsConfig.Searches, dnsConfig.Options) + if err != nil { + return errors.Wrapf(err, "failed to parse sandbox DNSConfig %+v", dnsConfig) + } + } + resolvPath := c.getResolvPath(id) + if resolvContent == "" { + // copy host's resolv.conf to resolvPath + err = c.os.CopyFile(resolvConfPath, resolvPath, 0644) + if err != nil { + return errors.Wrapf(err, "failed to copy host's resolv.conf to %q", resolvPath) + } + } else { + err = c.os.WriteFile(resolvPath, []byte(resolvContent), 0644) + if err != nil { + return errors.Wrapf(err, "failed to write resolv content to %q", resolvPath) + } + } + + // Setup sandbox /dev/shm. + if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE { + if _, err := c.os.Stat(devShm); err != nil { + return errors.Wrapf(err, "host %q is not available for host ipc", devShm) + } + } else { + sandboxDevShm := c.getSandboxDevShm(id) + if err := c.os.MkdirAll(sandboxDevShm, 0700); err != nil { + return errors.Wrap(err, "failed to create sandbox shm") + } + shmproperty := fmt.Sprintf("mode=1777,size=%d", defaultShmSize) + if err := c.os.(osinterface.UNIX).Mount("shm", sandboxDevShm, "tmpfs", uintptr(unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV), shmproperty); err != nil { + return errors.Wrap(err, "failed to mount sandbox shm") + } + } + + return nil +} + +// parseDNSOptions parse DNS options into resolv.conf format content, +// if none option is specified, will return empty with no error. +func parseDNSOptions(servers, searches, options []string) (string, error) { + resolvContent := "" + + if len(searches) > 0 { + resolvContent += fmt.Sprintf("search %s\n", strings.Join(searches, " ")) + } + + if len(servers) > 0 { + resolvContent += fmt.Sprintf("nameserver %s\n", strings.Join(servers, "\nnameserver ")) + } + + if len(options) > 0 { + resolvContent += fmt.Sprintf("options %s\n", strings.Join(options, " ")) + } + + return resolvContent, nil +} + +// cleanupSandboxFiles unmount some sandbox files, we rely on the removal of sandbox root directory to +// remove these files. Unmount should *NOT* return error if the mount point is already unmounted. +func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE { + path, err := c.os.FollowSymlinkInScope(c.getSandboxDevShm(id), "/") + if err != nil { + return errors.Wrap(err, "failed to follow symlink") + } + if err := c.os.(osinterface.UNIX).Unmount(path); err != nil && !os.IsNotExist(err) { + return errors.Wrapf(err, "failed to unmount %q", path) + } + } + return nil +} + +// taskOpts generates task options for a (sandbox) container. +func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { + // TODO(random-liu): Remove this after shim v1 is deprecated. + var taskOpts []containerd.NewTaskOpts + + // c.config.NoPivot is only supported for RuntimeLinuxV1 = "io.containerd.runtime.v1.linux" legacy linux runtime + // and is not supported for RuntimeRuncV1 = "io.containerd.runc.v1" or RuntimeRuncV2 = "io.containerd.runc.v2" + // for RuncV1/2 no pivot is set under the containerd.runtimes.runc.options config see + // https://github.com/containerd/containerd/blob/v1.3.2/runtime/v2/runc/options/oci.pb.go#L26 + if c.config.NoPivot && runtimeType == plugin.RuntimeLinuxV1 { + taskOpts = append(taskOpts, containerd.WithNoPivotRoot) + } + + return taskOpts +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_linux_test.go containerd-1.5.9/pkg/cri/server/sandbox_run_linux_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,443 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "os" + "path/filepath" + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/opts" + ostesting "github.com/containerd/containerd/pkg/os/testing" +) + +func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) { + config := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-name", + Uid: "test-uid", + Namespace: "test-ns", + Attempt: 1, + }, + Hostname: "test-hostname", + LogDirectory: "test-log-directory", + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + Linux: &runtime.LinuxPodSandboxConfig{ + CgroupParent: "/test/cgroup/parent", + }, + } + imageConfig := &imagespec.ImageConfig{ + Env: []string{"a=b", "c=d"}, + Entrypoint: []string{"/pause"}, + Cmd: []string{"forever"}, + WorkingDir: "/workspace", + } + specCheck := func(t *testing.T, id string, spec *runtimespec.Spec) { + assert.Equal(t, "test-hostname", spec.Hostname) + assert.Equal(t, getCgroupsPath("/test/cgroup/parent", id), spec.Linux.CgroupsPath) + assert.Equal(t, relativeRootfsPath, spec.Root.Path) + assert.Equal(t, true, spec.Root.Readonly) + assert.Contains(t, spec.Process.Env, "a=b", "c=d") + assert.Equal(t, []string{"/pause", "forever"}, spec.Process.Args) + assert.Equal(t, "/workspace", spec.Process.Cwd) + assert.EqualValues(t, *spec.Linux.Resources.CPU.Shares, opts.DefaultSandboxCPUshares) + assert.EqualValues(t, *spec.Process.OOMScoreAdj, defaultSandboxOOMAdj) + + t.Logf("Check PodSandbox annotations") + assert.Contains(t, spec.Annotations, annotations.SandboxID) + assert.EqualValues(t, spec.Annotations[annotations.SandboxID], id) + + assert.Contains(t, spec.Annotations, annotations.ContainerType) + assert.EqualValues(t, spec.Annotations[annotations.ContainerType], annotations.ContainerTypeSandbox) + + assert.Contains(t, spec.Annotations, annotations.SandboxNamespace) + assert.EqualValues(t, spec.Annotations[annotations.SandboxNamespace], "test-ns") + + assert.Contains(t, spec.Annotations, annotations.SandboxName) + assert.EqualValues(t, spec.Annotations[annotations.SandboxName], "test-name") + + assert.Contains(t, spec.Annotations, annotations.SandboxLogDir) + assert.EqualValues(t, spec.Annotations[annotations.SandboxLogDir], "test-log-directory") + + if selinux.GetEnabled() { + assert.NotEqual(t, "", spec.Process.SelinuxLabel) + assert.NotEqual(t, "", spec.Linux.MountLabel) + } + } + return config, imageConfig, specCheck +} + +func TestLinuxSandboxContainerSpec(t *testing.T) { + testID := "test-id" + nsPath := "test-cni" + for desc, test := range map[string]struct { + configChange func(*runtime.PodSandboxConfig) + specCheck func(*testing.T, *runtimespec.Spec) + expectErr bool + }{ + "spec should reflect original config": { + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + // runtime spec should have expected namespaces enabled by default. + require.NotNil(t, spec.Linux) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.NetworkNamespace, + Path: nsPath, + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.UTSNamespace, + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + }) + assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.IPCNamespace, + }) + }, + }, + "host namespace": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_NODE, + Ipc: runtime.NamespaceMode_NODE, + }, + } + }, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + // runtime spec should disable expected namespaces in host mode. + require.NotNil(t, spec.Linux) + assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.NetworkNamespace, + }) + assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.UTSNamespace, + }) + assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.PIDNamespace, + }) + assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{ + Type: runtimespec.IPCNamespace, + }) + }, + }, + "should set supplemental groups correctly": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + SupplementalGroups: []int64{1111, 2222}, + } + }, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + require.NotNil(t, spec.Process) + assert.Contains(t, spec.Process.User.AdditionalGids, uint32(1111)) + assert.Contains(t, spec.Process.User.AdditionalGids, uint32(2222)) + }, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + config, imageConfig, specCheck := getRunPodSandboxTestData() + if test.configChange != nil { + test.configChange(config) + } + spec, err := c.sandboxContainerSpec(testID, config, imageConfig, nsPath, nil) + if test.expectErr { + assert.Error(t, err) + assert.Nil(t, spec) + continue + } + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, spec) + if test.specCheck != nil { + test.specCheck(t, spec) + } + } +} + +func TestSetupSandboxFiles(t *testing.T) { + const ( + testID = "test-id" + realhostname = "test-real-hostname" + ) + for desc, test := range map[string]struct { + dnsConfig *runtime.DNSConfig + hostname string + ipcMode runtime.NamespaceMode + expectedCalls []ostesting.CalledDetail + }{ + "should check host /dev/shm existence when ipc mode is NODE": { + ipcMode: runtime.NamespaceMode_NODE, + expectedCalls: []ostesting.CalledDetail{ + { + Name: "Hostname", + }, + { + Name: "WriteFile", + Arguments: []interface{}{ + filepath.Join(testRootDir, sandboxesDir, testID, "hostname"), + []byte(realhostname + "\n"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/hosts", + filepath.Join(testRootDir, sandboxesDir, testID, "hosts"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/resolv.conf", + filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"), + os.FileMode(0644), + }, + }, + { + Name: "Stat", + Arguments: []interface{}{"/dev/shm"}, + }, + }, + }, + "should create new /etc/resolv.conf if DNSOptions is set": { + dnsConfig: &runtime.DNSConfig{ + Servers: []string{"8.8.8.8"}, + Searches: []string{"114.114.114.114"}, + Options: []string{"timeout:1"}, + }, + ipcMode: runtime.NamespaceMode_NODE, + expectedCalls: []ostesting.CalledDetail{ + { + Name: "Hostname", + }, + { + Name: "WriteFile", + Arguments: []interface{}{ + filepath.Join(testRootDir, sandboxesDir, testID, "hostname"), + []byte(realhostname + "\n"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/hosts", + filepath.Join(testRootDir, sandboxesDir, testID, "hosts"), + os.FileMode(0644), + }, + }, + { + Name: "WriteFile", + Arguments: []interface{}{ + filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"), + []byte(`search 114.114.114.114 +nameserver 8.8.8.8 +options timeout:1 +`), os.FileMode(0644), + }, + }, + { + Name: "Stat", + Arguments: []interface{}{"/dev/shm"}, + }, + }, + }, + "should create sandbox shm when ipc namespace mode is not NODE": { + ipcMode: runtime.NamespaceMode_POD, + expectedCalls: []ostesting.CalledDetail{ + { + Name: "Hostname", + }, + { + Name: "WriteFile", + Arguments: []interface{}{ + filepath.Join(testRootDir, sandboxesDir, testID, "hostname"), + []byte(realhostname + "\n"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/hosts", + filepath.Join(testRootDir, sandboxesDir, testID, "hosts"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/resolv.conf", + filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"), + os.FileMode(0644), + }, + }, + { + Name: "MkdirAll", + Arguments: []interface{}{ + filepath.Join(testStateDir, sandboxesDir, testID, "shm"), + os.FileMode(0700), + }, + }, + { + Name: "Mount", + // Ignore arguments which are too complex to check. + }, + }, + }, + "should create /etc/hostname when hostname is set": { + hostname: "test-hostname", + ipcMode: runtime.NamespaceMode_NODE, + expectedCalls: []ostesting.CalledDetail{ + { + Name: "WriteFile", + Arguments: []interface{}{ + filepath.Join(testRootDir, sandboxesDir, testID, "hostname"), + []byte("test-hostname\n"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/hosts", + filepath.Join(testRootDir, sandboxesDir, testID, "hosts"), + os.FileMode(0644), + }, + }, + { + Name: "CopyFile", + Arguments: []interface{}{ + "/etc/resolv.conf", + filepath.Join(testRootDir, sandboxesDir, testID, "resolv.conf"), + os.FileMode(0644), + }, + }, + { + Name: "Stat", + Arguments: []interface{}{"/dev/shm"}, + }, + }, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + c.os.(*ostesting.FakeOS).HostnameFn = func() (string, error) { + return realhostname, nil + } + cfg := &runtime.PodSandboxConfig{ + Hostname: test.hostname, + DnsConfig: test.dnsConfig, + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{ + Ipc: test.ipcMode, + }, + }, + }, + } + c.setupSandboxFiles(testID, cfg) + calls := c.os.(*ostesting.FakeOS).GetCalls() + assert.Len(t, calls, len(test.expectedCalls)) + for i, expected := range test.expectedCalls { + if expected.Arguments == nil { + // Ignore arguments. + expected.Arguments = calls[i].Arguments + } + assert.Equal(t, expected, calls[i]) + } + } +} + +func TestParseDNSOption(t *testing.T) { + for desc, test := range map[string]struct { + servers []string + searches []string + options []string + expectedContent string + expectErr bool + }{ + "empty dns options should return empty content": {}, + "non-empty dns options should return correct content": { + servers: []string{"8.8.8.8", "server.google.com"}, + searches: []string{"114.114.114.114"}, + options: []string{"timeout:1"}, + expectedContent: `search 114.114.114.114 +nameserver 8.8.8.8 +nameserver server.google.com +options timeout:1 +`, + }, + "expanded dns config should return correct content on modern libc (e.g. glibc 2.26 and above)": { + servers: []string{"8.8.8.8", "server.google.com"}, + searches: []string{ + "server0.google.com", + "server1.google.com", + "server2.google.com", + "server3.google.com", + "server4.google.com", + "server5.google.com", + "server6.google.com", + }, + options: []string{"timeout:1"}, + expectedContent: `search server0.google.com server1.google.com server2.google.com server3.google.com server4.google.com server5.google.com server6.google.com +nameserver 8.8.8.8 +nameserver server.google.com +options timeout:1 +`, + }, + } { + t.Logf("TestCase %q", desc) + resolvContent, err := parseDNSOptions(test.servers, test.searches, test.options) + if test.expectErr { + assert.Error(t, err) + continue + } + assert.NoError(t, err) + assert.Equal(t, resolvContent, test.expectedContent) + } +} + +func TestSandboxDisableCgroup(t *testing.T) { + config, imageConfig, _ := getRunPodSandboxTestData() + c := newTestCRIService() + c.config.DisableCgroup = true + spec, err := c.sandboxContainerSpec("test-id", config, imageConfig, "test-cni", []string{}) + require.NoError(t, err) + + t.Log("resource limit should not be set") + assert.Nil(t, spec.Linux.Resources.Memory) + assert.Nil(t, spec.Linux.Resources.CPU) + + t.Log("cgroup path should be empty") + assert.Empty(t, spec.Linux.CgroupsPath) +} + +// TODO(random-liu): [P1] Add unit test for different error cases to make sure +// the function cleans up on error properly. diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_other.go containerd-1.5.9/pkg/cri/server/sandbox_run_other.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func (c *criService) sandboxContainerSpec(id string, config *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, nsPath string, runtimePodAnnotations []string) (_ *runtimespec.Spec, retErr error) { + return c.runtimeSpec(id, "") +} + +// sandboxContainerSpecOpts generates OCI spec options for +// the sandbox container. +func (c *criService) sandboxContainerSpecOpts(config *runtime.PodSandboxConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + return []oci.SpecOpts{}, nil +} + +// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts, +// /etc/resolv.conf and /etc/hostname. +func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + return nil +} + +// cleanupSandboxFiles unmount some sandbox files, we rely on the removal of sandbox root directory to +// remove these files. Unmount should *NOT* return error if the mount point is already unmounted. +func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + return nil +} + +// taskOpts generates task options for a (sandbox) container. +func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { + return []containerd.NewTaskOpts{} +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_other_test.go containerd-1.5.9/pkg/cri/server/sandbox_run_other_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_other_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_other_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) { + config := &runtime.PodSandboxConfig{} + imageConfig := &imagespec.ImageConfig{} + specCheck := func(t *testing.T, id string, spec *runtimespec.Spec) { + } + return config, imageConfig, specCheck +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_test.go containerd-1.5.9/pkg/cri/server/sandbox_run_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,505 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "net" + goruntime "runtime" + "testing" + + cni "github.com/containerd/go-cni" + "github.com/containerd/typeurl" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + criconfig "github.com/containerd/containerd/pkg/cri/config" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +func TestSandboxContainerSpec(t *testing.T) { + if goruntime.GOOS == "darwin" { + t.Skip("not implemented on Darwin") + } + + testID := "test-id" + nsPath := "test-cni" + for desc, test := range map[string]struct { + configChange func(*runtime.PodSandboxConfig) + podAnnotations []string + imageConfigChange func(*imagespec.ImageConfig) + specCheck func(*testing.T, *runtimespec.Spec) + expectErr bool + }{ + "should return error when entrypoint and cmd are empty": { + imageConfigChange: func(c *imagespec.ImageConfig) { + c.Entrypoint = nil + c.Cmd = nil + }, + expectErr: true, + }, + "a passthrough annotation should be passed as an OCI annotation": { + podAnnotations: []string{"c"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, spec.Annotations["c"], "d") + }, + }, + "a non-passthrough annotation should not be passed as an OCI annotation": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Annotations["d"] = "e" + }, + podAnnotations: []string{"c"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, spec.Annotations["c"], "d") + _, ok := spec.Annotations["d"] + assert.False(t, ok) + }, + }, + "passthrough annotations should support wildcard match": { + configChange: func(c *runtime.PodSandboxConfig) { + c.Annotations["t.f"] = "j" + c.Annotations["z.g"] = "o" + c.Annotations["z"] = "o" + c.Annotations["y.ca"] = "b" + c.Annotations["y"] = "b" + }, + podAnnotations: []string{"t*", "z.*", "y.c*"}, + specCheck: func(t *testing.T, spec *runtimespec.Spec) { + assert.Equal(t, spec.Annotations["t.f"], "j") + assert.Equal(t, spec.Annotations["z.g"], "o") + assert.Equal(t, spec.Annotations["y.ca"], "b") + _, ok := spec.Annotations["y"] + assert.False(t, ok) + _, ok = spec.Annotations["z"] + assert.False(t, ok) + }, + }, + } { + t.Logf("TestCase %q", desc) + c := newTestCRIService() + config, imageConfig, specCheck := getRunPodSandboxTestData() + if test.configChange != nil { + test.configChange(config) + } + + if test.imageConfigChange != nil { + test.imageConfigChange(imageConfig) + } + spec, err := c.sandboxContainerSpec(testID, config, imageConfig, nsPath, + test.podAnnotations) + if test.expectErr { + assert.Error(t, err) + assert.Nil(t, spec) + continue + } + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, spec) + if test.specCheck != nil { + test.specCheck(t, spec) + } + } +} + +func TestTypeurlMarshalUnmarshalSandboxMeta(t *testing.T) { + for desc, test := range map[string]struct { + configChange func(*runtime.PodSandboxConfig) + }{ + "should marshal original config": {}, + "should marshal Linux": { + configChange: func(c *runtime.PodSandboxConfig) { + if c.Linux == nil { + c.Linux = &runtime.LinuxPodSandboxConfig{} + } + c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_NODE, + Ipc: runtime.NamespaceMode_NODE, + }, + SupplementalGroups: []int64{1111, 2222}, + } + }, + }, + } { + t.Logf("TestCase %q", desc) + meta := &sandboxstore.Metadata{ + ID: "1", + Name: "sandbox_1", + NetNSPath: "/home/cloud", + } + meta.Config, _, _ = getRunPodSandboxTestData() + if test.configChange != nil { + test.configChange(meta.Config) + } + + any, err := typeurl.MarshalAny(meta) + assert.NoError(t, err) + data, err := typeurl.UnmarshalAny(any) + assert.NoError(t, err) + assert.IsType(t, &sandboxstore.Metadata{}, data) + curMeta, ok := data.(*sandboxstore.Metadata) + assert.True(t, ok) + assert.Equal(t, meta, curMeta) + } +} + +func TestToCNIPortMappings(t *testing.T) { + for desc, test := range map[string]struct { + criPortMappings []*runtime.PortMapping + cniPortMappings []cni.PortMapping + }{ + "empty CRI port mapping should map to empty CNI port mapping": {}, + "CRI port mapping should be converted to CNI port mapping properly": { + criPortMappings: []*runtime.PortMapping{ + { + Protocol: runtime.Protocol_UDP, + ContainerPort: 1234, + HostPort: 5678, + HostIp: "123.124.125.126", + }, + { + Protocol: runtime.Protocol_TCP, + ContainerPort: 4321, + HostPort: 8765, + HostIp: "126.125.124.123", + }, + { + Protocol: runtime.Protocol_SCTP, + ContainerPort: 1234, + HostPort: 5678, + HostIp: "123.124.125.126", + }, + }, + cniPortMappings: []cni.PortMapping{ + { + HostPort: 5678, + ContainerPort: 1234, + Protocol: "udp", + HostIP: "123.124.125.126", + }, + { + HostPort: 8765, + ContainerPort: 4321, + Protocol: "tcp", + HostIP: "126.125.124.123", + }, + { + HostPort: 5678, + ContainerPort: 1234, + Protocol: "sctp", + HostIP: "123.124.125.126", + }, + }, + }, + "CRI port mapping without host port should be skipped": { + criPortMappings: []*runtime.PortMapping{ + { + Protocol: runtime.Protocol_UDP, + ContainerPort: 1234, + HostIp: "123.124.125.126", + }, + { + Protocol: runtime.Protocol_TCP, + ContainerPort: 4321, + HostPort: 8765, + HostIp: "126.125.124.123", + }, + }, + cniPortMappings: []cni.PortMapping{ + { + HostPort: 8765, + ContainerPort: 4321, + Protocol: "tcp", + HostIP: "126.125.124.123", + }, + }, + }, + "CRI port mapping with unsupported protocol should be skipped": { + criPortMappings: []*runtime.PortMapping{ + { + Protocol: runtime.Protocol_TCP, + ContainerPort: 4321, + HostPort: 8765, + HostIp: "126.125.124.123", + }, + }, + cniPortMappings: []cni.PortMapping{ + { + HostPort: 8765, + ContainerPort: 4321, + Protocol: "tcp", + HostIP: "126.125.124.123", + }, + }, + }, + } { + t.Logf("TestCase %q", desc) + assert.Equal(t, test.cniPortMappings, toCNIPortMappings(test.criPortMappings)) + } +} + +func TestSelectPodIP(t *testing.T) { + for desc, test := range map[string]struct { + ips []string + expectedIP string + expectedAdditionalIPs []string + }{ + "ipv4 should be picked even if ipv6 comes first": { + ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43"}, + expectedIP: "192.168.17.43", + expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334"}, + }, + "ipv4 should be picked when there is only ipv4": { + ips: []string{"192.168.17.43"}, + expectedIP: "192.168.17.43", + expectedAdditionalIPs: nil, + }, + "ipv6 should be picked when there is no ipv4": { + ips: []string{"2001:db8:85a3::8a2e:370:7334"}, + expectedIP: "2001:db8:85a3::8a2e:370:7334", + expectedAdditionalIPs: nil, + }, + "the first ipv4 should be picked when there are multiple ipv4": { // unlikely to happen + ips: []string{"2001:db8:85a3::8a2e:370:7334", "192.168.17.43", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"}, + expectedIP: "192.168.17.43", + expectedAdditionalIPs: []string{"2001:db8:85a3::8a2e:370:7334", "2001:db8:85a3::8a2e:370:7335", "192.168.17.45"}, + }, + } { + t.Logf("TestCase %q", desc) + var ipConfigs []*cni.IPConfig + for _, ip := range test.ips { + ipConfigs = append(ipConfigs, &cni.IPConfig{ + IP: net.ParseIP(ip), + }) + } + ip, additionalIPs := selectPodIPs(ipConfigs) + assert.Equal(t, test.expectedIP, ip) + assert.Equal(t, test.expectedAdditionalIPs, additionalIPs) + } +} + +func TestHostAccessingSandbox(t *testing.T) { + privilegedContext := &runtime.PodSandboxConfig{ + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + Privileged: true, + }, + }, + } + nonPrivilegedContext := &runtime.PodSandboxConfig{ + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + Privileged: false, + }, + }, + } + hostNamespace := &runtime.PodSandboxConfig{ + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + Privileged: false, + NamespaceOptions: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_NODE, + Ipc: runtime.NamespaceMode_NODE, + }, + }, + }, + } + tests := []struct { + name string + config *runtime.PodSandboxConfig + want bool + }{ + {"Security Context is nil", nil, false}, + {"Security Context is privileged", privilegedContext, false}, + {"Security Context is not privileged", nonPrivilegedContext, false}, + {"Security Context namespace host access", hostNamespace, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := hostAccessingSandbox(tt.config); got != tt.want { + t.Errorf("hostAccessingSandbox() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetSandboxRuntime(t *testing.T) { + untrustedWorkloadRuntime := criconfig.Runtime{ + Type: "io.containerd.runtime.v1.linux", + Engine: "untrusted-workload-runtime", + Root: "", + } + + defaultRuntime := criconfig.Runtime{ + Type: "io.containerd.runtime.v1.linux", + Engine: "default-runtime", + Root: "", + } + + fooRuntime := criconfig.Runtime{ + Type: "io.containerd.runtime.v1.linux", + Engine: "foo-bar", + Root: "", + } + + for desc, test := range map[string]struct { + sandboxConfig *runtime.PodSandboxConfig + runtimeHandler string + runtimes map[string]criconfig.Runtime + expectErr bool + expectedRuntime criconfig.Runtime + }{ + "should return error if untrusted workload requires host access": { + sandboxConfig: &runtime.PodSandboxConfig{ + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + Privileged: false, + NamespaceOptions: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_NODE, + Ipc: runtime.NamespaceMode_NODE, + }, + }, + }, + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + }, + expectErr: true, + }, + "should use untrusted workload runtime for untrusted workload": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + }, + expectedRuntime: untrustedWorkloadRuntime, + }, + "should use default runtime for regular workload": { + sandboxConfig: &runtime.PodSandboxConfig{}, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + }, + expectedRuntime: defaultRuntime, + }, + "should use default runtime for trusted workload": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "false", + }, + }, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + }, + expectedRuntime: defaultRuntime, + }, + "should return error if untrusted workload runtime is required but not configured": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + }, + expectErr: true, + }, + "should use 'untrusted' runtime for untrusted workload": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + }, + expectedRuntime: untrustedWorkloadRuntime, + }, + "should use 'untrusted' runtime for untrusted workload & handler": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimeHandler: "untrusted", + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + }, + expectedRuntime: untrustedWorkloadRuntime, + }, + "should return an error if untrusted annotation with conflicting handler": { + sandboxConfig: &runtime.PodSandboxConfig{ + Annotations: map[string]string{ + annotations.UntrustedWorkload: "true", + }, + }, + runtimeHandler: "foo", + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + "foo": fooRuntime, + }, + expectErr: true, + }, + "should use correct runtime for a runtime handler": { + sandboxConfig: &runtime.PodSandboxConfig{}, + runtimeHandler: "foo", + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, + "foo": fooRuntime, + }, + expectedRuntime: fooRuntime, + }, + "should return error if runtime handler is required but not configured": { + sandboxConfig: &runtime.PodSandboxConfig{}, + runtimeHandler: "bar", + runtimes: map[string]criconfig.Runtime{ + criconfig.RuntimeDefault: defaultRuntime, + "foo": fooRuntime, + }, + expectErr: true, + }, + } { + t.Run(desc, func(t *testing.T) { + cri := newTestCRIService() + cri.config = criconfig.Config{ + PluginConfig: criconfig.DefaultConfig(), + } + cri.config.ContainerdConfig.DefaultRuntimeName = criconfig.RuntimeDefault + cri.config.ContainerdConfig.Runtimes = test.runtimes + r, err := cri.getSandboxRuntime(test.sandboxConfig, test.runtimeHandler) + assert.Equal(t, test.expectErr, err != nil) + assert.Equal(t, test.expectedRuntime, r) + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_windows.go containerd-1.5.9/pkg/cri/server/sandbox_run_windows.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,93 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + customopts "github.com/containerd/containerd/pkg/cri/opts" +) + +func (c *criService) sandboxContainerSpec(id string, config *runtime.PodSandboxConfig, + imageConfig *imagespec.ImageConfig, nsPath string, runtimePodAnnotations []string) (*runtimespec.Spec, error) { + // Creates a spec Generator with the default spec. + specOpts := []oci.SpecOpts{ + oci.WithEnv(imageConfig.Env), + oci.WithHostname(config.GetHostname()), + } + if imageConfig.WorkingDir != "" { + specOpts = append(specOpts, oci.WithProcessCwd(imageConfig.WorkingDir)) + } + + if len(imageConfig.Entrypoint) == 0 && len(imageConfig.Cmd) == 0 { + // Pause image must have entrypoint or cmd. + return nil, errors.Errorf("invalid empty entrypoint and cmd in image config %+v", imageConfig) + } + specOpts = append(specOpts, oci.WithProcessArgs(append(imageConfig.Entrypoint, imageConfig.Cmd...)...)) + + specOpts = append(specOpts, + // Clear the root location since hcsshim expects it. + // NOTE: readonly rootfs doesn't work on windows. + customopts.WithoutRoot, + customopts.WithWindowsNetworkNamespace(nsPath), + ) + + specOpts = append(specOpts, customopts.WithWindowsDefaultSandboxShares) + + for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + runtimePodAnnotations) { + specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) + } + + specOpts = append(specOpts, + customopts.WithAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox), + customopts.WithAnnotation(annotations.SandboxID, id), + customopts.WithAnnotation(annotations.SandboxNamespace, config.GetMetadata().GetNamespace()), + customopts.WithAnnotation(annotations.SandboxName, config.GetMetadata().GetName()), + customopts.WithAnnotation(annotations.SandboxLogDir, config.GetLogDirectory()), + ) + + return c.runtimeSpec(id, "", specOpts...) +} + +// No sandbox container spec options for windows yet. +func (c *criService) sandboxContainerSpecOpts(config *runtime.PodSandboxConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) { + return nil, nil +} + +// No sandbox files needed for windows. +func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + return nil +} + +// No sandbox files needed for windows. +func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { + return nil +} + +// No task options needed for windows. +func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_run_windows_test.go containerd-1.5.9/pkg/cri/server/sandbox_run_windows_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_run_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_run_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,92 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/annotations" + "github.com/containerd/containerd/pkg/cri/opts" +) + +func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) { + config := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-name", + Uid: "test-uid", + Namespace: "test-ns", + Attempt: 1, + }, + Hostname: "test-hostname", + LogDirectory: "test-log-directory", + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + } + imageConfig := &imagespec.ImageConfig{ + Env: []string{"a=b", "c=d"}, + Entrypoint: []string{"/pause"}, + Cmd: []string{"forever"}, + WorkingDir: "/workspace", + } + specCheck := func(t *testing.T, id string, spec *runtimespec.Spec) { + assert.Equal(t, "test-hostname", spec.Hostname) + assert.Nil(t, spec.Root) + assert.Contains(t, spec.Process.Env, "a=b", "c=d") + assert.Equal(t, []string{"/pause", "forever"}, spec.Process.Args) + assert.Equal(t, "/workspace", spec.Process.Cwd) + assert.EqualValues(t, *spec.Windows.Resources.CPU.Shares, opts.DefaultSandboxCPUshares) + + t.Logf("Check PodSandbox annotations") + assert.Contains(t, spec.Annotations, annotations.SandboxID) + assert.EqualValues(t, spec.Annotations[annotations.SandboxID], id) + + assert.Contains(t, spec.Annotations, annotations.ContainerType) + assert.EqualValues(t, spec.Annotations[annotations.ContainerType], annotations.ContainerTypeSandbox) + + assert.Contains(t, spec.Annotations, annotations.SandboxNamespace) + assert.EqualValues(t, spec.Annotations[annotations.SandboxNamespace], "test-ns") + + assert.Contains(t, spec.Annotations, annotations.SandboxName) + assert.EqualValues(t, spec.Annotations[annotations.SandboxName], "test-name") + + assert.Contains(t, spec.Annotations, annotations.SandboxLogDir) + assert.EqualValues(t, spec.Annotations[annotations.SandboxLogDir], "test-log-directory") + } + return config, imageConfig, specCheck +} + +func TestSandboxWindowsNetworkNamespace(t *testing.T) { + testID := "test-id" + nsPath := "test-cni" + c := newTestCRIService() + + config, imageConfig, specCheck := getRunPodSandboxTestData() + spec, err := c.sandboxContainerSpec(testID, config, imageConfig, nsPath, nil) + assert.NoError(t, err) + assert.NotNil(t, spec) + specCheck(t, testID, spec) + assert.NotNil(t, spec.Windows) + assert.NotNil(t, spec.Windows.Network) + assert.Equal(t, nsPath, spec.Windows.Network.NetworkNamespace) +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_status.go containerd-1.5.9/pkg/cri/server/sandbox_status.go --- containerd-1.2.6/pkg/cri/server/sandbox_status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,217 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + goruntime "runtime" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + cni "github.com/containerd/go-cni" + runtimespec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +// PodSandboxStatus returns the status of the PodSandbox. +func (c *criService) PodSandboxStatus(ctx context.Context, r *runtime.PodSandboxStatusRequest) (*runtime.PodSandboxStatusResponse, error) { + sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) + if err != nil { + return nil, errors.Wrap(err, "an error occurred when try to find sandbox") + } + + ip, additionalIPs, err := c.getIPs(sandbox) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox ip") + } + status := toCRISandboxStatus(sandbox.Metadata, sandbox.Status.Get(), ip, additionalIPs) + if status.GetCreatedAt() == 0 { + // CRI doesn't allow CreatedAt == 0. + info, err := sandbox.Container.Info(ctx) + if err != nil { + return nil, errors.Wrapf(err, "failed to get CreatedAt for sandbox container in %q state", status.State) + } + status.CreatedAt = info.CreatedAt.UnixNano() + } + if !r.GetVerbose() { + return &runtime.PodSandboxStatusResponse{Status: status}, nil + } + + // Generate verbose information. + info, err := toCRISandboxInfo(ctx, sandbox) + if err != nil { + return nil, errors.Wrap(err, "failed to get verbose sandbox container info") + } + + return &runtime.PodSandboxStatusResponse{ + Status: status, + Info: info, + }, nil +} + +func (c *criService) getIPs(sandbox sandboxstore.Sandbox) (string, []string, error) { + config := sandbox.Config + + if goruntime.GOOS != "windows" && + config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE { + // For sandboxes using the node network we are not + // responsible for reporting the IP. + return "", nil, nil + } + + if closed, err := sandbox.NetNS.Closed(); err != nil { + return "", nil, errors.Wrap(err, "check network namespace closed") + } else if closed { + return "", nil, nil + } + + return sandbox.IP, sandbox.AdditionalIPs, nil +} + +// toCRISandboxStatus converts sandbox metadata into CRI pod sandbox status. +func toCRISandboxStatus(meta sandboxstore.Metadata, status sandboxstore.Status, ip string, additionalIPs []string) *runtime.PodSandboxStatus { + // Set sandbox state to NOTREADY by default. + state := runtime.PodSandboxState_SANDBOX_NOTREADY + if status.State == sandboxstore.StateReady { + state = runtime.PodSandboxState_SANDBOX_READY + } + nsOpts := meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions() + var ips []*runtime.PodIP + for _, additionalIP := range additionalIPs { + ips = append(ips, &runtime.PodIP{Ip: additionalIP}) + } + return &runtime.PodSandboxStatus{ + Id: meta.ID, + Metadata: meta.Config.GetMetadata(), + State: state, + CreatedAt: status.CreatedAt.UnixNano(), + Network: &runtime.PodSandboxNetworkStatus{ + Ip: ip, + AdditionalIps: ips, + }, + Linux: &runtime.LinuxPodSandboxStatus{ + Namespaces: &runtime.Namespace{ + Options: &runtime.NamespaceOption{ + Network: nsOpts.GetNetwork(), + Pid: nsOpts.GetPid(), + Ipc: nsOpts.GetIpc(), + }, + }, + }, + Labels: meta.Config.GetLabels(), + Annotations: meta.Config.GetAnnotations(), + RuntimeHandler: meta.RuntimeHandler, + } +} + +// SandboxInfo is extra information for sandbox. +// TODO (mikebrow): discuss predefining constants structures for some or all of these field names in CRI +type SandboxInfo struct { + Pid uint32 `json:"pid"` + Status string `json:"processStatus"` + NetNSClosed bool `json:"netNamespaceClosed"` + Image string `json:"image"` + SnapshotKey string `json:"snapshotKey"` + Snapshotter string `json:"snapshotter"` + // Note: a new field `RuntimeHandler` has been added into the CRI PodSandboxStatus struct, and + // should be set. This `RuntimeHandler` field will be deprecated after containerd 1.3 (tracked + // in https://github.com/containerd/cri/issues/1064). + RuntimeHandler string `json:"runtimeHandler"` // see the Note above + RuntimeType string `json:"runtimeType"` + RuntimeOptions interface{} `json:"runtimeOptions"` + Config *runtime.PodSandboxConfig `json:"config"` + RuntimeSpec *runtimespec.Spec `json:"runtimeSpec"` + CNIResult *cni.Result `json:"cniResult"` +} + +// toCRISandboxInfo converts internal container object information to CRI sandbox status response info map. +func toCRISandboxInfo(ctx context.Context, sandbox sandboxstore.Sandbox) (map[string]string, error) { + container := sandbox.Container + task, err := container.Task(ctx, nil) + if err != nil && !errdefs.IsNotFound(err) { + return nil, errors.Wrap(err, "failed to get sandbox container task") + } + + var processStatus containerd.ProcessStatus + if task != nil { + taskStatus, err := task.Status(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get task status") + } + + processStatus = taskStatus.Status + } + + si := &SandboxInfo{ + Pid: sandbox.Status.Get().Pid, + RuntimeHandler: sandbox.RuntimeHandler, + Status: string(processStatus), + Config: sandbox.Config, + CNIResult: sandbox.CNIResult, + } + + if si.Status == "" { + // If processStatus is empty, it means that the task is deleted. Apply "deleted" + // status which does not exist in containerd. + si.Status = "deleted" + } + + if sandbox.NetNS != nil { + // Add network closed information if sandbox is not using host network. + closed, err := sandbox.NetNS.Closed() + if err != nil { + return nil, errors.Wrap(err, "failed to check network namespace closed") + } + si.NetNSClosed = closed + } + + spec, err := container.Spec(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox container runtime spec") + } + si.RuntimeSpec = spec + + ctrInfo, err := container.Info(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get sandbox container info") + } + // Do not use config.SandboxImage because the configuration might + // be changed during restart. It may not reflect the actual image + // used by the sandbox container. + si.Image = ctrInfo.Image + si.SnapshotKey = ctrInfo.SnapshotKey + si.Snapshotter = ctrInfo.Snapshotter + + runtimeOptions, err := getRuntimeOptions(ctrInfo) + if err != nil { + return nil, errors.Wrap(err, "failed to get runtime options") + } + si.RuntimeType = ctrInfo.Runtime.Name + si.RuntimeOptions = runtimeOptions + + infoBytes, err := json.Marshal(si) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal info %v", si) + } + return map[string]string{ + "info": string(infoBytes), + }, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_status_test.go containerd-1.5.9/pkg/cri/server/sandbox_status_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_status_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_status_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,116 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +func TestPodSandboxStatus(t *testing.T) { + const ( + id = "test-id" + ip = "10.10.10.10" + ) + additionalIPs := []string{"8.8.8.8", "2001:db8:85a3::8a2e:370:7334"} + createdAt := time.Now() + config := &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-name", + Uid: "test-uid", + Namespace: "test-ns", + Attempt: 1, + }, + Linux: &runtime.LinuxPodSandboxConfig{ + SecurityContext: &runtime.LinuxSandboxSecurityContext{ + NamespaceOptions: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_CONTAINER, + Ipc: runtime.NamespaceMode_POD, + }, + }, + }, + Labels: map[string]string{"a": "b"}, + Annotations: map[string]string{"c": "d"}, + } + metadata := sandboxstore.Metadata{ + ID: id, + Name: "test-name", + Config: config, + RuntimeHandler: "test-runtime-handler", + } + + expected := &runtime.PodSandboxStatus{ + Id: id, + Metadata: config.GetMetadata(), + CreatedAt: createdAt.UnixNano(), + Network: &runtime.PodSandboxNetworkStatus{ + Ip: ip, + AdditionalIps: []*runtime.PodIP{ + { + Ip: additionalIPs[0], + }, + { + Ip: additionalIPs[1], + }, + }, + }, + Linux: &runtime.LinuxPodSandboxStatus{ + Namespaces: &runtime.Namespace{ + Options: &runtime.NamespaceOption{ + Network: runtime.NamespaceMode_NODE, + Pid: runtime.NamespaceMode_CONTAINER, + Ipc: runtime.NamespaceMode_POD, + }, + }, + }, + Labels: config.GetLabels(), + Annotations: config.GetAnnotations(), + RuntimeHandler: "test-runtime-handler", + } + for desc, test := range map[string]struct { + state sandboxstore.State + expectedState runtime.PodSandboxState + }{ + "sandbox state ready": { + state: sandboxstore.StateReady, + expectedState: runtime.PodSandboxState_SANDBOX_READY, + }, + "sandbox state not ready": { + state: sandboxstore.StateNotReady, + expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, + }, + "sandbox state unknown": { + state: sandboxstore.StateUnknown, + expectedState: runtime.PodSandboxState_SANDBOX_NOTREADY, + }, + } { + t.Logf("TestCase: %s", desc) + status := sandboxstore.Status{ + CreatedAt: createdAt, + State: test.state, + } + expected.State = test.expectedState + got := toCRISandboxStatus(metadata, status, ip, additionalIPs) + assert.Equal(t, expected, got) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_stop.go containerd-1.5.9/pkg/cri/server/sandbox_stop.go --- containerd-1.2.6/pkg/cri/server/sandbox_stop.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_stop.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,195 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "syscall" + "time" + + eventtypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +// StopPodSandbox stops the sandbox. If there are any running containers in the +// sandbox, they should be forcibly terminated. +func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandboxRequest) (*runtime.StopPodSandboxResponse, error) { + sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) + if err != nil { + return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q", + r.GetPodSandboxId()) + } + + if err := c.stopPodSandbox(ctx, sandbox); err != nil { + return nil, err + } + + return &runtime.StopPodSandboxResponse{}, nil +} + +func (c *criService) stopPodSandbox(ctx context.Context, sandbox sandboxstore.Sandbox) error { + // Use the full sandbox id. + id := sandbox.ID + + // Stop all containers inside the sandbox. This terminates the container forcibly, + // and container may still be created, so production should not rely on this behavior. + // TODO(random-liu): Introduce a state in sandbox to avoid future container creation. + containers := c.containerStore.List() + for _, container := range containers { + if container.SandboxID != id { + continue + } + // Forcibly stop the container. Do not use `StopContainer`, because it introduces a race + // if a container is removed after list. + if err := c.stopContainer(ctx, container, 0); err != nil { + return errors.Wrapf(err, "failed to stop container %q", container.ID) + } + } + + if err := c.cleanupSandboxFiles(id, sandbox.Config); err != nil { + return errors.Wrap(err, "failed to cleanup sandbox files") + } + + // Only stop sandbox container when it's running or unknown. + state := sandbox.Status.Get().State + if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown { + if err := c.stopSandboxContainer(ctx, sandbox); err != nil { + return errors.Wrapf(err, "failed to stop sandbox container %q in %q state", id, state) + } + } + + // Teardown network for sandbox. + if sandbox.NetNS != nil { + // Use empty netns path if netns is not available. This is defined in: + // https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md + if closed, err := sandbox.NetNS.Closed(); err != nil { + return errors.Wrap(err, "failed to check network namespace closed") + } else if closed { + sandbox.NetNSPath = "" + } + if err := c.teardownPodNetwork(ctx, sandbox); err != nil { + return errors.Wrapf(err, "failed to destroy network for sandbox %q", id) + } + if err := sandbox.NetNS.Remove(); err != nil { + return errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id) + } + } + + log.G(ctx).Infof("TearDown network for sandbox %q successfully", id) + + return nil +} + +// stopSandboxContainer kills the sandbox container. +// `task.Delete` is not called here because it will be called when +// the event monitor handles the `TaskExit` event. +func (c *criService) stopSandboxContainer(ctx context.Context, sandbox sandboxstore.Sandbox) error { + id := sandbox.ID + container := sandbox.Container + state := sandbox.Status.Get().State + task, err := container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to get sandbox container") + } + // Don't return for unknown state, some cleanup needs to be done. + if state == sandboxstore.StateUnknown { + return cleanupUnknownSandbox(ctx, id, sandbox) + } + return nil + } + + // Handle unknown state. + // The cleanup logic is the same with container unknown state. + if state == sandboxstore.StateUnknown { + // Start an exit handler for containers in unknown state. + waitCtx, waitCancel := context.WithCancel(ctrdutil.NamespacedContext()) + defer waitCancel() + exitCh, err := task.Wait(waitCtx) + if err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to wait for task") + } + return cleanupUnknownSandbox(ctx, id, sandbox) + } + + exitCtx, exitCancel := context.WithCancel(context.Background()) + stopCh := c.eventMonitor.startSandboxExitMonitor(exitCtx, id, task.Pid(), exitCh) + defer func() { + exitCancel() + // This ensures that exit monitor is stopped before + // `Wait` is cancelled, so no exit event is generated + // because of the `Wait` cancellation. + <-stopCh + }() + } + + // Kill the sandbox container. + if err = task.Kill(ctx, syscall.SIGKILL); err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "failed to kill sandbox container") + } + + return c.waitSandboxStop(ctx, sandbox) +} + +// waitSandboxStop waits for sandbox to be stopped until context is cancelled or +// the context deadline is exceeded. +func (c *criService) waitSandboxStop(ctx context.Context, sandbox sandboxstore.Sandbox) error { + select { + case <-ctx.Done(): + return errors.Wrapf(ctx.Err(), "wait sandbox container %q", sandbox.ID) + case <-sandbox.Stopped(): + return nil + } +} + +// teardownPodNetwork removes the network from the pod +func (c *criService) teardownPodNetwork(ctx context.Context, sandbox sandboxstore.Sandbox) error { + if c.netPlugin == nil { + return errors.New("cni config not initialized") + } + + var ( + id = sandbox.ID + path = sandbox.NetNSPath + config = sandbox.Config + ) + opts, err := cniNamespaceOpts(id, config) + if err != nil { + return errors.Wrap(err, "get cni namespace options") + } + + return c.netPlugin.Remove(ctx, id, path, opts...) +} + +// cleanupUnknownSandbox cleanup stopped sandbox in unknown state. +func cleanupUnknownSandbox(ctx context.Context, id string, sandbox sandboxstore.Sandbox) error { + // Reuse handleSandboxExit to do the cleanup. + return handleSandboxExit(ctx, &eventtypes.TaskExit{ + ContainerID: id, + ID: id, + Pid: 0, + ExitStatus: unknownExitCode, + ExitedAt: time.Now(), + }, sandbox) +} diff -Nru containerd-1.2.6/pkg/cri/server/sandbox_stop_test.go containerd-1.5.9/pkg/cri/server/sandbox_stop_test.go --- containerd-1.2.6/pkg/cri/server/sandbox_stop_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/sandbox_stop_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" +) + +func TestWaitSandboxStop(t *testing.T) { + id := "test-id" + for desc, test := range map[string]struct { + state sandboxstore.State + cancel bool + timeout time.Duration + expectErr bool + }{ + "should return error if timeout exceeds": { + state: sandboxstore.StateReady, + timeout: 200 * time.Millisecond, + expectErr: true, + }, + "should return error if context is cancelled": { + state: sandboxstore.StateReady, + timeout: time.Hour, + cancel: true, + expectErr: true, + }, + "should not return error if sandbox is stopped before timeout": { + state: sandboxstore.StateNotReady, + timeout: time.Hour, + expectErr: false, + }, + } { + c := newTestCRIService() + sandbox := sandboxstore.NewSandbox( + sandboxstore.Metadata{ID: id}, + sandboxstore.Status{State: test.state}, + ) + ctx := context.Background() + if test.cancel { + cancelledCtx, cancel := context.WithCancel(ctx) + cancel() + ctx = cancelledCtx + } + if test.timeout > 0 { + timeoutCtx, cancel := context.WithTimeout(ctx, test.timeout) + defer cancel() + ctx = timeoutCtx + } + err := c.waitSandboxStop(ctx, sandbox) + assert.Equal(t, test.expectErr, err != nil, desc) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/service.go containerd-1.5.9/pkg/cri/server/service.go --- containerd-1.2.6/pkg/cri/server/service.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,328 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/cri/streaming" + "github.com/containerd/containerd/plugin" + cni "github.com/containerd/go-cni" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store/label" + + "github.com/containerd/containerd/pkg/atomic" + criconfig "github.com/containerd/containerd/pkg/cri/config" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" + osinterface "github.com/containerd/containerd/pkg/os" + "github.com/containerd/containerd/pkg/registrar" +) + +// grpcServices are all the grpc services provided by cri containerd. +type grpcServices interface { + runtime.RuntimeServiceServer + runtime.ImageServiceServer +} + +// CRIService is the interface implement CRI remote service server. +type CRIService interface { + Run() error + // io.Closer is used by containerd to gracefully stop cri service. + io.Closer + plugin.Service + grpcServices +} + +// criService implements CRIService. +type criService struct { + // config contains all configurations. + config criconfig.Config + // imageFSPath is the path to image filesystem. + imageFSPath string + // os is an interface for all required os operations. + os osinterface.OS + // sandboxStore stores all resources associated with sandboxes. + sandboxStore *sandboxstore.Store + // sandboxNameIndex stores all sandbox names and make sure each name + // is unique. + sandboxNameIndex *registrar.Registrar + // containerStore stores all resources associated with containers. + containerStore *containerstore.Store + // containerNameIndex stores all container names and make sure each + // name is unique. + containerNameIndex *registrar.Registrar + // imageStore stores all resources associated with images. + imageStore *imagestore.Store + // snapshotStore stores information of all snapshots. + snapshotStore *snapshotstore.Store + // netPlugin is used to setup and teardown network when run/stop pod sandbox. + netPlugin cni.CNI + // client is an instance of the containerd client + client *containerd.Client + // streamServer is the streaming server serves container streaming request. + streamServer streaming.Server + // eventMonitor is the monitor monitors containerd events. + eventMonitor *eventMonitor + // initialized indicates whether the server is initialized. All GRPC services + // should return error before the server is initialized. + initialized atomic.Bool + // cniNetConfMonitor is used to reload cni network conf if there is + // any valid fs change events from cni network conf dir. + cniNetConfMonitor *cniNetConfSyncer + // baseOCISpecs contains cached OCI specs loaded via `Runtime.BaseRuntimeSpec` + baseOCISpecs map[string]*oci.Spec + // allCaps is the list of the capabilities. + // When nil, parsed from CapEff of /proc/self/status. + allCaps []string // nolint +} + +// NewCRIService returns a new instance of CRIService +func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIService, error) { + var err error + labels := label.NewStore() + c := &criService{ + config: config, + client: client, + os: osinterface.RealOS{}, + sandboxStore: sandboxstore.NewStore(labels), + containerStore: containerstore.NewStore(labels), + imageStore: imagestore.NewStore(client), + snapshotStore: snapshotstore.NewStore(), + sandboxNameIndex: registrar.NewRegistrar(), + containerNameIndex: registrar.NewRegistrar(), + initialized: atomic.NewBool(false), + } + + if client.SnapshotService(c.config.ContainerdConfig.Snapshotter) == nil { + return nil, errors.Errorf("failed to find snapshotter %q", c.config.ContainerdConfig.Snapshotter) + } + + c.imageFSPath = imageFSPath(config.ContainerdRootDir, config.ContainerdConfig.Snapshotter) + logrus.Infof("Get image filesystem path %q", c.imageFSPath) + + if err := c.initPlatform(); err != nil { + return nil, errors.Wrap(err, "initialize platform") + } + + // prepare streaming server + c.streamServer, err = newStreamServer(c, config.StreamServerAddress, config.StreamServerPort, config.StreamIdleTimeout) + if err != nil { + return nil, errors.Wrap(err, "failed to create stream server") + } + + c.eventMonitor = newEventMonitor(c) + + c.cniNetConfMonitor, err = newCNINetConfSyncer(c.config.NetworkPluginConfDir, c.netPlugin, c.cniLoadOptions()) + if err != nil { + return nil, errors.Wrap(err, "failed to create cni conf monitor") + } + + // Preload base OCI specs + c.baseOCISpecs, err = loadBaseOCISpecs(&config) + if err != nil { + return nil, err + } + + return c, nil +} + +// Register registers all required services onto a specific grpc server. +// This is used by containerd cri plugin. +func (c *criService) Register(s *grpc.Server) error { + return c.register(s) +} + +// RegisterTCP register all required services onto a GRPC server on TCP. +// This is used by containerd CRI plugin. +func (c *criService) RegisterTCP(s *grpc.Server) error { + if !c.config.DisableTCPService { + return c.register(s) + } + return nil +} + +// Run starts the CRI service. +func (c *criService) Run() error { + logrus.Info("Start subscribing containerd event") + c.eventMonitor.subscribe(c.client) + + logrus.Infof("Start recovering state") + if err := c.recover(ctrdutil.NamespacedContext()); err != nil { + return errors.Wrap(err, "failed to recover state") + } + + // Start event handler. + logrus.Info("Start event monitor") + eventMonitorErrCh := c.eventMonitor.start() + + // Start snapshot stats syncer, it doesn't need to be stopped. + logrus.Info("Start snapshots syncer") + snapshotsSyncer := newSnapshotsSyncer( + c.snapshotStore, + c.client.SnapshotService(c.config.ContainerdConfig.Snapshotter), + time.Duration(c.config.StatsCollectPeriod)*time.Second, + ) + snapshotsSyncer.start() + + // Start CNI network conf syncer + logrus.Info("Start cni network conf syncer") + cniNetConfMonitorErrCh := make(chan error, 1) + go func() { + defer close(cniNetConfMonitorErrCh) + cniNetConfMonitorErrCh <- c.cniNetConfMonitor.syncLoop() + }() + + // Start streaming server. + logrus.Info("Start streaming server") + streamServerErrCh := make(chan error) + go func() { + defer close(streamServerErrCh) + if err := c.streamServer.Start(true); err != nil && err != http.ErrServerClosed { + logrus.WithError(err).Error("Failed to start streaming server") + streamServerErrCh <- err + } + }() + + // Set the server as initialized. GRPC services could start serving traffic. + c.initialized.Set() + + var eventMonitorErr, streamServerErr, cniNetConfMonitorErr error + // Stop the whole CRI service if any of the critical service exits. + select { + case eventMonitorErr = <-eventMonitorErrCh: + case streamServerErr = <-streamServerErrCh: + case cniNetConfMonitorErr = <-cniNetConfMonitorErrCh: + } + if err := c.Close(); err != nil { + return errors.Wrap(err, "failed to stop cri service") + } + // If the error is set above, err from channel must be nil here, because + // the channel is supposed to be closed. Or else, we wait and set it. + if err := <-eventMonitorErrCh; err != nil { + eventMonitorErr = err + } + logrus.Info("Event monitor stopped") + // There is a race condition with http.Server.Serve. + // When `Close` is called at the same time with `Serve`, `Close` + // may finish first, and `Serve` may still block. + // See https://github.com/golang/go/issues/20239. + // Here we set a 2 second timeout for the stream server wait, + // if it timeout, an error log is generated. + // TODO(random-liu): Get rid of this after https://github.com/golang/go/issues/20239 + // is fixed. + const streamServerStopTimeout = 2 * time.Second + select { + case err := <-streamServerErrCh: + if err != nil { + streamServerErr = err + } + logrus.Info("Stream server stopped") + case <-time.After(streamServerStopTimeout): + logrus.Errorf("Stream server is not stopped in %q", streamServerStopTimeout) + } + if eventMonitorErr != nil { + return errors.Wrap(eventMonitorErr, "event monitor error") + } + if streamServerErr != nil { + return errors.Wrap(streamServerErr, "stream server error") + } + if cniNetConfMonitorErr != nil { + return errors.Wrap(cniNetConfMonitorErr, "cni network conf monitor error") + } + return nil +} + +// Close stops the CRI service. +// TODO(random-liu): Make close synchronous. +func (c *criService) Close() error { + logrus.Info("Stop CRI service") + if err := c.cniNetConfMonitor.stop(); err != nil { + logrus.WithError(err).Error("failed to stop cni network conf monitor") + } + c.eventMonitor.stop() + if err := c.streamServer.Stop(); err != nil { + return errors.Wrap(err, "failed to stop stream server") + } + return nil +} + +func (c *criService) register(s *grpc.Server) error { + instrumented := newInstrumentedService(c) + runtime.RegisterRuntimeServiceServer(s, instrumented) + runtime.RegisterImageServiceServer(s, instrumented) + return nil +} + +// imageFSPath returns containerd image filesystem path. +// Note that if containerd changes directory layout, we also needs to change this. +func imageFSPath(rootDir, snapshotter string) string { + return filepath.Join(rootDir, fmt.Sprintf("%s.%s", plugin.SnapshotPlugin, snapshotter)) +} + +func loadOCISpec(filename string) (*oci.Spec, error) { + file, err := os.Open(filename) + if err != nil { + return nil, errors.Wrapf(err, "failed to open base OCI spec: %s", filename) + } + defer file.Close() + + spec := oci.Spec{} + if err := json.NewDecoder(file).Decode(&spec); err != nil { + return nil, errors.Wrap(err, "failed to parse base OCI spec file") + } + + return &spec, nil +} + +func loadBaseOCISpecs(config *criconfig.Config) (map[string]*oci.Spec, error) { + specs := map[string]*oci.Spec{} + for _, cfg := range config.Runtimes { + if cfg.BaseRuntimeSpec == "" { + continue + } + + // Don't load same file twice + if _, ok := specs[cfg.BaseRuntimeSpec]; ok { + continue + } + + spec, err := loadOCISpec(cfg.BaseRuntimeSpec) + if err != nil { + return nil, errors.Wrapf(err, "failed to load base OCI spec from file: %s", cfg.BaseRuntimeSpec) + } + + specs[cfg.BaseRuntimeSpec] = spec + } + + return specs, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/service_linux.go containerd-1.5.9/pkg/cri/server/service_linux.go --- containerd-1.2.6/pkg/cri/server/service_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/service_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,78 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/pkg/cap" + "github.com/containerd/containerd/pkg/userns" + cni "github.com/containerd/go-cni" + "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// networkAttachCount is the minimum number of networks the PodSandbox +// attaches to +const networkAttachCount = 2 + +// initPlatform handles linux specific initialization for the CRI service. +func (c *criService) initPlatform() error { + var err error + + if userns.RunningInUserNS() { + if !(c.config.DisableCgroup && !c.apparmorEnabled() && c.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 !selinux.GetEnabled() { + logrus.Warn("Selinux is not supported") + } + if r := c.config.SelinuxCategoryRange; r > 0 { + selinux.CategoryRange = uint32(r) + } + } else { + selinux.SetDisabled() + } + + // Pod needs to attach to at least loopback network and a non host network, + // hence networkAttachCount is 2. If there are more network configs the + // pod will be attached to all the networks but we will only use the ip + // of the default network interface as the pod IP. + c.netPlugin, err = cni.New(cni.WithMinNetworkCount(networkAttachCount), + cni.WithPluginConfDir(c.config.NetworkPluginConfDir), + cni.WithPluginMaxConfNum(c.config.NetworkPluginMaxConfNum), + cni.WithPluginDir([]string{c.config.NetworkPluginBinDir})) + if err != nil { + return errors.Wrap(err, "failed to initialize cni") + } + + if c.allCaps == nil { + c.allCaps, err = cap.Current() + if err != nil { + return errors.Wrap(err, "failed to get caps") + } + } + + return nil +} + +// cniLoadOptions returns cni load options for the linux. +func (c *criService) cniLoadOptions() []cni.Opt { + return []cni.Opt{cni.WithLoNetwork, cni.WithDefaultConf} +} diff -Nru containerd-1.2.6/pkg/cri/server/service_other.go containerd-1.5.9/pkg/cri/server/service_other.go --- containerd-1.2.6/pkg/cri/server/service_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/service_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + cni "github.com/containerd/go-cni" +) + +// initPlatform handles linux specific initialization for the CRI service. +func (c *criService) initPlatform() error { + return nil +} + +// cniLoadOptions returns cni load options for the linux. +func (c *criService) cniLoadOptions() []cni.Opt { + return []cni.Opt{} +} diff -Nru containerd-1.2.6/pkg/cri/server/service_test.go containerd-1.5.9/pkg/cri/server/service_test.go --- containerd-1.2.6/pkg/cri/server/service_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/service_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,102 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + "io/ioutil" + "os" + "testing" + + "github.com/containerd/containerd/oci" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + criconfig "github.com/containerd/containerd/pkg/cri/config" + servertesting "github.com/containerd/containerd/pkg/cri/server/testing" + containerstore "github.com/containerd/containerd/pkg/cri/store/container" + imagestore "github.com/containerd/containerd/pkg/cri/store/image" + "github.com/containerd/containerd/pkg/cri/store/label" + sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" + snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" + ostesting "github.com/containerd/containerd/pkg/os/testing" + "github.com/containerd/containerd/pkg/registrar" +) + +const ( + testRootDir = "/test/root" + testStateDir = "/test/state" + // Use an image id as test sandbox image to avoid image name resolve. + // TODO(random-liu): Change this to image name after we have complete image + // management unit test framework. + testSandboxImage = "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113798" + testImageFSPath = "/test/image/fs/path" +) + +// newTestCRIService creates a fake criService for test. +func newTestCRIService() *criService { + labels := label.NewStore() + return &criService{ + config: criconfig.Config{ + RootDir: testRootDir, + StateDir: testStateDir, + PluginConfig: criconfig.PluginConfig{ + SandboxImage: testSandboxImage, + }, + }, + imageFSPath: testImageFSPath, + os: ostesting.NewFakeOS(), + sandboxStore: sandboxstore.NewStore(labels), + imageStore: imagestore.NewStore(nil), + snapshotStore: snapshotstore.NewStore(), + sandboxNameIndex: registrar.NewRegistrar(), + containerStore: containerstore.NewStore(labels), + containerNameIndex: registrar.NewRegistrar(), + netPlugin: servertesting.NewFakeCNIPlugin(), + } +} + +func TestLoadBaseOCISpec(t *testing.T) { + spec := oci.Spec{Version: "1.0.2", Hostname: "default"} + + file, err := ioutil.TempFile("", "spec-test-") + require.NoError(t, err) + + defer func() { + assert.NoError(t, file.Close()) + assert.NoError(t, os.RemoveAll(file.Name())) + }() + + err = json.NewEncoder(file).Encode(&spec) + assert.NoError(t, err) + + config := criconfig.Config{} + config.Runtimes = map[string]criconfig.Runtime{ + "runc": {BaseRuntimeSpec: file.Name()}, + } + + specs, err := loadBaseOCISpecs(&config) + assert.NoError(t, err) + + assert.Len(t, specs, 1) + + out, ok := specs[file.Name()] + assert.True(t, ok, "expected spec with file name %q", file.Name()) + + assert.Equal(t, "1.0.2", out.Version) + assert.Equal(t, "default", out.Hostname) +} diff -Nru containerd-1.2.6/pkg/cri/server/service_windows.go containerd-1.5.9/pkg/cri/server/service_windows.go --- containerd-1.2.6/pkg/cri/server/service_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/service_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + cni "github.com/containerd/go-cni" + "github.com/pkg/errors" +) + +// windowsNetworkAttachCount is the minimum number of networks the PodSandbox +// attaches to +const windowsNetworkAttachCount = 1 + +// initPlatform handles linux specific initialization for the CRI service. +func (c *criService) initPlatform() error { + var err error + // For windows, the loopback network is added as default. + // There is no need to explicitly add one hence networkAttachCount is 1. + // If there are more network configs the pod will be attached to all the + // networks but we will only use the ip of the default network interface + // as the pod IP. + c.netPlugin, err = cni.New(cni.WithMinNetworkCount(windowsNetworkAttachCount), + cni.WithPluginConfDir(c.config.NetworkPluginConfDir), + cni.WithPluginMaxConfNum(c.config.NetworkPluginMaxConfNum), + cni.WithPluginDir([]string{c.config.NetworkPluginBinDir})) + if err != nil { + return errors.Wrap(err, "failed to initialize cni") + } + + return nil +} + +// cniLoadOptions returns cni load options for the windows. +func (c *criService) cniLoadOptions() []cni.Opt { + return []cni.Opt{cni.WithDefaultConf} +} diff -Nru containerd-1.2.6/pkg/cri/server/snapshots.go containerd-1.5.9/pkg/cri/server/snapshots.go --- containerd-1.2.6/pkg/cri/server/snapshots.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/snapshots.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,120 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "time" + + "github.com/containerd/containerd/errdefs" + snapshot "github.com/containerd/containerd/snapshots" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + snapshotstore "github.com/containerd/containerd/pkg/cri/store/snapshot" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +// snapshotsSyncer syncs snapshot stats periodically. imagefs info and container stats +// should both use cached result here. +// TODO(random-liu): Benchmark with high workload. We may need a statsSyncer instead if +// benchmark result shows that container cpu/memory stats also need to be cached. +type snapshotsSyncer struct { + store *snapshotstore.Store + snapshotter snapshot.Snapshotter + syncPeriod time.Duration +} + +// newSnapshotsSyncer creates a snapshot syncer. +func newSnapshotsSyncer(store *snapshotstore.Store, snapshotter snapshot.Snapshotter, + period time.Duration) *snapshotsSyncer { + return &snapshotsSyncer{ + store: store, + snapshotter: snapshotter, + syncPeriod: period, + } +} + +// start starts the snapshots syncer. No stop function is needed because +// the syncer doesn't update any persistent states, it's fine to let it +// exit with the process. +func (s *snapshotsSyncer) start() { + tick := time.NewTicker(s.syncPeriod) + go func() { + defer tick.Stop() + // TODO(random-liu): This is expensive. We should do benchmark to + // check the resource usage and optimize this. + for { + if err := s.sync(); err != nil { + logrus.WithError(err).Error("Failed to sync snapshot stats") + } + <-tick.C + } + }() +} + +// sync updates all snapshots stats. +func (s *snapshotsSyncer) sync() error { + ctx := ctrdutil.NamespacedContext() + start := time.Now().UnixNano() + var snapshots []snapshot.Info + // Do not call `Usage` directly in collect function, because + // `Usage` takes time, we don't want `Walk` to hold read lock + // of snapshot metadata store for too long time. + // TODO(random-liu): Set timeout for the following 2 contexts. + if err := s.snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error { + snapshots = append(snapshots, info) + return nil + }); err != nil { + return errors.Wrap(err, "walk all snapshots failed") + } + for _, info := range snapshots { + sn, err := s.store.Get(info.Name) + if err == nil { + // Only update timestamp for non-active snapshot. + if sn.Kind == info.Kind && sn.Kind != snapshot.KindActive { + sn.Timestamp = time.Now().UnixNano() + s.store.Add(sn) + continue + } + } + // Get newest stats if the snapshot is new or active. + sn = snapshotstore.Snapshot{ + Key: info.Name, + Kind: info.Kind, + Timestamp: time.Now().UnixNano(), + } + usage, err := s.snapshotter.Usage(ctx, info.Name) + if err != nil { + if !errdefs.IsNotFound(err) { + logrus.WithError(err).Errorf("Failed to get usage for snapshot %q", info.Name) + } + continue + } + sn.Size = uint64(usage.Size) + sn.Inodes = uint64(usage.Inodes) + s.store.Add(sn) + } + for _, sn := range s.store.List() { + if sn.Timestamp >= start { + continue + } + // Delete the snapshot stats if it's not updated this time. + s.store.Delete(sn.Key) + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/status.go containerd-1.5.9/pkg/cri/server/status.go --- containerd-1.2.6/pkg/cri/server/status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "encoding/json" + "fmt" + goruntime "runtime" + + "github.com/containerd/containerd/log" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// networkNotReadyReason is the reason reported when network is not ready. +const networkNotReadyReason = "NetworkPluginNotReady" + +// Status returns the status of the runtime. +func (c *criService) Status(ctx context.Context, r *runtime.StatusRequest) (*runtime.StatusResponse, error) { + // As a containerd plugin, if CRI plugin is serving request, + // containerd must be ready. + runtimeCondition := &runtime.RuntimeCondition{ + Type: runtime.RuntimeReady, + Status: true, + } + networkCondition := &runtime.RuntimeCondition{ + Type: runtime.NetworkReady, + Status: true, + } + // Check the status of the cni initialization + if err := c.netPlugin.Status(); err != nil { + networkCondition.Status = false + networkCondition.Reason = networkNotReadyReason + networkCondition.Message = fmt.Sprintf("Network plugin returns error: %v", err) + } + + resp := &runtime.StatusResponse{ + Status: &runtime.RuntimeStatus{Conditions: []*runtime.RuntimeCondition{ + runtimeCondition, + networkCondition, + }}, + } + if r.Verbose { + configByt, err := json.Marshal(c.config) + if err != nil { + return nil, err + } + resp.Info = make(map[string]string) + resp.Info["config"] = string(configByt) + versionByt, err := json.Marshal(goruntime.Version()) + if err != nil { + return nil, err + } + resp.Info["golang"] = string(versionByt) + + cniConfig, err := json.Marshal(c.netPlugin.GetConfig()) + if err != nil { + log.G(ctx).WithError(err).Errorf("Failed to marshal CNI config %v", err) + } + resp.Info["cniconfig"] = string(cniConfig) + + lastCNILoadStatus := "OK" + if lerr := c.cniNetConfMonitor.lastStatus(); lerr != nil { + lastCNILoadStatus = lerr.Error() + } + resp.Info["lastCNILoadStatus"] = lastCNILoadStatus + } + return resp, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/streaming.go containerd-1.5.9/pkg/cri/server/streaming.go --- containerd-1.2.6/pkg/cri/server/streaming.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/streaming.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,239 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "context" + "crypto/tls" + "io" + "math" + "net" + "os" + "time" + + "github.com/pkg/errors" + k8snet "k8s.io/apimachinery/pkg/util/net" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/tools/remotecommand" + k8scert "k8s.io/client-go/util/cert" + "k8s.io/utils/exec" + + "github.com/containerd/containerd/pkg/cri/streaming" + ctrdutil "github.com/containerd/containerd/pkg/cri/util" +) + +type streamListenerMode int + +const ( + x509KeyPairTLS streamListenerMode = iota + selfSignTLS + withoutTLS +) + +func getStreamListenerMode(c *criService) (streamListenerMode, error) { + if c.config.EnableTLSStreaming { + if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" { + return x509KeyPairTLS, nil + } + if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile == "" { + return -1, errors.New("must set X509KeyPairStreaming.TLSKeyFile") + } + if c.config.X509KeyPairStreaming.TLSCertFile == "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" { + return -1, errors.New("must set X509KeyPairStreaming.TLSCertFile") + } + return selfSignTLS, nil + } + if c.config.X509KeyPairStreaming.TLSCertFile != "" { + return -1, errors.New("X509KeyPairStreaming.TLSCertFile is set but EnableTLSStreaming is not set") + } + if c.config.X509KeyPairStreaming.TLSKeyFile != "" { + return -1, errors.New("X509KeyPairStreaming.TLSKeyFile is set but EnableTLSStreaming is not set") + } + return withoutTLS, nil +} + +func newStreamServer(c *criService, addr, port, streamIdleTimeout string) (streaming.Server, error) { + if addr == "" { + a, err := k8snet.ResolveBindAddress(nil) + if err != nil { + return nil, errors.Wrap(err, "failed to get stream server address") + } + addr = a.String() + } + config := streaming.DefaultConfig + if streamIdleTimeout != "" { + var err error + config.StreamIdleTimeout, err = time.ParseDuration(streamIdleTimeout) + if err != nil { + return nil, errors.Wrap(err, "invalid stream idle timeout") + } + } + config.Addr = net.JoinHostPort(addr, port) + run := newStreamRuntime(c) + tlsMode, err := getStreamListenerMode(c) + if err != nil { + return nil, errors.Wrapf(err, "invalid stream server configuration") + } + switch tlsMode { + case x509KeyPairTLS: + tlsCert, err := tls.LoadX509KeyPair(c.config.X509KeyPairStreaming.TLSCertFile, c.config.X509KeyPairStreaming.TLSKeyFile) + if err != nil { + return nil, errors.Wrap(err, "failed to load x509 key pair for stream server") + } + config.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{tlsCert}, + } + return streaming.NewServer(config, run) + case selfSignTLS: + tlsCert, err := newTLSCert() + if err != nil { + return nil, errors.Wrap(err, "failed to generate tls certificate for stream server") + } + config.TLSConfig = &tls.Config{ + Certificates: []tls.Certificate{tlsCert}, + InsecureSkipVerify: true, + } + return streaming.NewServer(config, run) + case withoutTLS: + return streaming.NewServer(config, run) + default: + return nil, errors.New("invalid configuration for the stream listener") + } +} + +type streamRuntime struct { + c *criService +} + +func newStreamRuntime(c *criService) streaming.Runtime { + return &streamRuntime{c: c} +} + +// Exec executes a command inside the container. exec.ExitError is returned if the command +// returns non-zero exit code. +func (s *streamRuntime) Exec(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, + tty bool, resize <-chan remotecommand.TerminalSize) error { + exitCode, err := s.c.execInContainer(ctrdutil.NamespacedContext(), containerID, execOptions{ + cmd: cmd, + stdin: stdin, + stdout: stdout, + stderr: stderr, + tty: tty, + resize: resize, + }) + if err != nil { + return errors.Wrap(err, "failed to exec in container") + } + if *exitCode == 0 { + return nil + } + return &exec.CodeExitError{ + Err: errors.Errorf("error executing command %v, exit code %d", cmd, *exitCode), + Code: int(*exitCode), + } +} + +func (s *streamRuntime) Attach(containerID string, in io.Reader, out, err io.WriteCloser, tty bool, + resize <-chan remotecommand.TerminalSize) error { + return s.c.attachContainer(ctrdutil.NamespacedContext(), containerID, in, out, err, tty, resize) +} + +func (s *streamRuntime) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error { + if port <= 0 || port > math.MaxUint16 { + return errors.Errorf("invalid port %d", port) + } + ctx := ctrdutil.NamespacedContext() + return s.c.portForward(ctx, podSandboxID, port, stream) +} + +// handleResizing spawns a goroutine that processes the resize channel, calling resizeFunc for each +// remotecommand.TerminalSize received from the channel. +func handleResizing(ctx context.Context, resize <-chan remotecommand.TerminalSize, resizeFunc func(size remotecommand.TerminalSize)) { + if resize == nil { + return + } + + go func() { + defer runtime.HandleCrash() + + for { + select { + case <-ctx.Done(): + return + case size, ok := <-resize: + if !ok { + return + } + if size.Height < 1 || size.Width < 1 { + continue + } + resizeFunc(size) + } + } + }() +} + +// newTLSCert returns a self CA signed tls.certificate. +// TODO (mikebrow): replace / rewrite this function to support using CA +// signing of the certificate. Requires a security plan for kubernetes regarding +// CRI connections / streaming, etc. For example, kubernetes could configure or +// require a CA service and pass a configuration down through CRI. +func newTLSCert() (tls.Certificate, error) { + fail := func(err error) (tls.Certificate, error) { return tls.Certificate{}, err } + + hostName, err := os.Hostname() + if err != nil { + return fail(errors.Wrap(err, "failed to get hostname")) + } + + addrs, err := net.InterfaceAddrs() + if err != nil { + return fail(errors.Wrap(err, "failed to get host IP addresses")) + } + + var alternateIPs []net.IP + var alternateDNS []string + for _, addr := range addrs { + var ip net.IP + + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + default: + continue + } + + alternateIPs = append(alternateIPs, ip) + alternateDNS = append(alternateDNS, ip.String()) + } + + // Generate a self signed certificate key (CA is self) + certPem, keyPem, err := k8scert.GenerateSelfSignedCertKey(hostName, alternateIPs, alternateDNS) + if err != nil { + return fail(errors.Wrap(err, "certificate key could not be created")) + } + + // Load the tls certificate + tlsCert, err := tls.X509KeyPair(certPem, keyPem) + if err != nil { + return fail(errors.Wrap(err, "certificate could not be loaded")) + } + + return tlsCert, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/streaming_test.go containerd-1.5.9/pkg/cri/server/streaming_test.go --- containerd-1.2.6/pkg/cri/server/streaming_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/streaming_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,153 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "testing" + + "github.com/containerd/containerd/pkg/cri/config" + "github.com/stretchr/testify/assert" +) + +func TestValidateStreamServer(t *testing.T) { + for desc, test := range map[string]struct { + *criService + tlsMode streamListenerMode + expectErr bool + }{ + "should pass with default withoutTLS": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.DefaultConfig(), + }, + }, + tlsMode: withoutTLS, + expectErr: false, + }, + "should pass with x509KeyPairTLS": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: true, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "non-empty", + TLSCertFile: "non-empty", + }, + }, + }, + }, + tlsMode: x509KeyPairTLS, + expectErr: false, + }, + "should pass with selfSign": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: true, + }, + }, + }, + tlsMode: selfSignTLS, + expectErr: false, + }, + "should return error with X509 keypair but not EnableTLSStreaming": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: false, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "non-empty", + TLSCertFile: "non-empty", + }, + }, + }, + }, + tlsMode: -1, + expectErr: true, + }, + "should return error with X509 TLSCertFile empty": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: true, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "non-empty", + TLSCertFile: "", + }, + }, + }, + }, + tlsMode: -1, + expectErr: true, + }, + "should return error with X509 TLSKeyFile empty": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: true, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "", + TLSCertFile: "non-empty", + }, + }, + }, + }, + tlsMode: -1, + expectErr: true, + }, + "should return error without EnableTLSStreaming and only TLSCertFile set": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: false, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "", + TLSCertFile: "non-empty", + }, + }, + }, + }, + tlsMode: -1, + expectErr: true, + }, + "should return error without EnableTLSStreaming and only TLSKeyFile set": { + criService: &criService{ + config: config.Config{ + PluginConfig: config.PluginConfig{ + EnableTLSStreaming: false, + X509KeyPairStreaming: config.X509KeyPairStreaming{ + TLSKeyFile: "non-empty", + TLSCertFile: "", + }, + }, + }, + }, + tlsMode: -1, + expectErr: true, + }, + } { + t.Run(desc, func(t *testing.T) { + tlsMode, err := getStreamListenerMode(test.criService) + if test.expectErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, test.tlsMode, tlsMode) + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/testing/fake_cni_plugin.go containerd-1.5.9/pkg/cri/server/testing/fake_cni_plugin.go --- containerd-1.2.6/pkg/cri/server/testing/fake_cni_plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/testing/fake_cni_plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testing + +import ( + "context" + + cni "github.com/containerd/go-cni" +) + +// FakeCNIPlugin is a fake plugin used for test. +type FakeCNIPlugin struct { + StatusErr error + LoadErr error +} + +// NewFakeCNIPlugin create a FakeCNIPlugin. +func NewFakeCNIPlugin() *FakeCNIPlugin { + return &FakeCNIPlugin{} +} + +// Setup setups the network of PodSandbox. +func (f *FakeCNIPlugin) Setup(ctx context.Context, id, path string, opts ...cni.NamespaceOpts) (*cni.Result, error) { + return nil, nil +} + +// Remove teardown the network of PodSandbox. +func (f *FakeCNIPlugin) Remove(ctx context.Context, id, path string, opts ...cni.NamespaceOpts) error { + return nil +} + +// Status get the status of the plugin. +func (f *FakeCNIPlugin) Status() error { + return f.StatusErr +} + +// Load loads the network config. +func (f *FakeCNIPlugin) Load(opts ...cni.Opt) error { + return f.LoadErr +} + +// GetConfig returns a copy of the CNI plugin configurations as parsed by CNI +func (f *FakeCNIPlugin) GetConfig() *cni.ConfigResult { + return nil +} diff -Nru containerd-1.2.6/pkg/cri/server/update_runtime_config.go containerd-1.5.9/pkg/cri/server/update_runtime_config.go --- containerd-1.2.6/pkg/cri/server/update_runtime_config.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/update_runtime_config.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,128 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "net" + "os" + "path/filepath" + "strings" + "text/template" + + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// cniConfigTemplate contains the values containerd will overwrite +// in the cni config template. +type cniConfigTemplate struct { + // PodCIDR is the cidr for pods on the node. + PodCIDR string + // PodCIDRRanges is the cidr ranges for pods on the node. + PodCIDRRanges []string + // Routes is a list of routes configured. + Routes []string +} + +const ( + // cniConfigFileName is the name of cni config file generated by containerd. + cniConfigFileName = "10-containerd-net.conflist" + // zeroCIDRv6 is the null route for IPv6. + zeroCIDRv6 = "::/0" + // zeroCIDRv4 is the null route for IPv4. + zeroCIDRv4 = "0.0.0.0/0" +) + +// UpdateRuntimeConfig updates the runtime config. Currently only handles podCIDR updates. +func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateRuntimeConfigRequest) (*runtime.UpdateRuntimeConfigResponse, error) { + podCIDRs := r.GetRuntimeConfig().GetNetworkConfig().GetPodCidr() + if podCIDRs == "" { + return &runtime.UpdateRuntimeConfigResponse{}, nil + } + cidrs := strings.Split(podCIDRs, ",") + for i := range cidrs { + cidrs[i] = strings.TrimSpace(cidrs[i]) + } + routes, err := getRoutes(cidrs) + if err != nil { + return nil, errors.Wrap(err, "get routes") + } + + confTemplate := c.config.NetworkPluginConfTemplate + if confTemplate == "" { + log.G(ctx).Info("No cni config template is specified, wait for other system components to drop the config.") + return &runtime.UpdateRuntimeConfigResponse{}, nil + } + if err := c.netPlugin.Status(); err == nil { + log.G(ctx).Infof("Network plugin is ready, skip generating cni config from template %q", confTemplate) + return &runtime.UpdateRuntimeConfigResponse{}, nil + } else if err := c.netPlugin.Load(c.cniLoadOptions()...); err == nil { + log.G(ctx).Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate) + return &runtime.UpdateRuntimeConfigResponse{}, nil + } + log.G(ctx).Infof("Generating cni config from template %q", confTemplate) + // generate cni config file from the template with updated pod cidr. + t, err := template.ParseFiles(confTemplate) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse cni config template %q", confTemplate) + } + if err := os.MkdirAll(c.config.NetworkPluginConfDir, 0755); err != nil { + return nil, errors.Wrapf(err, "failed to create cni config directory: %q", c.config.NetworkPluginConfDir) + } + confFile := filepath.Join(c.config.NetworkPluginConfDir, cniConfigFileName) + f, err := os.OpenFile(confFile, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return nil, errors.Wrapf(err, "failed to open cni config file %q", confFile) + } + defer f.Close() + if err := t.Execute(f, cniConfigTemplate{ + PodCIDR: cidrs[0], + PodCIDRRanges: cidrs, + Routes: routes, + }); err != nil { + return nil, errors.Wrapf(err, "failed to generate cni config file %q", confFile) + } + return &runtime.UpdateRuntimeConfigResponse{}, nil +} + +// getRoutes generates required routes for the passed in cidrs. +func getRoutes(cidrs []string) ([]string, error) { + var ( + routes []string + hasV4, hasV6 bool + ) + for _, c := range cidrs { + _, cidr, err := net.ParseCIDR(c) + if err != nil { + return nil, err + } + if cidr.IP.To4() != nil { + hasV4 = true + } else { + hasV6 = true + } + } + if hasV4 { + routes = append(routes, zeroCIDRv4) + } + if hasV6 { + routes = append(routes, zeroCIDRv6) + } + return routes, nil +} diff -Nru containerd-1.2.6/pkg/cri/server/update_runtime_config_test.go containerd-1.5.9/pkg/cri/server/update_runtime_config_test.go --- containerd-1.2.6/pkg/cri/server/update_runtime_config_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/update_runtime_config_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,140 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + criconfig "github.com/containerd/containerd/pkg/cri/config" + servertesting "github.com/containerd/containerd/pkg/cri/server/testing" +) + +func TestUpdateRuntimeConfig(t *testing.T) { + const ( + testTemplate = ` +{ + "name": "test-pod-network", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "ptp", + "mtu": 1460, + "ipam": { + "type": "host-local", + "subnet": "{{.PodCIDR}}", + "ranges": [{{range $i, $range := .PodCIDRRanges}}{{if $i}}, {{end}}[{"subnet": "{{$range}}"}]{{end}}], + "routes": [{{range $i, $route := .Routes}}{{if $i}}, {{end}}{"dst": "{{$route}}"}{{end}}] + } + }, + ] +}` + testCIDR = "10.0.0.0/24, 2001:4860:4860::/64" + expected = ` +{ + "name": "test-pod-network", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "ptp", + "mtu": 1460, + "ipam": { + "type": "host-local", + "subnet": "10.0.0.0/24", + "ranges": [[{"subnet": "10.0.0.0/24"}], [{"subnet": "2001:4860:4860::/64"}]], + "routes": [{"dst": "0.0.0.0/0"}, {"dst": "::/0"}] + } + }, + ] +}` + ) + + for name, test := range map[string]struct { + noTemplate bool + emptyCIDR bool + networkReady bool + expectCNIConfig bool + }{ + "should not generate cni config if cidr is empty": { + emptyCIDR: true, + expectCNIConfig: false, + }, + "should not generate cni config if template file is not specified": { + noTemplate: true, + expectCNIConfig: false, + }, + "should not generate cni config if network is ready": { + networkReady: true, + expectCNIConfig: false, + }, + "should generate cni config if template is specified and cidr is provided": { + expectCNIConfig: true, + }, + } { + t.Run(name, func(t *testing.T) { + testDir, err := ioutil.TempDir(os.TempDir(), "test-runtime-config") + require.NoError(t, err) + defer os.RemoveAll(testDir) + templateName := filepath.Join(testDir, "template") + err = ioutil.WriteFile(templateName, []byte(testTemplate), 0666) + require.NoError(t, err) + confDir := filepath.Join(testDir, "net.d") + confName := filepath.Join(confDir, cniConfigFileName) + + c := newTestCRIService() + c.config.CniConfig = criconfig.CniConfig{ + NetworkPluginConfDir: confDir, + NetworkPluginConfTemplate: templateName, + } + req := &runtime.UpdateRuntimeConfigRequest{ + RuntimeConfig: &runtime.RuntimeConfig{ + NetworkConfig: &runtime.NetworkConfig{ + PodCidr: testCIDR, + }, + }, + } + if test.noTemplate { + c.config.CniConfig.NetworkPluginConfTemplate = "" + } + if test.emptyCIDR { + req.RuntimeConfig.NetworkConfig.PodCidr = "" + } + if !test.networkReady { + c.netPlugin.(*servertesting.FakeCNIPlugin).StatusErr = errors.New("random error") + c.netPlugin.(*servertesting.FakeCNIPlugin).LoadErr = errors.New("random error") + } + _, err = c.UpdateRuntimeConfig(context.Background(), req) + assert.NoError(t, err) + if !test.expectCNIConfig { + _, err := os.Stat(confName) + assert.Error(t, err) + } else { + got, err := ioutil.ReadFile(confName) + assert.NoError(t, err) + assert.Equal(t, expected, string(got)) + } + }) + } +} diff -Nru containerd-1.2.6/pkg/cri/server/version.go containerd-1.5.9/pkg/cri/server/version.go --- containerd-1.2.6/pkg/cri/server/version.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/server/version.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package server + +import ( + "github.com/containerd/containerd/version" + "golang.org/x/net/context" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/constants" +) + +const ( + containerName = "containerd" + // kubeAPIVersion is the api version of kubernetes. + // TODO(random-liu): Change this to actual CRI version. + kubeAPIVersion = "0.1.0" +) + +// Version returns the runtime name, runtime version and runtime API version. +func (c *criService) Version(ctx context.Context, r *runtime.VersionRequest) (*runtime.VersionResponse, error) { + return &runtime.VersionResponse{ + Version: kubeAPIVersion, + RuntimeName: containerName, + RuntimeVersion: version.Version, + RuntimeApiVersion: constants.CRIVersion, + }, nil +} diff -Nru containerd-1.2.6/pkg/cri/store/container/container.go containerd-1.5.9/pkg/cri/store/container/container.go --- containerd-1.2.6/pkg/cri/store/container/container.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/container.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,181 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "sync" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/pkg/cri/store/label" + "github.com/containerd/containerd/pkg/cri/store/truncindex" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + "github.com/containerd/containerd/pkg/cri/store" +) + +// Container contains all resources associated with the container. All methods to +// mutate the internal state are thread-safe. +type Container struct { + // Metadata is the metadata of the container, it is **immutable** after created. + Metadata + // Status stores the status of the container. + Status StatusStorage + // Container is the containerd container client. + Container containerd.Container + // Container IO. + // IO could only be nil when the container is in unknown state. + IO *cio.ContainerIO + // StopCh is used to propagate the stop information of the container. + *store.StopCh + // IsStopSignaledWithTimeout the default is 0, and it is set to 1 after sending + // the signal once to avoid repeated sending of the signal. + IsStopSignaledWithTimeout *uint32 +} + +// Opts sets specific information to newly created Container. +type Opts func(*Container) error + +// WithContainer adds the containerd Container to the internal data store. +func WithContainer(cntr containerd.Container) Opts { + return func(c *Container) error { + c.Container = cntr + return nil + } +} + +// WithContainerIO adds IO into the container. +func WithContainerIO(io *cio.ContainerIO) Opts { + return func(c *Container) error { + c.IO = io + return nil + } +} + +// WithStatus adds status to the container. +func WithStatus(status Status, root string) Opts { + return func(c *Container) error { + s, err := StoreStatus(root, c.ID, status) + if err != nil { + return err + } + c.Status = s + if s.Get().State() == runtime.ContainerState_CONTAINER_EXITED { + c.Stop() + } + return nil + } +} + +// NewContainer creates an internally used container type. +func NewContainer(metadata Metadata, opts ...Opts) (Container, error) { + c := Container{ + Metadata: metadata, + StopCh: store.NewStopCh(), + IsStopSignaledWithTimeout: new(uint32), + } + for _, o := range opts { + if err := o(&c); err != nil { + return Container{}, err + } + } + return c, nil +} + +// Delete deletes checkpoint for the container. +func (c *Container) Delete() error { + return c.Status.Delete() +} + +// Store stores all Containers. +type Store struct { + lock sync.RWMutex + containers map[string]Container + idIndex *truncindex.TruncIndex + labels *label.Store +} + +// NewStore creates a container store. +func NewStore(labels *label.Store) *Store { + return &Store{ + containers: make(map[string]Container), + idIndex: truncindex.NewTruncIndex([]string{}), + labels: labels, + } +} + +// Add a container into the store. Returns store.ErrAlreadyExist if the +// container already exists. +func (s *Store) Add(c Container) error { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.containers[c.ID]; ok { + return store.ErrAlreadyExist + } + if err := s.labels.Reserve(c.ProcessLabel); err != nil { + return err + } + if err := s.idIndex.Add(c.ID); err != nil { + return err + } + s.containers[c.ID] = c + return nil +} + +// Get returns the container with specified id. Returns store.ErrNotExist +// if the container doesn't exist. +func (s *Store) Get(id string) (Container, error) { + s.lock.RLock() + defer s.lock.RUnlock() + id, err := s.idIndex.Get(id) + if err != nil { + if err == truncindex.ErrNotExist { + err = store.ErrNotExist + } + return Container{}, err + } + if c, ok := s.containers[id]; ok { + return c, nil + } + return Container{}, store.ErrNotExist +} + +// List lists all containers. +func (s *Store) List() []Container { + s.lock.RLock() + defer s.lock.RUnlock() + var containers []Container + for _, c := range s.containers { + containers = append(containers, c) + } + return containers +} + +// Delete deletes the container from store with specified id. +func (s *Store) Delete(id string) { + s.lock.Lock() + defer s.lock.Unlock() + id, err := s.idIndex.Get(id) + if err != nil { + // Note: The idIndex.Delete and delete doesn't handle truncated index. + // So we need to return if there are error. + return + } + s.labels.Release(s.containers[id].ProcessLabel) + s.idIndex.Delete(id) // nolint: errcheck + delete(s.containers, id) +} diff -Nru containerd-1.2.6/pkg/cri/store/container/container_test.go containerd-1.5.9/pkg/cri/store/container/container_test.go --- containerd-1.2.6/pkg/cri/store/container/container_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/container_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,247 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "strings" + "testing" + "time" + + "github.com/containerd/containerd/pkg/cri/store/label" + "github.com/opencontainers/selinux/go-selinux" + assertlib "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + cio "github.com/containerd/containerd/pkg/cri/io" + "github.com/containerd/containerd/pkg/cri/store" +) + +func TestContainerStore(t *testing.T) { + metadatas := map[string]Metadata{ + "1": { + ID: "1", + Name: "Container-1", + SandboxID: "Sandbox-1", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "TestPod-1", + Attempt: 1, + }, + }, + ImageRef: "TestImage-1", + StopSignal: "SIGTERM", + LogPath: "/test/log/path/1", + ProcessLabel: "junk:junk:junk:c1,c2", + }, + "2abcd": { + ID: "2abcd", + Name: "Container-2abcd", + SandboxID: "Sandbox-2abcd", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "TestPod-2abcd", + Attempt: 2, + }, + }, + StopSignal: "SIGTERM", + ImageRef: "TestImage-2", + LogPath: "/test/log/path/2", + ProcessLabel: "junk:junk:junk:c1,c2", + }, + "4a333": { + ID: "4a333", + Name: "Container-4a333", + SandboxID: "Sandbox-4a333", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "TestPod-4a333", + Attempt: 3, + }, + }, + StopSignal: "SIGTERM", + ImageRef: "TestImage-3", + LogPath: "/test/log/path/3", + ProcessLabel: "junk:junk:junk:c1,c3", + }, + "4abcd": { + ID: "4abcd", + Name: "Container-4abcd", + SandboxID: "Sandbox-4abcd", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "TestPod-4abcd", + Attempt: 1, + }, + }, + StopSignal: "SIGTERM", + ImageRef: "TestImage-4abcd", + ProcessLabel: "junk:junk:junk:c1,c4", + }, + } + statuses := map[string]Status{ + "1": { + Pid: 1, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 1, + Reason: "TestReason-1", + Message: "TestMessage-1", + }, + "2abcd": { + Pid: 2, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 2, + Reason: "TestReason-2abcd", + Message: "TestMessage-2abcd", + }, + "4a333": { + Pid: 3, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 3, + Reason: "TestReason-4a333", + Message: "TestMessage-4a333", + Starting: true, + }, + "4abcd": { + Pid: 4, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 4, + Reason: "TestReason-4abcd", + Message: "TestMessage-4abcd", + Removing: true, + }, + } + assert := assertlib.New(t) + containers := map[string]Container{} + for id := range metadatas { + container, err := NewContainer( + metadatas[id], + WithFakeStatus(statuses[id]), + ) + assert.NoError(err) + containers[id] = container + } + + s := NewStore(label.NewStore()) + reserved := map[string]bool{} + s.labels.Reserver = func(label string) { + reserved[strings.SplitN(label, ":", 4)[3]] = true + } + s.labels.Releaser = func(label string) { + reserved[strings.SplitN(label, ":", 4)[3]] = false + } + + t.Logf("should be able to add container") + for _, c := range containers { + assert.NoError(s.Add(c)) + } + + t.Logf("should be able to get container") + genTruncIndex := func(normalName string) string { return normalName[:(len(normalName)+1)/2] } + for id, c := range containers { + got, err := s.Get(genTruncIndex(id)) + assert.NoError(err) + assert.Equal(c, got) + } + + t.Logf("should be able to list containers") + cs := s.List() + assert.Len(cs, len(containers)) + + if selinux.GetEnabled() { + t.Logf("should have reserved labels (requires -tag selinux)") + assert.Equal(map[string]bool{ + "c1,c2": true, + "c1,c3": true, + "c1,c4": true, + }, reserved) + } + + cntrNum := len(containers) + for testID, v := range containers { + truncID := genTruncIndex(testID) + + t.Logf("add should return already exists error for duplicated container") + assert.Equal(store.ErrAlreadyExist, s.Add(v)) + + t.Logf("should be able to delete container") + s.Delete(truncID) + cntrNum-- + cs = s.List() + assert.Len(cs, cntrNum) + + t.Logf("get should return not exist error after deletion") + c, err := s.Get(truncID) + assert.Equal(Container{}, c) + assert.Equal(store.ErrNotExist, err) + } + + if selinux.GetEnabled() { + t.Logf("should have released all labels (requires -tag selinux)") + assert.Equal(map[string]bool{ + "c1,c2": false, + "c1,c3": false, + "c1,c4": false, + }, reserved) + } +} + +func TestWithContainerIO(t *testing.T) { + meta := Metadata{ + ID: "1", + Name: "Container-1", + SandboxID: "Sandbox-1", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "TestPod-1", + Attempt: 1, + }, + }, + ImageRef: "TestImage-1", + StopSignal: "SIGTERM", + LogPath: "/test/log/path", + } + status := Status{ + Pid: 1, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 1, + Reason: "TestReason-1", + Message: "TestMessage-1", + } + assert := assertlib.New(t) + + c, err := NewContainer(meta, WithFakeStatus(status)) + assert.NoError(err) + assert.Nil(c.IO) + + c, err = NewContainer( + meta, + WithFakeStatus(status), + WithContainerIO(&cio.ContainerIO{}), + ) + assert.NoError(err) + assert.NotNil(c.IO) +} diff -Nru containerd-1.2.6/pkg/cri/store/container/fake_status.go containerd-1.5.9/pkg/cri/store/container/fake_status.go --- containerd-1.2.6/pkg/cri/store/container/fake_status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/fake_status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import "sync" + +// WithFakeStatus adds fake status to the container. +func WithFakeStatus(status Status) Opts { + return func(c *Container) error { + c.Status = &fakeStatusStorage{status: status} + if status.FinishedAt != 0 { + // Fake the TaskExit event + c.Stop() + } + return nil + } +} + +// fakeStatusStorage is a fake status storage for testing. +type fakeStatusStorage struct { + sync.RWMutex + status Status +} + +func (f *fakeStatusStorage) Get() Status { + f.RLock() + defer f.RUnlock() + return f.status +} + +func (f *fakeStatusStorage) UpdateSync(u UpdateFunc) error { + return f.Update(u) +} + +func (f *fakeStatusStorage) Update(u UpdateFunc) error { + f.Lock() + defer f.Unlock() + newStatus, err := u(f.status) + if err != nil { + return err + } + f.status = newStatus + return nil +} + +func (f *fakeStatusStorage) Delete() error { + return nil +} diff -Nru containerd-1.2.6/pkg/cri/store/container/metadata.go containerd-1.5.9/pkg/cri/store/container/metadata.go --- containerd-1.2.6/pkg/cri/store/container/metadata.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/metadata.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "encoding/json" + + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// NOTE(random-liu): +// 1) Metadata is immutable after created. +// 2) Metadata is checkpointed as containerd container label. + +// metadataVersion is current version of container metadata. +const metadataVersion = "v1" // nolint + +// versionedMetadata is the internal versioned container metadata. +// nolint +type versionedMetadata struct { + // Version indicates the version of the versioned container metadata. + Version string + // Metadata's type is metadataInternal. If not there will be a recursive call in MarshalJSON. + Metadata metadataInternal +} + +// metadataInternal is for internal use. +type metadataInternal Metadata + +// Metadata is the unversioned container metadata. +type Metadata struct { + // ID is the container id. + ID string + // Name is the container name. + Name string + // SandboxID is the sandbox id the container belongs to. + SandboxID string + // Config is the CRI container config. + // NOTE(random-liu): Resource limits are updatable, the source + // of truth for resource limits are in containerd. + Config *runtime.ContainerConfig + // ImageRef is the reference of image used by the container. + ImageRef string + // LogPath is the container log path. + LogPath string + // StopSignal is the system call signal that will be sent to the container to exit. + // TODO(random-liu): Add integration test for stop signal. + StopSignal string + // ProcessLabel is the SELinux process label for the container + ProcessLabel string +} + +// MarshalJSON encodes Metadata into bytes in json format. +func (c *Metadata) MarshalJSON() ([]byte, error) { + return json.Marshal(&versionedMetadata{ + Version: metadataVersion, + Metadata: metadataInternal(*c), + }) +} + +// UnmarshalJSON decodes Metadata from bytes. +func (c *Metadata) UnmarshalJSON(data []byte) error { + versioned := &versionedMetadata{} + if err := json.Unmarshal(data, versioned); err != nil { + return err + } + // Handle old version after upgrade. + switch versioned.Version { + case metadataVersion: + *c = Metadata(versioned.Metadata) + return nil + } + return errors.Errorf("unsupported version: %q", versioned.Version) +} diff -Nru containerd-1.2.6/pkg/cri/store/container/metadata_test.go containerd-1.5.9/pkg/cri/store/container/metadata_test.go --- containerd-1.2.6/pkg/cri/store/container/metadata_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/metadata_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "encoding/json" + "testing" + + assertlib "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestMetadataMarshalUnmarshal(t *testing.T) { + meta := &Metadata{ + ID: "test-id", + Name: "test-name", + SandboxID: "test-sandbox-id", + Config: &runtime.ContainerConfig{ + Metadata: &runtime.ContainerMetadata{ + Name: "test-name", + Attempt: 1, + }, + }, + ImageRef: "test-image-ref", + LogPath: "/test/log/path", + } + + assert := assertlib.New(t) + newMeta := &Metadata{} + newVerMeta := &versionedMetadata{} + + t.Logf("should be able to do json.marshal") + data, err := json.Marshal(meta) + assert.NoError(err) + data1, err := json.Marshal(&versionedMetadata{ + Version: metadataVersion, + Metadata: metadataInternal(*meta), + }) + assert.NoError(err) + assert.Equal(data, data1) + + t.Logf("should be able to do MarshalJSON") + data, err = meta.MarshalJSON() + assert.NoError(err) + assert.NoError(newMeta.UnmarshalJSON(data)) + assert.Equal(meta, newMeta) + + t.Logf("should be able to do MarshalJSON and json.Unmarshal") + data, err = meta.MarshalJSON() + assert.NoError(err) + assert.NoError(json.Unmarshal(data, newVerMeta)) + assert.Equal(meta, (*Metadata)(&newVerMeta.Metadata)) + + t.Logf("should be able to do json.Marshal and UnmarshalJSON") + data, err = json.Marshal(meta) + assert.NoError(err) + assert.NoError(newMeta.UnmarshalJSON(data)) + assert.Equal(meta, newMeta) + + t.Logf("should json.Unmarshal fail for unsupported version") + unsupported, err := json.Marshal(&versionedMetadata{ + Version: "random-test-version", + Metadata: metadataInternal(*meta), + }) + assert.NoError(err) + assert.Error(json.Unmarshal(unsupported, &newMeta)) +} diff -Nru containerd-1.2.6/pkg/cri/store/container/status.go containerd-1.5.9/pkg/cri/store/container/status.go --- containerd-1.2.6/pkg/cri/store/container/status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,247 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "github.com/containerd/continuity" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// The container state machine in the CRI plugin: +// +// + + +// | | +// | Create | Load +// | | +// +----v----+ | +// | | | +// | CREATED <---------+-----------+ +// | | | | +// +----+----- | | +// | | | +// | Start | | +// | | | +// +----v----+ | | +// Exec +--------+ | | | +// Attach | | RUNNING <---------+ | +// LogReopen +--------> | | | +// +----+----+ | | +// | | | +// | Stop/Exit | | +// | | | +// +----v----+ | | +// | <---------+ +----v----+ +// | EXITED | | | +// | <----------------+ UNKNOWN | +// +----+----+ Stop | | +// | +---------+ +// | Remove +// v +// DELETED + +// statusVersion is current version of container status. +const statusVersion = "v1" // nolint + +// versionedStatus is the internal used versioned container status. +// nolint +type versionedStatus struct { + // Version indicates the version of the versioned container status. + Version string + Status +} + +// Status is the status of a container. +type Status struct { + // Pid is the init process id of the container. + Pid uint32 + // CreatedAt is the created timestamp. + CreatedAt int64 + // StartedAt is the started timestamp. + StartedAt int64 + // FinishedAt is the finished timestamp. + FinishedAt int64 + // ExitCode is the container exit code. + ExitCode int32 + // CamelCase string explaining why container is in its current state. + Reason string + // Human-readable message indicating details about why container is in its + // current state. + Message string + // Starting indicates that the container is in starting state. + // This field doesn't need to be checkpointed. + Starting bool `json:"-"` + // Removing indicates that the container is in removing state. + // This field doesn't need to be checkpointed. + Removing bool `json:"-"` + // Unknown indicates that the container status is not fully loaded. + // This field doesn't need to be checkpointed. + Unknown bool `json:"-"` +} + +// State returns current state of the container based on the container status. +func (s Status) State() runtime.ContainerState { + if s.Unknown { + return runtime.ContainerState_CONTAINER_UNKNOWN + } + if s.FinishedAt != 0 { + return runtime.ContainerState_CONTAINER_EXITED + } + if s.StartedAt != 0 { + return runtime.ContainerState_CONTAINER_RUNNING + } + if s.CreatedAt != 0 { + return runtime.ContainerState_CONTAINER_CREATED + } + return runtime.ContainerState_CONTAINER_UNKNOWN +} + +// encode encodes Status into bytes in json format. +func (s *Status) encode() ([]byte, error) { + return json.Marshal(&versionedStatus{ + Version: statusVersion, + Status: *s, + }) +} + +// decode decodes Status from bytes. +func (s *Status) decode(data []byte) error { + versioned := &versionedStatus{} + if err := json.Unmarshal(data, versioned); err != nil { + return err + } + // Handle old version after upgrade. + switch versioned.Version { + case statusVersion: + *s = versioned.Status + return nil + } + return errors.New("unsupported version") +} + +// UpdateFunc is function used to update the container status. If there +// is an error, the update will be rolled back. +type UpdateFunc func(Status) (Status, error) + +// StatusStorage manages the container status with a storage backend. +type StatusStorage interface { + // Get a container status. + Get() Status + // UpdateSync updates the container status and the on disk checkpoint. + // Note that the update MUST be applied in one transaction. + UpdateSync(UpdateFunc) error + // Update the container status. Note that the update MUST be applied + // in one transaction. + Update(UpdateFunc) error + // Delete the container status. + // Note: + // * Delete should be idempotent. + // * The status must be deleted in one transaction. + Delete() error +} + +// StoreStatus creates the storage containing the passed in container status with the +// specified id. +// The status MUST be created in one transaction. +func StoreStatus(root, id string, status Status) (StatusStorage, error) { + data, err := status.encode() + if err != nil { + return nil, errors.Wrap(err, "failed to encode status") + } + path := filepath.Join(root, "status") + if err := continuity.AtomicWriteFile(path, data, 0600); err != nil { + return nil, errors.Wrapf(err, "failed to checkpoint status to %q", path) + } + return &statusStorage{ + path: path, + status: status, + }, nil +} + +// LoadStatus loads container status from checkpoint. There shouldn't be threads +// writing to the file during loading. +func LoadStatus(root, id string) (Status, error) { + path := filepath.Join(root, "status") + data, err := ioutil.ReadFile(path) + if err != nil { + return Status{}, errors.Wrapf(err, "failed to read status from %q", path) + } + var status Status + if err := status.decode(data); err != nil { + return Status{}, errors.Wrapf(err, "failed to decode status %q", data) + } + return status, nil +} + +type statusStorage struct { + sync.RWMutex + path string + status Status +} + +// Get a copy of container status. +func (s *statusStorage) Get() Status { + s.RLock() + defer s.RUnlock() + return s.status +} + +// UpdateSync updates the container status and the on disk checkpoint. +func (s *statusStorage) UpdateSync(u UpdateFunc) error { + s.Lock() + defer s.Unlock() + newStatus, err := u(s.status) + if err != nil { + return err + } + data, err := newStatus.encode() + if err != nil { + return errors.Wrap(err, "failed to encode status") + } + if err := continuity.AtomicWriteFile(s.path, data, 0600); err != nil { + return errors.Wrapf(err, "failed to checkpoint status to %q", s.path) + } + s.status = newStatus + return nil +} + +// Update the container status. +func (s *statusStorage) Update(u UpdateFunc) error { + s.Lock() + defer s.Unlock() + newStatus, err := u(s.status) + if err != nil { + return err + } + s.status = newStatus + return nil +} + +// Delete deletes the container status from disk atomically. +func (s *statusStorage) Delete() error { + temp := filepath.Dir(s.path) + ".del-" + filepath.Base(s.path) + if err := os.Rename(s.path, temp); err != nil && !os.IsNotExist(err) { + return err + } + return os.RemoveAll(temp) +} diff -Nru containerd-1.2.6/pkg/cri/store/container/status_test.go containerd-1.5.9/pkg/cri/store/container/status_test.go --- containerd-1.2.6/pkg/cri/store/container/status_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/container/status_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,195 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package container + +import ( + "encoding/json" + "errors" + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + assertlib "github.com/stretchr/testify/assert" + requirelib "github.com/stretchr/testify/require" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestContainerState(t *testing.T) { + for c, test := range map[string]struct { + status Status + state runtime.ContainerState + }{ + "unknown state": { + status: Status{ + Unknown: true, + }, + state: runtime.ContainerState_CONTAINER_UNKNOWN, + }, + "unknown state because there is no timestamp set": { + status: Status{}, + state: runtime.ContainerState_CONTAINER_UNKNOWN, + }, + "created state": { + status: Status{ + CreatedAt: time.Now().UnixNano(), + }, + state: runtime.ContainerState_CONTAINER_CREATED, + }, + "running state": { + status: Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + }, + state: runtime.ContainerState_CONTAINER_RUNNING, + }, + "exited state": { + status: Status{ + CreatedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + }, + state: runtime.ContainerState_CONTAINER_EXITED, + }, + } { + t.Logf("TestCase %q", c) + assertlib.Equal(t, test.state, test.status.State()) + } +} + +func TestStatusEncodeDecode(t *testing.T) { + s := &Status{ + Pid: 1234, + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + FinishedAt: time.Now().UnixNano(), + ExitCode: 1, + Reason: "test-reason", + Message: "test-message", + Removing: true, + Starting: true, + Unknown: true, + } + assert := assertlib.New(t) + data, err := s.encode() + assert.NoError(err) + newS := &Status{} + assert.NoError(newS.decode(data)) + s.Removing = false // Removing should not be encoded. + s.Starting = false // Starting should not be encoded. + s.Unknown = false // Unknown should not be encoded. + assert.Equal(s, newS) + + unsupported, err := json.Marshal(&versionedStatus{ + Version: "random-test-version", + Status: *s, + }) + assert.NoError(err) + assert.Error(newS.decode(unsupported)) +} + +func TestStatus(t *testing.T) { + testID := "test-id" + testStatus := Status{ + CreatedAt: time.Now().UnixNano(), + } + updateStatus := Status{ + CreatedAt: time.Now().UnixNano(), + StartedAt: time.Now().UnixNano(), + } + updateErr := errors.New("update error") + assert := assertlib.New(t) + require := requirelib.New(t) + + tempDir, err := ioutil.TempDir(os.TempDir(), "status-test") + require.NoError(err) + defer os.RemoveAll(tempDir) + statusFile := filepath.Join(tempDir, "status") + + t.Logf("simple store and get") + s, err := StoreStatus(tempDir, testID, testStatus) + assert.NoError(err) + old := s.Get() + assert.Equal(testStatus, old) + _, err = os.Stat(statusFile) + assert.NoError(err) + loaded, err := LoadStatus(tempDir, testID) + require.NoError(err) + assert.Equal(testStatus, loaded) + + t.Logf("failed update should not take effect") + err = s.Update(func(o Status) (Status, error) { + o = updateStatus + return o, updateErr + }) + assert.Equal(updateErr, err) + assert.Equal(testStatus, s.Get()) + loaded, err = LoadStatus(tempDir, testID) + require.NoError(err) + assert.Equal(testStatus, loaded) + + t.Logf("successful update should take effect but not checkpoint") + err = s.Update(func(o Status) (Status, error) { + o = updateStatus + return o, nil + }) + assert.NoError(err) + assert.Equal(updateStatus, s.Get()) + loaded, err = LoadStatus(tempDir, testID) + require.NoError(err) + assert.Equal(testStatus, loaded) + // Recover status. + assert.NoError(s.Update(func(o Status) (Status, error) { + o = testStatus + return o, nil + })) + + t.Logf("failed update sync should not take effect") + err = s.UpdateSync(func(o Status) (Status, error) { + o = updateStatus + return o, updateErr + }) + assert.Equal(updateErr, err) + assert.Equal(testStatus, s.Get()) + loaded, err = LoadStatus(tempDir, testID) + require.NoError(err) + assert.Equal(testStatus, loaded) + + t.Logf("successful update sync should take effect and checkpoint") + err = s.UpdateSync(func(o Status) (Status, error) { + o = updateStatus + return o, nil + }) + assert.NoError(err) + assert.Equal(updateStatus, s.Get()) + loaded, err = LoadStatus(tempDir, testID) + require.NoError(err) + assert.Equal(updateStatus, loaded) + + t.Logf("successful update should not affect existing snapshot") + assert.Equal(testStatus, old) + + t.Logf("delete status") + assert.NoError(s.Delete()) + _, err = LoadStatus(tempDir, testID) + assert.Error(err) + _, err = os.Stat(statusFile) + assert.True(os.IsNotExist(err)) + + t.Logf("delete status should be idempotent") + assert.NoError(s.Delete()) +} diff -Nru containerd-1.2.6/pkg/cri/store/errors.go containerd-1.5.9/pkg/cri/store/errors.go --- containerd-1.2.6/pkg/cri/store/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package store + +import "github.com/containerd/containerd/errdefs" + +var ( + // ErrAlreadyExist is the error returned when data added in the store + // already exists. + // + // This error has been DEPRECATED and will be removed in 1.5. Please switch + // usage directly to `errdefs.ErrAlreadyExists`. + ErrAlreadyExist = errdefs.ErrAlreadyExists + // ErrNotExist is the error returned when data is not in the store. + // + // This error has been DEPRECATED and will be removed in 1.5. Please switch + // usage directly to `errdefs.ErrNotFound`. + ErrNotExist = errdefs.ErrNotFound +) diff -Nru containerd-1.2.6/pkg/cri/store/errors_test.go containerd-1.5.9/pkg/cri/store/errors_test.go --- containerd-1.2.6/pkg/cri/store/errors_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/errors_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package store + +import ( + "testing" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/containerd/containerd/errdefs" +) + +func TestStoreErrAlreadyExistGRPCStatus(t *testing.T) { + err := errdefs.ToGRPC(ErrAlreadyExist) + s, ok := status.FromError(err) + if !ok { + t.Fatalf("failed to convert err: %v to status: %d", err, codes.AlreadyExists) + } + if s.Code() != codes.AlreadyExists { + t.Fatalf("expected code: %d got: %d", codes.AlreadyExists, s.Code()) + } +} + +func TestStoreErrNotExistGRPCStatus(t *testing.T) { + err := errdefs.ToGRPC(ErrNotExist) + s, ok := status.FromError(err) + if !ok { + t.Fatalf("failed to convert err: %v to status: %d", err, codes.NotFound) + } + if s.Code() != codes.NotFound { + t.Fatalf("expected code: %d got: %d", codes.NotFound, s.Code()) + } +} diff -Nru containerd-1.2.6/pkg/cri/store/image/fake_image.go containerd-1.5.9/pkg/cri/store/image/fake_image.go --- containerd-1.2.6/pkg/cri/store/image/fake_image.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/image/fake_image.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package image + +import "github.com/pkg/errors" + +// NewFakeStore returns an image store with predefined images. +// Update is not allowed for this fake store. +func NewFakeStore(images []Image) (*Store, error) { + s := NewStore(nil) + for _, i := range images { + for _, ref := range i.References { + s.refCache[ref] = i.ID + } + if err := s.store.add(i); err != nil { + return nil, errors.Wrapf(err, "add image %+v", i) + } + } + return s, nil +} diff -Nru containerd-1.2.6/pkg/cri/store/image/image.go containerd-1.5.9/pkg/cri/store/image/image.go --- containerd-1.2.6/pkg/cri/store/image/image.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/image/image.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,256 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package image + +import ( + "context" + "encoding/json" + "sync" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + imagedigest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest/digestset" + imageidentity "github.com/opencontainers/image-spec/identity" + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + + storeutil "github.com/containerd/containerd/pkg/cri/store" + "github.com/containerd/containerd/pkg/cri/util" +) + +// Image contains all resources associated with the image. All fields +// MUST not be mutated directly after created. +type Image struct { + // Id of the image. Normally the digest of image config. + ID string + // References are references to the image, e.g. RepoTag and RepoDigest. + References []string + // ChainID is the chainID of the image. + ChainID string + // Size is the compressed size of the image. + Size int64 + // ImageSpec is the oci image structure which describes basic information about the image. + ImageSpec imagespec.Image +} + +// Store stores all images. +type Store struct { + lock sync.RWMutex + // refCache is a containerd image reference to image id cache. + refCache map[string]string + // client is the containerd client. + client *containerd.Client + // store is the internal image store indexed by image id. + store *store +} + +// NewStore creates an image store. +func NewStore(client *containerd.Client) *Store { + return &Store{ + refCache: make(map[string]string), + client: client, + store: &store{ + images: make(map[string]Image), + digestSet: digestset.NewSet(), + }, + } +} + +// Update updates cache for a reference. +func (s *Store) Update(ctx context.Context, ref string) error { + s.lock.Lock() + defer s.lock.Unlock() + i, err := s.client.GetImage(ctx, ref) + if err != nil && !errdefs.IsNotFound(err) { + return errors.Wrap(err, "get image from containerd") + } + var img *Image + if err == nil { + img, err = getImage(ctx, i) + if err != nil { + return errors.Wrap(err, "get image info from containerd") + } + } + return s.update(ref, img) +} + +// update updates the internal cache. img == nil means that +// the image does not exist in containerd. +func (s *Store) update(ref string, img *Image) error { + oldID, oldExist := s.refCache[ref] + if img == nil { + // The image reference doesn't exist in containerd. + if oldExist { + // Remove the reference from the store. + s.store.delete(oldID, ref) + delete(s.refCache, ref) + } + return nil + } + if oldExist { + if oldID == img.ID { + return nil + } + // Updated. Remove tag from old image. + s.store.delete(oldID, ref) + } + // New image. Add new image. + s.refCache[ref] = img.ID + return s.store.add(*img) +} + +// getImage gets image information from containerd. +func getImage(ctx context.Context, i containerd.Image) (*Image, error) { + // Get image information. + diffIDs, err := i.RootFS(ctx) + if err != nil { + return nil, errors.Wrap(err, "get image diffIDs") + } + chainID := imageidentity.ChainID(diffIDs) + + size, err := i.Size(ctx) + if err != nil { + return nil, errors.Wrap(err, "get image compressed resource size") + } + + desc, err := i.Config(ctx) + if err != nil { + return nil, errors.Wrap(err, "get image config descriptor") + } + id := desc.Digest.String() + + rb, err := content.ReadBlob(ctx, i.ContentStore(), desc) + if err != nil { + return nil, errors.Wrap(err, "read image config from content store") + } + var ociimage imagespec.Image + if err := json.Unmarshal(rb, &ociimage); err != nil { + return nil, errors.Wrapf(err, "unmarshal image config %s", rb) + } + + return &Image{ + ID: id, + References: []string{i.Name()}, + ChainID: chainID.String(), + Size: size, + ImageSpec: ociimage, + }, nil +} + +// Resolve resolves a image reference to image id. +func (s *Store) Resolve(ref string) (string, error) { + s.lock.RLock() + defer s.lock.RUnlock() + id, ok := s.refCache[ref] + if !ok { + return "", storeutil.ErrNotExist + } + return id, nil +} + +// Get gets image metadata by image id. The id can be truncated. +// Returns various validation errors if the image id is invalid. +// Returns storeutil.ErrNotExist if the image doesn't exist. +func (s *Store) Get(id string) (Image, error) { + return s.store.get(id) +} + +// List lists all images. +func (s *Store) List() []Image { + return s.store.list() +} + +type store struct { + lock sync.RWMutex + images map[string]Image + digestSet *digestset.Set +} + +func (s *store) list() []Image { + s.lock.RLock() + defer s.lock.RUnlock() + var images []Image + for _, i := range s.images { + images = append(images, i) + } + return images +} + +func (s *store) add(img Image) error { + s.lock.Lock() + defer s.lock.Unlock() + if _, err := s.digestSet.Lookup(img.ID); err != nil { + if err != digestset.ErrDigestNotFound { + return err + } + if err := s.digestSet.Add(imagedigest.Digest(img.ID)); err != nil { + return err + } + } + + i, ok := s.images[img.ID] + if !ok { + // If the image doesn't exist, add it. + s.images[img.ID] = img + return nil + } + // Or else, merge and sort the references. + i.References = sortReferences(util.MergeStringSlices(i.References, img.References)) + s.images[img.ID] = i + return nil +} + +func (s *store) get(id string) (Image, error) { + s.lock.RLock() + defer s.lock.RUnlock() + digest, err := s.digestSet.Lookup(id) + if err != nil { + if err == digestset.ErrDigestNotFound { + err = storeutil.ErrNotExist + } + return Image{}, err + } + if i, ok := s.images[digest.String()]; ok { + return i, nil + } + return Image{}, storeutil.ErrNotExist +} + +func (s *store) delete(id, ref string) { + s.lock.Lock() + defer s.lock.Unlock() + digest, err := s.digestSet.Lookup(id) + if err != nil { + // Note: The idIndex.Delete and delete doesn't handle truncated index. + // So we need to return if there are error. + return + } + i, ok := s.images[digest.String()] + if !ok { + return + } + i.References = util.SubtractStringSlice(i.References, ref) + if len(i.References) != 0 { + s.images[digest.String()] = i + return + } + // Remove the image if it is not referenced any more. + s.digestSet.Remove(digest) // nolint: errcheck + delete(s.images, digest.String()) +} diff -Nru containerd-1.2.6/pkg/cri/store/image/image_test.go containerd-1.5.9/pkg/cri/store/image/image_test.go --- containerd-1.2.6/pkg/cri/store/image/image_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/image/image_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,248 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package image + +import ( + "sort" + "strings" + "testing" + + "github.com/opencontainers/go-digest/digestset" + assertlib "github.com/stretchr/testify/assert" + + storeutil "github.com/containerd/containerd/pkg/cri/store" +) + +func TestInternalStore(t *testing.T) { + images := []Image{ + { + ID: "sha256:1123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ChainID: "test-chain-id-1", + References: []string{"containerd.io/ref-1"}, + Size: 10, + }, + { + ID: "sha256:2123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ChainID: "test-chain-id-2abcd", + References: []string{"containerd.io/ref-2abcd"}, + Size: 20, + }, + { + ID: "sha256:3123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + References: []string{"containerd.io/ref-4a333"}, + ChainID: "test-chain-id-4a333", + Size: 30, + }, + { + ID: "sha256:4123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + References: []string{"containerd.io/ref-4abcd"}, + ChainID: "test-chain-id-4abcd", + Size: 40, + }, + } + assert := assertlib.New(t) + genTruncIndex := func(normalName string) string { return normalName[:(len(normalName)+1)/2] } + + s := &store{ + images: make(map[string]Image), + digestSet: digestset.NewSet(), + } + + t.Logf("should be able to add image") + for _, img := range images { + err := s.add(img) + assert.NoError(err) + } + + t.Logf("should be able to get image") + for _, v := range images { + truncID := genTruncIndex(v.ID) + got, err := s.get(truncID) + assert.NoError(err, "truncID:%s, fullID:%s", truncID, v.ID) + assert.Equal(v, got) + } + + t.Logf("should be able to get image by truncated imageId without algorithm") + for _, v := range images { + truncID := genTruncIndex(v.ID[strings.Index(v.ID, ":")+1:]) + got, err := s.get(truncID) + assert.NoError(err, "truncID:%s, fullID:%s", truncID, v.ID) + assert.Equal(v, got) + } + + t.Logf("should not be able to get image by ambiguous prefix") + ambiguousPrefixs := []string{"sha256", "sha256:"} + for _, v := range ambiguousPrefixs { + _, err := s.get(v) + assert.NotEqual(nil, err) + } + + t.Logf("should be able to list images") + imgs := s.list() + assert.Len(imgs, len(images)) + + imageNum := len(images) + for _, v := range images { + truncID := genTruncIndex(v.ID) + oldRef := v.References[0] + newRef := oldRef + "new" + + t.Logf("should be able to add new references") + newImg := v + newImg.References = []string{newRef} + err := s.add(newImg) + assert.NoError(err) + got, err := s.get(truncID) + assert.NoError(err) + assert.Len(got.References, 2) + assert.Contains(got.References, oldRef, newRef) + + t.Logf("should not be able to add duplicated references") + err = s.add(newImg) + assert.NoError(err) + got, err = s.get(truncID) + assert.NoError(err) + assert.Len(got.References, 2) + assert.Contains(got.References, oldRef, newRef) + + t.Logf("should be able to delete image references") + s.delete(truncID, oldRef) + got, err = s.get(truncID) + assert.NoError(err) + assert.Equal([]string{newRef}, got.References) + + t.Logf("should be able to delete image") + s.delete(truncID, newRef) + got, err = s.get(truncID) + assert.Equal(storeutil.ErrNotExist, err) + assert.Equal(Image{}, got) + + imageNum-- + imgs = s.list() + assert.Len(imgs, imageNum) + } +} + +func TestImageStore(t *testing.T) { + id := "sha256:1123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + newID := "sha256:9923456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + image := Image{ + ID: id, + ChainID: "test-chain-id-1", + References: []string{"containerd.io/ref-1"}, + Size: 10, + } + assert := assertlib.New(t) + + equal := func(i1, i2 Image) { + sort.Strings(i1.References) + sort.Strings(i2.References) + assert.Equal(i1, i2) + } + for desc, test := range map[string]struct { + ref string + image *Image + expected []Image + }{ + "nothing should happen if a non-exist ref disappear": { + ref: "containerd.io/ref-2", + image: nil, + expected: []Image{image}, + }, + "new ref for an existing image": { + ref: "containerd.io/ref-2", + image: &Image{ + ID: id, + ChainID: "test-chain-id-1", + References: []string{"containerd.io/ref-2"}, + Size: 10, + }, + expected: []Image{ + { + ID: id, + ChainID: "test-chain-id-1", + References: []string{"containerd.io/ref-1", "containerd.io/ref-2"}, + Size: 10, + }, + }, + }, + "new ref for a new image": { + ref: "containerd.io/ref-2", + image: &Image{ + ID: newID, + ChainID: "test-chain-id-2", + References: []string{"containerd.io/ref-2"}, + Size: 20, + }, + expected: []Image{ + image, + { + ID: newID, + ChainID: "test-chain-id-2", + References: []string{"containerd.io/ref-2"}, + Size: 20, + }, + }, + }, + "existing ref point to a new image": { + ref: "containerd.io/ref-1", + image: &Image{ + ID: newID, + ChainID: "test-chain-id-2", + References: []string{"containerd.io/ref-1"}, + Size: 20, + }, + expected: []Image{ + { + ID: newID, + ChainID: "test-chain-id-2", + References: []string{"containerd.io/ref-1"}, + Size: 20, + }, + }, + }, + "existing ref disappear": { + ref: "containerd.io/ref-1", + image: nil, + expected: []Image{}, + }, + } { + t.Logf("TestCase %q", desc) + s, err := NewFakeStore([]Image{image}) + assert.NoError(err) + assert.NoError(s.update(test.ref, test.image)) + + assert.Len(s.List(), len(test.expected)) + for _, expect := range test.expected { + got, err := s.Get(expect.ID) + assert.NoError(err) + equal(got, expect) + for _, ref := range expect.References { + id, err := s.Resolve(ref) + assert.NoError(err) + assert.Equal(expect.ID, id) + } + } + + if test.image == nil { + // Shouldn't be able to index by removed ref. + id, err := s.Resolve(test.ref) + assert.Equal(storeutil.ErrNotExist, err) + assert.Empty(id) + } + } +} diff -Nru containerd-1.2.6/pkg/cri/store/image/sort.go containerd-1.5.9/pkg/cri/store/image/sort.go --- containerd-1.2.6/pkg/cri/store/image/sort.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/image/sort.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,75 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package image + +import ( + "sort" + + "github.com/containerd/containerd/reference/docker" +) + +// sortReferences sorts references by refRank then string comparison +func sortReferences(references []string) []string { + var prefs []docker.Reference + var bad []string + + for _, ref := range references { + pref, err := docker.ParseAnyReference(ref) + if err != nil { + bad = append(bad, ref) + } else { + prefs = append(prefs, pref) + } + } + sort.Slice(prefs, func(a, b int) bool { + ar := refRank(prefs[a]) + br := refRank(prefs[b]) + if ar == br { + return prefs[a].String() < prefs[b].String() + } + return ar < br + }) + sort.Strings(bad) + var refs []string + for _, pref := range prefs { + refs = append(refs, pref.String()) + } + return append(refs, bad...) +} + +// refRank ranks precedence for reference type, preferring higher information references +// 1. Name + Tag + Digest +// 2. Name + Tag +// 3. Name + Digest +// 4. Name +// 5. Digest +// 6. Parse error +func refRank(ref docker.Reference) uint8 { + if _, ok := ref.(docker.Named); ok { + if _, ok = ref.(docker.Tagged); ok { + if _, ok = ref.(docker.Digested); ok { + return 1 + } + return 2 + } + if _, ok = ref.(docker.Digested); ok { + return 3 + } + return 4 + } + return 5 +} diff -Nru containerd-1.2.6/pkg/cri/store/image/sort_test.go containerd-1.5.9/pkg/cri/store/image/sort_test.go --- containerd-1.2.6/pkg/cri/store/image/sort_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/image/sort_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package image + +import ( + "io" + "io/ioutil" + "math/rand" + "testing" + + "github.com/opencontainers/go-digest" +) + +func TestReferenceSorting(t *testing.T) { + digested := func(seed int64) string { + b, err := ioutil.ReadAll(io.LimitReader(rand.New(rand.NewSource(seed)), 64)) + if err != nil { + panic(err) + } + return digest.FromBytes(b).String() + } + // Add z. prefix to string sort after "sha256:" + r1 := func(name, tag string, seed int64) string { + return "z.containerd.io/" + name + ":" + tag + "@" + digested(seed) + } + r2 := func(name, tag string) string { + return "z.containerd.io/" + name + ":" + tag + } + r3 := func(name string, seed int64) string { + return "z.containerd.io/" + name + "@" + digested(seed) + } + + for i, tc := range []struct { + unsorted []string + expected []string + }{ + { + unsorted: []string{r2("name", "latest"), r3("name", 1), r1("name", "latest", 1)}, + expected: []string{r1("name", "latest", 1), r2("name", "latest"), r3("name", 1)}, + }, + { + unsorted: []string{"can't parse this:latest", r3("name", 1), r2("name", "latest")}, + expected: []string{r2("name", "latest"), r3("name", 1), "can't parse this:latest"}, + }, + { + unsorted: []string{digested(1), r3("name", 1), r2("name", "latest")}, + expected: []string{r2("name", "latest"), r3("name", 1), digested(1)}, + }, + { + unsorted: []string{r2("name", "tag2"), r2("name", "tag3"), r2("name", "tag1")}, + expected: []string{r2("name", "tag1"), r2("name", "tag2"), r2("name", "tag3")}, + }, + { + unsorted: []string{r2("name-2", "tag"), r2("name-3", "tag"), r2("name-1", "tag")}, + expected: []string{r2("name-1", "tag"), r2("name-2", "tag"), r2("name-3", "tag")}, + }, + } { + sorted := sortReferences(tc.unsorted) + if len(sorted) != len(tc.expected) { + t.Errorf("[%d]: Mismatched sized, got %d, expected %d", i, len(sorted), len(tc.expected)) + continue + } + for j := range sorted { + if sorted[j] != tc.expected[j] { + t.Errorf("[%d]: Wrong value at %d, got %q, expected %q", i, j, sorted[j], tc.expected[j]) + break + } + } + } +} diff -Nru containerd-1.2.6/pkg/cri/store/label/label.go containerd-1.5.9/pkg/cri/store/label/label.go --- containerd-1.2.6/pkg/cri/store/label/label.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/label/label.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,97 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package label + +import ( + "sync" + + "github.com/opencontainers/selinux/go-selinux" +) + +// Store is used to store SELinux process labels +type Store struct { + sync.Mutex + levels map[string]int + Releaser func(string) + Reserver func(string) +} + +// NewStore creates a new SELinux process label store +func NewStore() *Store { + return &Store{ + levels: map[string]int{}, + Releaser: selinux.ReleaseLabel, + Reserver: selinux.ReserveLabel, + } +} + +// Reserve reserves the MLS/MCS level component of the specified label +// and prevents multiple reserves for the same level +func (s *Store) Reserve(label string) error { + s.Lock() + defer s.Unlock() + + context, err := selinux.NewContext(label) + if err != nil { + return err + } + + level := context["level"] + // no reason to count empty + if level == "" { + return nil + } + + if _, ok := s.levels[level]; !ok { + s.Reserver(label) + } + + s.levels[level]++ + return nil +} + +// Release un-reserves the MLS/MCS level component of the specified label, +// allowing it to be used by another process once labels with the same +// level have been released. +func (s *Store) Release(label string) { + s.Lock() + defer s.Unlock() + + context, err := selinux.NewContext(label) + if err != nil { + return + } + + level := context["level"] + if level == "" { + return + } + + count, ok := s.levels[level] + if !ok { + return + } + switch { + case count == 1: + s.Releaser(label) + delete(s.levels, level) + case count < 1: + delete(s.levels, level) + case count > 1: + s.levels[level] = count - 1 + } +} diff -Nru containerd-1.2.6/pkg/cri/store/label/label_test.go containerd-1.5.9/pkg/cri/store/label/label_test.go --- containerd-1.2.6/pkg/cri/store/label/label_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/label/label_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,116 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package label + +import ( + "testing" + + "github.com/opencontainers/selinux/go-selinux" + "github.com/stretchr/testify/assert" +) + +func TestAddThenRemove(t *testing.T) { + if !selinux.GetEnabled() { + t.Skip("selinux is not enabled") + } + + assert := assert.New(t) + store := NewStore() + releaseCount := 0 + reserveCount := 0 + store.Releaser = func(label string) { + assert.Contains(label, ":c1,c2") + releaseCount++ + assert.Equal(1, releaseCount) + } + store.Reserver = func(label string) { + assert.Contains(label, ":c1,c2") + reserveCount++ + assert.Equal(1, reserveCount) + } + + t.Log("should count to two level") + assert.NoError(store.Reserve("junk:junk:junk:c1,c2")) + assert.NoError(store.Reserve("junk2:junk2:junk2:c1,c2")) + + t.Log("should have one item") + assert.Equal(1, len(store.levels)) + + t.Log("c1,c2 count should be 2") + assert.Equal(2, store.levels["c1,c2"]) + + store.Release("junk:junk:junk:c1,c2") + store.Release("junk2:junk2:junk2:c1,c2") + + t.Log("should have 0 items") + assert.Equal(0, len(store.levels)) + + t.Log("should have reserved") + assert.Equal(1, reserveCount) + + t.Log("should have released") + assert.Equal(1, releaseCount) +} + +func TestJunkData(t *testing.T) { + if !selinux.GetEnabled() { + t.Skip("selinux is not enabled") + } + + assert := assert.New(t) + store := NewStore() + releaseCount := 0 + store.Releaser = func(label string) { + releaseCount++ + } + reserveCount := 0 + store.Reserver = func(label string) { + reserveCount++ + } + + t.Log("should ignore empty label") + assert.NoError(store.Reserve("")) + assert.Equal(0, len(store.levels)) + store.Release("") + assert.Equal(0, len(store.levels)) + assert.Equal(0, releaseCount) + assert.Equal(0, reserveCount) + + t.Log("should fail on bad label") + assert.Error(store.Reserve("junkjunkjunkc1c2")) + assert.Equal(0, len(store.levels)) + store.Release("junkjunkjunkc1c2") + assert.Equal(0, len(store.levels)) + assert.Equal(0, releaseCount) + assert.Equal(0, reserveCount) + + t.Log("should not release unknown label") + store.Release("junk2:junk2:junk2:c1,c2") + assert.Equal(0, len(store.levels)) + assert.Equal(0, releaseCount) + assert.Equal(0, reserveCount) + + t.Log("should release once even if too many deletes") + assert.NoError(store.Reserve("junk2:junk2:junk2:c1,c2")) + assert.Equal(1, len(store.levels)) + assert.Equal(1, store.levels["c1,c2"]) + store.Release("junk2:junk2:junk2:c1,c2") + store.Release("junk2:junk2:junk2:c1,c2") + assert.Equal(0, len(store.levels)) + assert.Equal(1, releaseCount) + assert.Equal(1, reserveCount) +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/metadata.go containerd-1.5.9/pkg/cri/store/sandbox/metadata.go --- containerd-1.2.6/pkg/cri/store/sandbox/metadata.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/metadata.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "encoding/json" + + cni "github.com/containerd/go-cni" + "github.com/pkg/errors" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// NOTE(random-liu): +// 1) Metadata is immutable after created. +// 2) Metadata is checkpointed as containerd container label. + +// metadataVersion is current version of sandbox metadata. +const metadataVersion = "v1" // nolint + +// versionedMetadata is the internal versioned sandbox metadata. +// nolint +type versionedMetadata struct { + // Version indicates the version of the versioned sandbox metadata. + Version string + // Metadata's type is metadataInternal. If not there will be a recursive call in MarshalJSON. + Metadata metadataInternal +} + +// metadataInternal is for internal use. +type metadataInternal Metadata + +// Metadata is the unversioned sandbox metadata. +type Metadata struct { + // ID is the sandbox id. + ID string + // Name is the sandbox name. + Name string + // Config is the CRI sandbox config. + Config *runtime.PodSandboxConfig + // NetNSPath is the network namespace used by the sandbox. + NetNSPath string + // IP of Pod if it is attached to non host network + IP string + // AdditionalIPs of the Pod if it is attached to non host network + AdditionalIPs []string + // RuntimeHandler is the runtime handler name of the pod. + RuntimeHandler string + // CNIresult resulting configuration for attached network namespace interfaces + CNIResult *cni.Result + // ProcessLabel is the SELinux process label for the container + ProcessLabel string +} + +// MarshalJSON encodes Metadata into bytes in json format. +func (c *Metadata) MarshalJSON() ([]byte, error) { + return json.Marshal(&versionedMetadata{ + Version: metadataVersion, + Metadata: metadataInternal(*c), + }) +} + +// UnmarshalJSON decodes Metadata from bytes. +func (c *Metadata) UnmarshalJSON(data []byte) error { + versioned := &versionedMetadata{} + if err := json.Unmarshal(data, versioned); err != nil { + return err + } + // Handle old version after upgrade. + switch versioned.Version { + case metadataVersion: + *c = Metadata(versioned.Metadata) + return nil + } + return errors.Errorf("unsupported version: %q", versioned.Version) +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/metadata_test.go containerd-1.5.9/pkg/cri/store/sandbox/metadata_test.go --- containerd-1.2.6/pkg/cri/store/sandbox/metadata_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/metadata_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,79 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "encoding/json" + "testing" + + assertlib "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +func TestMetadataMarshalUnmarshal(t *testing.T) { + meta := &Metadata{ + ID: "test-id", + Name: "test-name", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "test-name", + Uid: "test-uid", + Namespace: "test-namespace", + Attempt: 1, + }, + }, + } + assert := assertlib.New(t) + newMeta := &Metadata{} + newVerMeta := &versionedMetadata{} + + t.Logf("should be able to do json.marshal") + data, err := json.Marshal(meta) + assert.NoError(err) + data1, err := json.Marshal(&versionedMetadata{ + Version: metadataVersion, + Metadata: metadataInternal(*meta), + }) + assert.NoError(err) + assert.Equal(data, data1) + + t.Logf("should be able to do MarshalJSON") + data, err = meta.MarshalJSON() + assert.NoError(err) + assert.NoError(newMeta.UnmarshalJSON(data)) + assert.Equal(meta, newMeta) + + t.Logf("should be able to do MarshalJSON and json.Unmarshal") + data, err = meta.MarshalJSON() + assert.NoError(err) + assert.NoError(json.Unmarshal(data, newVerMeta)) + assert.Equal(meta, (*Metadata)(&newVerMeta.Metadata)) + + t.Logf("should be able to do json.Marshal and UnmarshalJSON") + data, err = json.Marshal(meta) + assert.NoError(err) + assert.NoError(newMeta.UnmarshalJSON(data)) + assert.Equal(meta, newMeta) + + t.Logf("should json.Unmarshal fail for unsupported version") + unsupported, err := json.Marshal(&versionedMetadata{ + Version: "random-test-version", + Metadata: metadataInternal(*meta), + }) + assert.NoError(err) + assert.Error(json.Unmarshal(unsupported, &newMeta)) +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/sandbox.go containerd-1.5.9/pkg/cri/store/sandbox/sandbox.go --- containerd-1.2.6/pkg/cri/store/sandbox/sandbox.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/sandbox.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,137 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "sync" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/pkg/cri/store/label" + "github.com/containerd/containerd/pkg/cri/store/truncindex" + + "github.com/containerd/containerd/pkg/cri/store" + "github.com/containerd/containerd/pkg/netns" +) + +// Sandbox contains all resources associated with the sandbox. All methods to +// mutate the internal state are thread safe. +type Sandbox struct { + // Metadata is the metadata of the sandbox, it is immutable after created. + Metadata + // Status stores the status of the sandbox. + Status StatusStorage + // Container is the containerd sandbox container client. + Container containerd.Container + // CNI network namespace client. + // For hostnetwork pod, this is always nil; + // For non hostnetwork pod, this should never be nil. + NetNS *netns.NetNS + // StopCh is used to propagate the stop information of the sandbox. + *store.StopCh +} + +// NewSandbox creates an internally used sandbox type. This functions reminds +// the caller that a sandbox must have a status. +func NewSandbox(metadata Metadata, status Status) Sandbox { + s := Sandbox{ + Metadata: metadata, + Status: StoreStatus(status), + StopCh: store.NewStopCh(), + } + if status.State == StateNotReady { + s.Stop() + } + return s +} + +// Store stores all sandboxes. +type Store struct { + lock sync.RWMutex + sandboxes map[string]Sandbox + idIndex *truncindex.TruncIndex + labels *label.Store +} + +// NewStore creates a sandbox store. +func NewStore(labels *label.Store) *Store { + return &Store{ + sandboxes: make(map[string]Sandbox), + idIndex: truncindex.NewTruncIndex([]string{}), + labels: labels, + } +} + +// Add a sandbox into the store. +func (s *Store) Add(sb Sandbox) error { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.sandboxes[sb.ID]; ok { + return store.ErrAlreadyExist + } + if err := s.labels.Reserve(sb.ProcessLabel); err != nil { + return err + } + if err := s.idIndex.Add(sb.ID); err != nil { + return err + } + s.sandboxes[sb.ID] = sb + return nil +} + +// Get returns the sandbox with specified id. +// Returns store.ErrNotExist if the sandbox doesn't exist. +func (s *Store) Get(id string) (Sandbox, error) { + s.lock.RLock() + defer s.lock.RUnlock() + id, err := s.idIndex.Get(id) + if err != nil { + if err == truncindex.ErrNotExist { + err = store.ErrNotExist + } + return Sandbox{}, err + } + if sb, ok := s.sandboxes[id]; ok { + return sb, nil + } + return Sandbox{}, store.ErrNotExist +} + +// List lists all sandboxes. +func (s *Store) List() []Sandbox { + s.lock.RLock() + defer s.lock.RUnlock() + var sandboxes []Sandbox + for _, sb := range s.sandboxes { + sandboxes = append(sandboxes, sb) + } + return sandboxes +} + +// Delete deletes the sandbox with specified id. +func (s *Store) Delete(id string) { + s.lock.Lock() + defer s.lock.Unlock() + id, err := s.idIndex.Get(id) + if err != nil { + // Note: The idIndex.Delete and delete doesn't handle truncated index. + // So we need to return if there are error. + return + } + s.labels.Release(s.sandboxes[id].ProcessLabel) + s.idIndex.Delete(id) // nolint: errcheck + delete(s.sandboxes, id) +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/sandbox_test.go containerd-1.5.9/pkg/cri/store/sandbox/sandbox_test.go --- containerd-1.2.6/pkg/cri/store/sandbox/sandbox_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/sandbox_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,156 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "testing" + + "github.com/containerd/containerd/pkg/cri/store/label" + assertlib "github.com/stretchr/testify/assert" + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/store" +) + +func TestSandboxStore(t *testing.T) { + sandboxes := map[string]Sandbox{ + "1": NewSandbox( + Metadata{ + ID: "1", + Name: "Sandbox-1", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "TestPod-1", + Uid: "TestUid-1", + Namespace: "TestNamespace-1", + Attempt: 1, + }, + }, + NetNSPath: "TestNetNS-1", + }, + Status{State: StateReady}, + ), + "2abcd": NewSandbox( + Metadata{ + ID: "2abcd", + Name: "Sandbox-2abcd", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "TestPod-2abcd", + Uid: "TestUid-2abcd", + Namespace: "TestNamespace-2abcd", + Attempt: 2, + }, + }, + NetNSPath: "TestNetNS-2", + }, + Status{State: StateNotReady}, + ), + "4a333": NewSandbox( + Metadata{ + ID: "4a333", + Name: "Sandbox-4a333", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "TestPod-4a333", + Uid: "TestUid-4a333", + Namespace: "TestNamespace-4a333", + Attempt: 3, + }, + }, + NetNSPath: "TestNetNS-3", + }, + Status{State: StateNotReady}, + ), + "4abcd": NewSandbox( + Metadata{ + ID: "4abcd", + Name: "Sandbox-4abcd", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "TestPod-4abcd", + Uid: "TestUid-4abcd", + Namespace: "TestNamespace-4abcd", + Attempt: 1, + }, + }, + NetNSPath: "TestNetNS-4abcd", + }, + Status{State: StateReady}, + ), + } + unknown := NewSandbox( + Metadata{ + ID: "3defg", + Name: "Sandbox-3defg", + Config: &runtime.PodSandboxConfig{ + Metadata: &runtime.PodSandboxMetadata{ + Name: "TestPod-3defg", + Uid: "TestUid-3defg", + Namespace: "TestNamespace-3defg", + Attempt: 1, + }, + }, + NetNSPath: "TestNetNS-3defg", + }, + Status{State: StateUnknown}, + ) + assert := assertlib.New(t) + s := NewStore(label.NewStore()) + + t.Logf("should be able to add sandbox") + for _, sb := range sandboxes { + assert.NoError(s.Add(sb)) + } + assert.NoError(s.Add(unknown)) + + t.Logf("should be able to get sandbox") + genTruncIndex := func(normalName string) string { return normalName[:(len(normalName)+1)/2] } + for id, sb := range sandboxes { + got, err := s.Get(genTruncIndex(id)) + assert.NoError(err) + assert.Equal(sb, got) + } + + t.Logf("should be able to get sandbox in unknown state with Get") + got, err := s.Get(unknown.ID) + assert.NoError(err) + assert.Equal(unknown, got) + + t.Logf("should be able to list sandboxes") + sbNum := len(sandboxes) + 1 + sbs := s.List() + assert.Len(sbs, sbNum) + + for testID, v := range sandboxes { + truncID := genTruncIndex(testID) + + t.Logf("add should return already exists error for duplicated sandbox") + assert.Equal(store.ErrAlreadyExist, s.Add(v)) + + t.Logf("should be able to delete sandbox") + s.Delete(truncID) + sbNum-- + sbs = s.List() + assert.Len(sbs, sbNum) + + t.Logf("get should return not exist error after deletion") + sb, err := s.Get(truncID) + assert.Equal(Sandbox{}, sb) + assert.Equal(store.ErrNotExist, err) + } +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/status.go containerd-1.5.9/pkg/cri/store/sandbox/status.go --- containerd-1.2.6/pkg/cri/store/sandbox/status.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/status.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,151 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "strconv" + "sync" + "time" + + runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// The sandbox state machine in the CRI plugin: +// + + +// | | +// | Create(Run) | Load +// | | +// Start | | +// (failed) | | +// +------------------+ +-----------+ +// | | | | +// | | | | +// | | | | +// | | Start(Run) | | +// | | | | +// | PortForward +----v----+ | | +// | +------+ | | | +// | | | READY <---------+ | +// | +------> | | | +// | +----+----+ | | +// | | | | +// | | Stop/Exit | | +// | | | | +// | +----v----+ | | +// | | <---------+ +----v----+ +// | | NOTREADY| | | +// | | <----------------+ UNKNOWN | +// | +----+----+ Stop | | +// | | +---------+ +// | | Remove +// | v +// +-------------> DELETED + +// State is the sandbox state we use in containerd/cri. +// It includes unknown, which is internal states not defined in CRI. +// The state mapping from internal states to CRI states: +// * ready -> ready +// * not ready -> not ready +// * unknown -> not ready +type State uint32 + +const ( + // StateReady is ready state, it means sandbox container + // is running. + StateReady State = iota + // StateNotReady is notready state, it ONLY means sandbox + // container is not running. + // StopPodSandbox should still be called for NOTREADY sandbox to + // cleanup resources other than sandbox container, e.g. network namespace. + // This is an assumption made in CRI. + StateNotReady + // StateUnknown is unknown state. Sandbox only goes + // into unknown state when its status fails to be loaded. + StateUnknown +) + +// String returns the string representation of the state +func (s State) String() string { + switch s { + case StateReady: + return runtime.PodSandboxState_SANDBOX_READY.String() + case StateNotReady: + return runtime.PodSandboxState_SANDBOX_NOTREADY.String() + case StateUnknown: + // PodSandboxState doesn't have an unknown state, but State does, so return a string using the same convention + return "SANDBOX_UNKNOWN" + default: + return "invalid sandbox state value: " + strconv.Itoa(int(s)) + } +} + +// Status is the status of a sandbox. +type Status struct { + // Pid is the init process id of the sandbox container. + Pid uint32 + // CreatedAt is the created timestamp. + CreatedAt time.Time + // State is the state of the sandbox. + State State +} + +// UpdateFunc is function used to update the sandbox status. If there +// is an error, the update will be rolled back. +type UpdateFunc func(Status) (Status, error) + +// StatusStorage manages the sandbox status. +// The status storage for sandbox is different from container status storage, +// because we don't checkpoint sandbox status. If we need checkpoint in the +// future, we should combine this with container status storage. +type StatusStorage interface { + // Get a sandbox status. + Get() Status + // Update the sandbox status. Note that the update MUST be applied + // in one transaction. + Update(UpdateFunc) error +} + +// StoreStatus creates the storage containing the passed in sandbox status with the +// specified id. +// The status MUST be created in one transaction. +func StoreStatus(status Status) StatusStorage { + return &statusStorage{status: status} +} + +type statusStorage struct { + sync.RWMutex + status Status +} + +// Get a copy of sandbox status. +func (s *statusStorage) Get() Status { + s.RLock() + defer s.RUnlock() + return s.status +} + +// Update the sandbox status. +func (s *statusStorage) Update(u UpdateFunc) error { + s.Lock() + defer s.Unlock() + newStatus, err := u(s.status) + if err != nil { + return err + } + s.status = newStatus + return nil +} diff -Nru containerd-1.2.6/pkg/cri/store/sandbox/status_test.go containerd-1.5.9/pkg/cri/store/sandbox/status_test.go --- containerd-1.2.6/pkg/cri/store/sandbox/status_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/sandbox/status_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,69 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sandbox + +import ( + "errors" + "testing" + "time" + + assertlib "github.com/stretchr/testify/assert" +) + +func TestStatus(t *testing.T) { + testStatus := Status{ + Pid: 123, + CreatedAt: time.Now(), + State: StateUnknown, + } + updateStatus := Status{ + Pid: 456, + CreatedAt: time.Now(), + State: StateReady, + } + updateErr := errors.New("update error") + assert := assertlib.New(t) + + t.Logf("simple store and get") + s := StoreStatus(testStatus) + old := s.Get() + assert.Equal(testStatus, old) + + t.Logf("failed update should not take effect") + err := s.Update(func(o Status) (Status, error) { + o = updateStatus + return o, updateErr + }) + assert.Equal(updateErr, err) + assert.Equal(testStatus, s.Get()) + + t.Logf("successful update should take effect but not checkpoint") + err = s.Update(func(o Status) (Status, error) { + o = updateStatus + return o, nil + }) + assert.NoError(err) + assert.Equal(updateStatus, s.Get()) +} + +func TestStateStringConversion(t *testing.T) { + assert := assertlib.New(t) + assert.Equal("SANDBOX_READY", StateReady.String()) + assert.Equal("SANDBOX_NOTREADY", StateNotReady.String()) + assert.Equal("SANDBOX_UNKNOWN", StateUnknown.String()) + assert.Equal("invalid sandbox state value: 123", State(123).String()) +} diff -Nru containerd-1.2.6/pkg/cri/store/snapshot/snapshot.go containerd-1.5.9/pkg/cri/store/snapshot/snapshot.go --- containerd-1.2.6/pkg/cri/store/snapshot/snapshot.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/snapshot/snapshot.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,87 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package snapshot + +import ( + "sync" + + snapshot "github.com/containerd/containerd/snapshots" + + "github.com/containerd/containerd/pkg/cri/store" +) + +// Snapshot contains the information about the snapshot. +type Snapshot struct { + // Key is the key of the snapshot + Key string + // Kind is the kind of the snapshot (active, committed, view) + Kind snapshot.Kind + // Size is the size of the snapshot in bytes. + Size uint64 + // Inodes is the number of inodes used by the snapshot + Inodes uint64 + // Timestamp is latest update time (in nanoseconds) of the snapshot + // information. + Timestamp int64 +} + +// Store stores all snapshots. +type Store struct { + lock sync.RWMutex + snapshots map[string]Snapshot +} + +// NewStore creates a snapshot store. +func NewStore() *Store { + return &Store{snapshots: make(map[string]Snapshot)} +} + +// Add a snapshot into the store. +func (s *Store) Add(snapshot Snapshot) { + s.lock.Lock() + defer s.lock.Unlock() + s.snapshots[snapshot.Key] = snapshot +} + +// Get returns the snapshot with specified key. Returns store.ErrNotExist if the +// snapshot doesn't exist. +func (s *Store) Get(key string) (Snapshot, error) { + s.lock.RLock() + defer s.lock.RUnlock() + if sn, ok := s.snapshots[key]; ok { + return sn, nil + } + return Snapshot{}, store.ErrNotExist +} + +// List lists all snapshots. +func (s *Store) List() []Snapshot { + s.lock.RLock() + defer s.lock.RUnlock() + var snapshots []Snapshot + for _, sn := range s.snapshots { + snapshots = append(snapshots, sn) + } + return snapshots +} + +// Delete deletes the snapshot with specified key. +func (s *Store) Delete(key string) { + s.lock.Lock() + defer s.lock.Unlock() + delete(s.snapshots, key) +} diff -Nru containerd-1.2.6/pkg/cri/store/snapshot/snapshot_test.go containerd-1.5.9/pkg/cri/store/snapshot/snapshot_test.go --- containerd-1.2.6/pkg/cri/store/snapshot/snapshot_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/snapshot/snapshot_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package snapshot + +import ( + "testing" + "time" + + snapshot "github.com/containerd/containerd/snapshots" + assertlib "github.com/stretchr/testify/assert" + + "github.com/containerd/containerd/pkg/cri/store" +) + +func TestSnapshotStore(t *testing.T) { + snapshots := map[string]Snapshot{ + "key1": { + Key: "key1", + Kind: snapshot.KindActive, + Size: 10, + Inodes: 100, + Timestamp: time.Now().UnixNano(), + }, + "key2": { + Key: "key2", + Kind: snapshot.KindCommitted, + Size: 20, + Inodes: 200, + Timestamp: time.Now().UnixNano(), + }, + "key3": { + Key: "key3", + Kind: snapshot.KindView, + Size: 0, + Inodes: 0, + Timestamp: time.Now().UnixNano(), + }, + } + assert := assertlib.New(t) + + s := NewStore() + + t.Logf("should be able to add snapshot") + for _, sn := range snapshots { + s.Add(sn) + } + + t.Logf("should be able to get snapshot") + for id, sn := range snapshots { + got, err := s.Get(id) + assert.NoError(err) + assert.Equal(sn, got) + } + + t.Logf("should be able to list snapshot") + sns := s.List() + assert.Len(sns, 3) + + testKey := "key2" + + t.Logf("should be able to delete snapshot") + s.Delete(testKey) + sns = s.List() + assert.Len(sns, 2) + + t.Logf("get should return empty struct and ErrNotExist after deletion") + sn, err := s.Get(testKey) + assert.Equal(Snapshot{}, sn) + assert.Equal(store.ErrNotExist, err) +} diff -Nru containerd-1.2.6/pkg/cri/store/truncindex/truncindex.go containerd-1.5.9/pkg/cri/store/truncindex/truncindex.go --- containerd-1.2.6/pkg/cri/store/truncindex/truncindex.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/truncindex/truncindex.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,157 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// This file is a copy of moby/moby/pkg/truncindex/truncindex.go + +// Package truncindex provides a general 'index tree', used by Docker +// in order to be able to reference containers by only a few unambiguous +// characters of their id. +package truncindex + +import ( + "errors" + "fmt" + "strings" + "sync" + + "github.com/tchap/go-patricia/patricia" +) + +var ( + // ErrEmptyPrefix is an error returned if the prefix was empty. + ErrEmptyPrefix = errors.New("Prefix can't be empty") + + // ErrIllegalChar is returned when a space is in the ID + ErrIllegalChar = errors.New("illegal character: ' '") + + // ErrNotExist is returned when ID or its prefix not found in index. + ErrNotExist = errors.New("ID does not exist") +) + +// ErrAmbiguousPrefix is returned if the prefix was ambiguous +// (multiple ids for the prefix). +type ErrAmbiguousPrefix struct { + prefix string +} + +func (e ErrAmbiguousPrefix) Error() string { + return fmt.Sprintf("Multiple IDs found with provided prefix: %s", e.prefix) +} + +// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes. +// This is used to retrieve image and container IDs by more convenient shorthand prefixes. +type TruncIndex struct { + sync.RWMutex + trie *patricia.Trie + ids map[string]struct{} +} + +// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs. +func NewTruncIndex(ids []string) (idx *TruncIndex) { + idx = &TruncIndex{ + ids: make(map[string]struct{}), + + // Change patricia max prefix per node length, + // because our len(ID) always 64 + trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)), + } + for _, id := range ids { + idx.addID(id) + } + return +} + +func (idx *TruncIndex) addID(id string) error { + if strings.Contains(id, " ") { + return ErrIllegalChar + } + if id == "" { + return ErrEmptyPrefix + } + if _, exists := idx.ids[id]; exists { + return fmt.Errorf("id already exists: '%s'", id) + } + idx.ids[id] = struct{}{} + if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted { + return fmt.Errorf("failed to insert id: %s", id) + } + return nil +} + +// Add adds a new ID to the TruncIndex. +func (idx *TruncIndex) Add(id string) error { + idx.Lock() + defer idx.Unlock() + return idx.addID(id) +} + +// Delete removes an ID from the TruncIndex. If there are multiple IDs +// with the given prefix, an error is thrown. +func (idx *TruncIndex) Delete(id string) error { + idx.Lock() + defer idx.Unlock() + if _, exists := idx.ids[id]; !exists || id == "" { + return fmt.Errorf("no such id: '%s'", id) + } + delete(idx.ids, id) + if deleted := idx.trie.Delete(patricia.Prefix(id)); !deleted { + return fmt.Errorf("no such id: '%s'", id) + } + return nil +} + +// Get retrieves an ID from the TruncIndex. If there are multiple IDs +// with the given prefix, an error is thrown. +func (idx *TruncIndex) Get(s string) (string, error) { + if s == "" { + return "", ErrEmptyPrefix + } + var ( + id string + ) + subTreeVisitFunc := func(prefix patricia.Prefix, item patricia.Item) error { + if id != "" { + // we haven't found the ID if there are two or more IDs + id = "" + return ErrAmbiguousPrefix{prefix: s} + } + id = string(prefix) + return nil + } + + idx.RLock() + defer idx.RUnlock() + if err := idx.trie.VisitSubtree(patricia.Prefix(s), subTreeVisitFunc); err != nil { + return "", err + } + if id != "" { + return id, nil + } + return "", ErrNotExist +} + +// Iterate iterates over all stored IDs and passes each of them to the given +// handler. Take care that the handler method does not call any public +// method on truncindex as the internal locking is not reentrant/recursive +// and will result in deadlock. +func (idx *TruncIndex) Iterate(handler func(id string)) { + idx.Lock() + defer idx.Unlock() + idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { + handler(string(prefix)) + return nil + }) +} diff -Nru containerd-1.2.6/pkg/cri/store/util.go containerd-1.5.9/pkg/cri/store/util.go --- containerd-1.2.6/pkg/cri/store/util.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/store/util.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package store + +import "sync" + +// StopCh is used to propagate the stop information of a container. +type StopCh struct { + ch chan struct{} + once sync.Once +} + +// NewStopCh creates a stop channel. The channel is open by default. +func NewStopCh() *StopCh { + return &StopCh{ch: make(chan struct{})} +} + +// Stop close stopCh of the container. +func (s *StopCh) Stop() { + s.once.Do(func() { + close(s.ch) + }) +} + +// Stopped return the stopCh of the container as a readonly channel. +func (s *StopCh) Stopped() <-chan struct{} { + return s.ch +} diff -Nru containerd-1.2.6/pkg/cri/streaming/errors.go containerd-1.5.9/pkg/cri/streaming/errors.go --- containerd-1.2.6/pkg/cri/streaming/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,72 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package streaming + +import ( + "net/http" + "strconv" + + "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" +) + +// NewErrorStreamingDisabled creates an error for disabled streaming method. +func NewErrorStreamingDisabled(method string) error { + return grpcstatus.Errorf(codes.NotFound, "streaming method %s disabled", method) +} + +// NewErrorTooManyInFlight creates an error for exceeding the maximum number of in-flight requests. +func NewErrorTooManyInFlight() error { + return grpcstatus.Error(codes.ResourceExhausted, "maximum number of in-flight requests exceeded") +} + +// WriteError translates a CRI streaming error into an appropriate HTTP response. +func WriteError(err error, w http.ResponseWriter) error { + s, _ := grpcstatus.FromError(err) + var status int + switch s.Code() { + case codes.NotFound: + status = http.StatusNotFound + case codes.ResourceExhausted: + // We only expect to hit this if there is a DoS, so we just wait the full TTL. + // If this is ever hit in steady-state operations, consider increasing the maxInFlight requests, + // or plumbing through the time to next expiration. + w.Header().Set("Retry-After", strconv.Itoa(int(cacheTTL.Seconds()))) + status = http.StatusTooManyRequests + default: + status = http.StatusInternalServerError + } + w.WriteHeader(status) + _, writeErr := w.Write([]byte(err.Error())) + return writeErr +} diff -Nru containerd-1.2.6/pkg/cri/streaming/portforward/constants.go containerd-1.5.9/pkg/cri/streaming/portforward/constants.go --- containerd-1.2.6/pkg/cri/streaming/portforward/constants.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/portforward/constants.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package portforward contains server-side logic for handling port forwarding requests. +package portforward + +// ProtocolV1Name is the name of the subprotocol used for port forwarding. +const ProtocolV1Name = "portforward.k8s.io" + +// SupportedProtocols are the supported port forwarding protocols. +var SupportedProtocols = []string{ProtocolV1Name} diff -Nru containerd-1.2.6/pkg/cri/streaming/portforward/httpstream.go containerd-1.5.9/pkg/cri/streaming/portforward/httpstream.go --- containerd-1.2.6/pkg/cri/streaming/portforward/httpstream.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/portforward/httpstream.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,315 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package portforward + +import ( + "errors" + "fmt" + "net/http" + "strconv" + "sync" + "time" + + api "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/httpstream" + "k8s.io/apimachinery/pkg/util/httpstream/spdy" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + "k8s.io/klog/v2" +) + +func handleHTTPStreams(req *http.Request, w http.ResponseWriter, portForwarder PortForwarder, podName string, uid types.UID, supportedPortForwardProtocols []string, idleTimeout, streamCreationTimeout time.Duration) error { + _, err := httpstream.Handshake(req, w, supportedPortForwardProtocols) + // negotiated protocol isn't currently used server side, but could be in the future + if err != nil { + // Handshake writes the error to the client + return err + } + streamChan := make(chan httpstream.Stream, 1) + + klog.V(5).Infof("Upgrading port forward response") + upgrader := spdy.NewResponseUpgrader() + conn := upgrader.UpgradeResponse(w, req, httpStreamReceived(streamChan)) + if conn == nil { + return errors.New("unable to upgrade httpstream connection") + } + defer conn.Close() + + klog.V(5).Infof("(conn=%p) setting port forwarding streaming connection idle timeout to %v", conn, idleTimeout) + conn.SetIdleTimeout(idleTimeout) + + h := &httpStreamHandler{ + conn: conn, + streamChan: streamChan, + streamPairs: make(map[string]*httpStreamPair), + streamCreationTimeout: streamCreationTimeout, + pod: podName, + uid: uid, + forwarder: portForwarder, + } + h.run() + + return nil +} + +// httpStreamReceived is the httpstream.NewStreamHandler for port +// forward streams. It checks each stream's port and stream type headers, +// rejecting any streams that with missing or invalid values. Each valid +// stream is sent to the streams channel. +func httpStreamReceived(streams chan httpstream.Stream) func(httpstream.Stream, <-chan struct{}) error { + return func(stream httpstream.Stream, replySent <-chan struct{}) error { + // make sure it has a valid port header + portString := stream.Headers().Get(api.PortHeader) + if len(portString) == 0 { + return fmt.Errorf("%q header is required", api.PortHeader) + } + port, err := strconv.ParseUint(portString, 10, 16) + if err != nil { + return fmt.Errorf("unable to parse %q as a port: %v", portString, err) + } + if port < 1 { + return fmt.Errorf("port %q must be > 0", portString) + } + + // make sure it has a valid stream type header + streamType := stream.Headers().Get(api.StreamType) + if len(streamType) == 0 { + return fmt.Errorf("%q header is required", api.StreamType) + } + if streamType != api.StreamTypeError && streamType != api.StreamTypeData { + return fmt.Errorf("invalid stream type %q", streamType) + } + + streams <- stream + return nil + } +} + +// httpStreamHandler is capable of processing multiple port forward +// requests over a single httpstream.Connection. +type httpStreamHandler struct { + conn httpstream.Connection + streamChan chan httpstream.Stream + streamPairsLock sync.RWMutex + streamPairs map[string]*httpStreamPair + streamCreationTimeout time.Duration + pod string + uid types.UID + forwarder PortForwarder +} + +// getStreamPair returns a httpStreamPair for requestID. This creates a +// new pair if one does not yet exist for the requestID. The returned bool is +// true if the pair was created. +func (h *httpStreamHandler) getStreamPair(requestID string) (*httpStreamPair, bool) { + h.streamPairsLock.Lock() + defer h.streamPairsLock.Unlock() + + if p, ok := h.streamPairs[requestID]; ok { + klog.V(5).Infof("(conn=%p, request=%s) found existing stream pair", h.conn, requestID) + return p, false + } + + klog.V(5).Infof("(conn=%p, request=%s) creating new stream pair", h.conn, requestID) + + p := newPortForwardPair(requestID) + h.streamPairs[requestID] = p + + return p, true +} + +// monitorStreamPair waits for the pair to receive both its error and data +// streams, or for the timeout to expire (whichever happens first), and then +// removes the pair. +func (h *httpStreamHandler) monitorStreamPair(p *httpStreamPair, timeout <-chan time.Time) { + select { + case <-timeout: + err := fmt.Errorf("(conn=%v, request=%s) timed out waiting for streams", h.conn, p.requestID) + utilruntime.HandleError(err) + p.printError(err.Error()) + case <-p.complete: + klog.V(5).Infof("(conn=%v, request=%s) successfully received error and data streams", h.conn, p.requestID) + } + h.removeStreamPair(p.requestID) +} + +// removeStreamPair removes the stream pair identified by requestID from streamPairs. +func (h *httpStreamHandler) removeStreamPair(requestID string) { + h.streamPairsLock.Lock() + defer h.streamPairsLock.Unlock() + + delete(h.streamPairs, requestID) +} + +// requestID returns the request id for stream. +func (h *httpStreamHandler) requestID(stream httpstream.Stream) string { + requestID := stream.Headers().Get(api.PortForwardRequestIDHeader) + if len(requestID) == 0 { + klog.V(5).Infof("(conn=%p) stream received without %s header", h.conn, api.PortForwardRequestIDHeader) + // If we get here, it's because the connection came from an older client + // that isn't generating the request id header + // (https://github.com/kubernetes/kubernetes/blob/843134885e7e0b360eb5441e85b1410a8b1a7a0c/pkg/client/unversioned/portforward/portforward.go#L258-L287) + // + // This is a best-effort attempt at supporting older clients. + // + // When there aren't concurrent new forwarded connections, each connection + // will have a pair of streams (data, error), and the stream IDs will be + // consecutive odd numbers, e.g. 1 and 3 for the first connection. Convert + // the stream ID into a pseudo-request id by taking the stream type and + // using id = stream.Identifier() when the stream type is error, + // and id = stream.Identifier() - 2 when it's data. + // + // NOTE: this only works when there are not concurrent new streams from + // multiple forwarded connections; it's a best-effort attempt at supporting + // old clients that don't generate request ids. If there are concurrent + // new connections, it's possible that 1 connection gets streams whose IDs + // are not consecutive (e.g. 5 and 9 instead of 5 and 7). + streamType := stream.Headers().Get(api.StreamType) + switch streamType { + case api.StreamTypeError: + requestID = strconv.Itoa(int(stream.Identifier())) + case api.StreamTypeData: + requestID = strconv.Itoa(int(stream.Identifier()) - 2) + } + + klog.V(5).Infof("(conn=%p) automatically assigning request ID=%q from stream type=%s, stream ID=%d", h.conn, requestID, streamType, stream.Identifier()) + } + return requestID +} + +// run is the main loop for the httpStreamHandler. It processes new +// streams, invoking portForward for each complete stream pair. The loop exits +// when the httpstream.Connection is closed. +func (h *httpStreamHandler) run() { + klog.V(5).Infof("(conn=%p) waiting for port forward streams", h.conn) +Loop: + for { + select { + case <-h.conn.CloseChan(): + klog.V(5).Infof("(conn=%p) upgraded connection closed", h.conn) + break Loop + case stream := <-h.streamChan: + requestID := h.requestID(stream) + streamType := stream.Headers().Get(api.StreamType) + klog.V(5).Infof("(conn=%p, request=%s) received new stream of type %s", h.conn, requestID, streamType) + + p, created := h.getStreamPair(requestID) + if created { + go h.monitorStreamPair(p, time.After(h.streamCreationTimeout)) + } + if complete, err := p.add(stream); err != nil { + msg := fmt.Sprintf("error processing stream for request %s: %v", requestID, err) + utilruntime.HandleError(errors.New(msg)) + p.printError(msg) + } else if complete { + go h.portForward(p) + } + } + } +} + +// portForward invokes the httpStreamHandler's forwarder.PortForward +// function for the given stream pair. +func (h *httpStreamHandler) portForward(p *httpStreamPair) { + defer p.dataStream.Close() + defer p.errorStream.Close() + + portString := p.dataStream.Headers().Get(api.PortHeader) + port, _ := strconv.ParseInt(portString, 10, 32) + + klog.V(5).Infof("(conn=%p, request=%s) invoking forwarder.PortForward for port %s", h.conn, p.requestID, portString) + err := h.forwarder.PortForward(h.pod, h.uid, int32(port), p.dataStream) + klog.V(5).Infof("(conn=%p, request=%s) done invoking forwarder.PortForward for port %s", h.conn, p.requestID, portString) + + if err != nil { + msg := fmt.Errorf("error forwarding port %d to pod %s, uid %v: %v", port, h.pod, h.uid, err) + utilruntime.HandleError(msg) + fmt.Fprint(p.errorStream, msg.Error()) + } +} + +// httpStreamPair represents the error and data streams for a port +// forwarding request. +type httpStreamPair struct { + lock sync.RWMutex + requestID string + dataStream httpstream.Stream + errorStream httpstream.Stream + complete chan struct{} +} + +// newPortForwardPair creates a new httpStreamPair. +func newPortForwardPair(requestID string) *httpStreamPair { + return &httpStreamPair{ + requestID: requestID, + complete: make(chan struct{}), + } +} + +// add adds the stream to the httpStreamPair. If the pair already +// contains a stream for the new stream's type, an error is returned. add +// returns true if both the data and error streams for this pair have been +// received. +func (p *httpStreamPair) add(stream httpstream.Stream) (bool, error) { + p.lock.Lock() + defer p.lock.Unlock() + + switch stream.Headers().Get(api.StreamType) { + case api.StreamTypeError: + if p.errorStream != nil { + return false, errors.New("error stream already assigned") + } + p.errorStream = stream + case api.StreamTypeData: + if p.dataStream != nil { + return false, errors.New("data stream already assigned") + } + p.dataStream = stream + } + + complete := p.errorStream != nil && p.dataStream != nil + if complete { + close(p.complete) + } + return complete, nil +} + +// printError writes s to p.errorStream if p.errorStream has been set. +func (p *httpStreamPair) printError(s string) { + p.lock.RLock() + defer p.lock.RUnlock() + if p.errorStream != nil { + fmt.Fprint(p.errorStream, s) + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/portforward/portforward.go containerd-1.5.9/pkg/cri/streaming/portforward/portforward.go --- containerd-1.2.6/pkg/cri/streaming/portforward/portforward.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/portforward/portforward.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,69 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package portforward + +import ( + "io" + "net/http" + "time" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/util/wsstream" +) + +// PortForwarder knows how to forward content from a data stream to/from a port +// in a pod. +type PortForwarder interface { + // PortForwarder copies data between a data stream and a port in a pod. + PortForward(name string, uid types.UID, port int32, stream io.ReadWriteCloser) error +} + +// ServePortForward handles a port forwarding request. A single request is +// kept alive as long as the client is still alive and the connection has not +// been timed out due to idleness. This function handles multiple forwarded +// connections; i.e., multiple `curl http://localhost:8888/` requests will be +// handled by a single invocation of ServePortForward. +func ServePortForward(w http.ResponseWriter, req *http.Request, portForwarder PortForwarder, podName string, uid types.UID, portForwardOptions *V4Options, idleTimeout time.Duration, streamCreationTimeout time.Duration, supportedProtocols []string) { + var err error + if wsstream.IsWebSocketRequest(req) { + err = handleWebSocketStreams(req, w, portForwarder, podName, uid, portForwardOptions, supportedProtocols, idleTimeout, streamCreationTimeout) + } else { + err = handleHTTPStreams(req, w, portForwarder, podName, uid, supportedProtocols, idleTimeout, streamCreationTimeout) + } + + if err != nil { + runtime.HandleError(err) + return + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/portforward/websocket.go containerd-1.5.9/pkg/cri/streaming/portforward/websocket.go --- containerd-1.2.6/pkg/cri/streaming/portforward/websocket.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/portforward/websocket.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,213 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package portforward + +import ( + "encoding/binary" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "sync" + "time" + + "k8s.io/klog/v2" + + api "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/server/httplog" + "k8s.io/apiserver/pkg/util/wsstream" +) + +const ( + dataChannel = iota + errorChannel + + v4BinaryWebsocketProtocol = "v4." + wsstream.ChannelWebSocketProtocol + v4Base64WebsocketProtocol = "v4." + wsstream.Base64ChannelWebSocketProtocol +) + +// V4Options contains details about which streams are required for port +// forwarding. +// All fields included in V4Options need to be expressed explicitly in the +// CRI (k8s.io/cri-api/pkg/apis/{version}/api.proto) PortForwardRequest. +type V4Options struct { + Ports []int32 +} + +// NewV4Options creates a new options from the Request. +func NewV4Options(req *http.Request) (*V4Options, error) { + if !wsstream.IsWebSocketRequest(req) { + return &V4Options{}, nil + } + + portStrings := req.URL.Query()[api.PortHeader] + if len(portStrings) == 0 { + return nil, fmt.Errorf("query parameter %q is required", api.PortHeader) + } + + ports := make([]int32, 0, len(portStrings)) + for _, portString := range portStrings { + if len(portString) == 0 { + return nil, fmt.Errorf("query parameter %q cannot be empty", api.PortHeader) + } + for _, p := range strings.Split(portString, ",") { + port, err := strconv.ParseUint(p, 10, 16) + if err != nil { + return nil, fmt.Errorf("unable to parse %q as a port: %v", portString, err) + } + if port < 1 { + return nil, fmt.Errorf("port %q must be > 0", portString) + } + ports = append(ports, int32(port)) + } + } + + return &V4Options{ + Ports: ports, + }, nil +} + +// BuildV4Options returns a V4Options based on the given information. +func BuildV4Options(ports []int32) (*V4Options, error) { + return &V4Options{Ports: ports}, nil +} + +// handleWebSocketStreams handles requests to forward ports to a pod via +// a PortForwarder. A pair of streams are created per port (DATA n, +// ERROR n+1). The associated port is written to each stream as a unsigned 16 +// bit integer in little endian format. +func handleWebSocketStreams(req *http.Request, w http.ResponseWriter, portForwarder PortForwarder, podName string, uid types.UID, opts *V4Options, supportedPortForwardProtocols []string, idleTimeout, streamCreationTimeout time.Duration) error { + channels := make([]wsstream.ChannelType, 0, len(opts.Ports)*2) + for i := 0; i < len(opts.Ports); i++ { + channels = append(channels, wsstream.ReadWriteChannel, wsstream.WriteChannel) + } + conn := wsstream.NewConn(map[string]wsstream.ChannelProtocolConfig{ + "": { + Binary: true, + Channels: channels, + }, + v4BinaryWebsocketProtocol: { + Binary: true, + Channels: channels, + }, + v4Base64WebsocketProtocol: { + Binary: false, + Channels: channels, + }, + }) + conn.SetIdleTimeout(idleTimeout) + _, streams, err := conn.Open(httplog.Unlogged(req, w), req) + if err != nil { + err = fmt.Errorf("unable to upgrade websocket connection: %v", err) + return err + } + defer conn.Close() + streamPairs := make([]*websocketStreamPair, len(opts.Ports)) + for i := range streamPairs { + streamPair := websocketStreamPair{ + port: opts.Ports[i], + dataStream: streams[i*2+dataChannel], + errorStream: streams[i*2+errorChannel], + } + streamPairs[i] = &streamPair + + portBytes := make([]byte, 2) + // port is always positive so conversion is allowable + binary.LittleEndian.PutUint16(portBytes, uint16(streamPair.port)) + streamPair.dataStream.Write(portBytes) + streamPair.errorStream.Write(portBytes) + } + h := &websocketStreamHandler{ + conn: conn, + streamPairs: streamPairs, + pod: podName, + uid: uid, + forwarder: portForwarder, + } + h.run() + + return nil +} + +// websocketStreamPair represents the error and data streams for a port +// forwarding request. +type websocketStreamPair struct { + port int32 + dataStream io.ReadWriteCloser + errorStream io.WriteCloser +} + +// websocketStreamHandler is capable of processing a single port forward +// request over a websocket connection +type websocketStreamHandler struct { + conn *wsstream.Conn + streamPairs []*websocketStreamPair + pod string + uid types.UID + forwarder PortForwarder +} + +// run invokes the websocketStreamHandler's forwarder.PortForward +// function for the given stream pair. +func (h *websocketStreamHandler) run() { + wg := sync.WaitGroup{} + wg.Add(len(h.streamPairs)) + + for _, pair := range h.streamPairs { + p := pair + go func() { + defer wg.Done() + h.portForward(p) + }() + } + + wg.Wait() +} + +func (h *websocketStreamHandler) portForward(p *websocketStreamPair) { + defer p.dataStream.Close() + defer p.errorStream.Close() + + klog.V(5).Infof("(conn=%p) invoking forwarder.PortForward for port %d", h.conn, p.port) + err := h.forwarder.PortForward(h.pod, h.uid, p.port, p.dataStream) + klog.V(5).Infof("(conn=%p) done invoking forwarder.PortForward for port %d", h.conn, p.port) + + if err != nil { + msg := fmt.Errorf("error forwarding port %d to pod %s, uid %v: %v", p.port, h.pod, h.uid, err) + runtime.HandleError(msg) + fmt.Fprint(p.errorStream, msg.Error()) + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/remotecommand/attach.go containerd-1.5.9/pkg/cri/streaming/remotecommand/attach.go --- containerd-1.2.6/pkg/cri/streaming/remotecommand/attach.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/remotecommand/attach.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,75 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remotecommand + +import ( + "fmt" + "io" + "net/http" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/tools/remotecommand" +) + +// Attacher knows how to attach to a running container in a pod. +type Attacher interface { + // AttachContainer attaches to the running container in the pod, copying data between in/out/err + // and the container's stdin/stdout/stderr. + AttachContainer(name string, uid types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error +} + +// ServeAttach handles requests to attach to a container. After creating/receiving the required +// streams, it delegates the actual attaching to attacher. +func ServeAttach(w http.ResponseWriter, req *http.Request, attacher Attacher, podName string, uid types.UID, container string, streamOpts *Options, idleTimeout, streamCreationTimeout time.Duration, supportedProtocols []string) { + ctx, ok := createStreams(req, w, streamOpts, supportedProtocols, idleTimeout, streamCreationTimeout) + if !ok { + // error is handled by createStreams + return + } + defer ctx.conn.Close() + + err := attacher.AttachContainer(podName, uid, container, ctx.stdinStream, ctx.stdoutStream, ctx.stderrStream, ctx.tty, ctx.resizeChan) + if err != nil { + err = fmt.Errorf("error attaching to container: %v", err) + runtime.HandleError(err) + ctx.writeStatus(apierrors.NewInternalError(err)) + } else { + ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ + Status: metav1.StatusSuccess, + }}) + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/remotecommand/doc.go containerd-1.5.9/pkg/cri/streaming/remotecommand/doc.go --- containerd-1.2.6/pkg/cri/streaming/remotecommand/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/remotecommand/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package remotecommand contains functions related to executing commands in and attaching to pods. +package remotecommand diff -Nru containerd-1.2.6/pkg/cri/streaming/remotecommand/exec.go containerd-1.5.9/pkg/cri/streaming/remotecommand/exec.go --- containerd-1.2.6/pkg/cri/streaming/remotecommand/exec.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/remotecommand/exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,95 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remotecommand + +import ( + "fmt" + "io" + "net/http" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/tools/remotecommand" + utilexec "k8s.io/utils/exec" +) + +// Executor knows how to execute a command in a container in a pod. +type Executor interface { + // ExecInContainer executes a command in a container in the pod, copying data + // between in/out/err and the container's stdin/stdout/stderr. + ExecInContainer(name string, uid types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error +} + +// ServeExec handles requests to execute a command in a container. After +// creating/receiving the required streams, it delegates the actual execution +// to the executor. +func ServeExec(w http.ResponseWriter, req *http.Request, executor Executor, podName string, uid types.UID, container string, cmd []string, streamOpts *Options, idleTimeout, streamCreationTimeout time.Duration, supportedProtocols []string) { + ctx, ok := createStreams(req, w, streamOpts, supportedProtocols, idleTimeout, streamCreationTimeout) + if !ok { + // error is handled by createStreams + return + } + defer ctx.conn.Close() + + err := executor.ExecInContainer(podName, uid, container, cmd, ctx.stdinStream, ctx.stdoutStream, ctx.stderrStream, ctx.tty, ctx.resizeChan, 0) + if err != nil { + if exitErr, ok := err.(utilexec.ExitError); ok && exitErr.Exited() { + rc := exitErr.ExitStatus() + ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ + Status: metav1.StatusFailure, + Reason: remotecommandconsts.NonZeroExitCodeReason, + Details: &metav1.StatusDetails{ + Causes: []metav1.StatusCause{ + { + Type: remotecommandconsts.ExitCodeCauseType, + Message: fmt.Sprintf("%d", rc), + }, + }, + }, + Message: fmt.Sprintf("command terminated with non-zero exit code: %v", exitErr), + }}) + } else { + err = fmt.Errorf("error executing command in container: %v", err) + runtime.HandleError(err) + ctx.writeStatus(apierrors.NewInternalError(err)) + } + } else { + ctx.writeStatus(&apierrors.StatusError{ErrStatus: metav1.Status{ + Status: metav1.StatusSuccess, + }}) + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/remotecommand/httpstream.go containerd-1.5.9/pkg/cri/streaming/remotecommand/httpstream.go --- containerd-1.2.6/pkg/cri/streaming/remotecommand/httpstream.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/remotecommand/httpstream.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,463 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remotecommand + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "time" + + api "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/httpstream" + "k8s.io/apimachinery/pkg/util/httpstream/spdy" + remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/util/wsstream" + "k8s.io/client-go/tools/remotecommand" + + "k8s.io/klog/v2" +) + +// Options contains details about which streams are required for +// remote command execution. +type Options struct { + Stdin bool + Stdout bool + Stderr bool + TTY bool +} + +// NewOptions creates a new Options from the Request. +func NewOptions(req *http.Request) (*Options, error) { + tty := req.FormValue(api.ExecTTYParam) == "1" + stdin := req.FormValue(api.ExecStdinParam) == "1" + stdout := req.FormValue(api.ExecStdoutParam) == "1" + stderr := req.FormValue(api.ExecStderrParam) == "1" + if tty && stderr { + // TODO: make this an error before we reach this method + klog.V(4).Infof("Access to exec with tty and stderr is not supported, bypassing stderr") + stderr = false + } + + if !stdin && !stdout && !stderr { + return nil, fmt.Errorf("you must specify at least 1 of stdin, stdout, stderr") + } + + return &Options{ + Stdin: stdin, + Stdout: stdout, + Stderr: stderr, + TTY: tty, + }, nil +} + +// context contains the connection and streams used when +// forwarding an attach or execute session into a container. +type context struct { + conn io.Closer + stdinStream io.ReadCloser + stdoutStream io.WriteCloser + stderrStream io.WriteCloser + writeStatus func(status *apierrors.StatusError) error + resizeStream io.ReadCloser + resizeChan chan remotecommand.TerminalSize + tty bool +} + +// streamAndReply holds both a Stream and a channel that is closed when the stream's reply frame is +// enqueued. Consumers can wait for replySent to be closed prior to proceeding, to ensure that the +// replyFrame is enqueued before the connection's goaway frame is sent (e.g. if a stream was +// received and right after, the connection gets closed). +type streamAndReply struct { + httpstream.Stream + replySent <-chan struct{} +} + +// waitStreamReply waits until either replySent or stop is closed. If replySent is closed, it sends +// an empty struct to the notify channel. +func waitStreamReply(replySent <-chan struct{}, notify chan<- struct{}, stop <-chan struct{}) { + select { + case <-replySent: + notify <- struct{}{} + case <-stop: + } +} + +func createStreams(req *http.Request, w http.ResponseWriter, opts *Options, supportedStreamProtocols []string, idleTimeout, streamCreationTimeout time.Duration) (*context, bool) { + var ctx *context + var ok bool + if wsstream.IsWebSocketRequest(req) { + ctx, ok = createWebSocketStreams(req, w, opts, idleTimeout) + } else { + ctx, ok = createHTTPStreamStreams(req, w, opts, supportedStreamProtocols, idleTimeout, streamCreationTimeout) + } + if !ok { + return nil, false + } + + if ctx.resizeStream != nil { + ctx.resizeChan = make(chan remotecommand.TerminalSize) + go handleResizeEvents(ctx.resizeStream, ctx.resizeChan) + } + + return ctx, true +} + +func createHTTPStreamStreams(req *http.Request, w http.ResponseWriter, opts *Options, supportedStreamProtocols []string, idleTimeout, streamCreationTimeout time.Duration) (*context, bool) { + protocol, err := httpstream.Handshake(req, w, supportedStreamProtocols) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return nil, false + } + + streamCh := make(chan streamAndReply) + + upgrader := spdy.NewResponseUpgrader() + conn := upgrader.UpgradeResponse(w, req, func(stream httpstream.Stream, replySent <-chan struct{}) error { + streamCh <- streamAndReply{Stream: stream, replySent: replySent} + return nil + }) + // from this point on, we can no longer call methods on response + if conn == nil { + // The upgrader is responsible for notifying the client of any errors that + // occurred during upgrading. All we can do is return here at this point + // if we weren't successful in upgrading. + return nil, false + } + + conn.SetIdleTimeout(idleTimeout) + + var handler protocolHandler + switch protocol { + case remotecommandconsts.StreamProtocolV4Name: + handler = &v4ProtocolHandler{} + case remotecommandconsts.StreamProtocolV3Name: + handler = &v3ProtocolHandler{} + case remotecommandconsts.StreamProtocolV2Name: + handler = &v2ProtocolHandler{} + case "": + klog.V(4).Infof("Client did not request protocol negotiation. Falling back to %q", remotecommandconsts.StreamProtocolV1Name) + fallthrough + case remotecommandconsts.StreamProtocolV1Name: + handler = &v1ProtocolHandler{} + } + + // count the streams client asked for, starting with 1 + expectedStreams := 1 + if opts.Stdin { + expectedStreams++ + } + if opts.Stdout { + expectedStreams++ + } + if opts.Stderr { + expectedStreams++ + } + if opts.TTY && handler.supportsTerminalResizing() { + expectedStreams++ + } + + expired := time.NewTimer(streamCreationTimeout) + defer expired.Stop() + + ctx, err := handler.waitForStreams(streamCh, expectedStreams, expired.C) + if err != nil { + runtime.HandleError(err) + return nil, false + } + + ctx.conn = conn + ctx.tty = opts.TTY + + return ctx, true +} + +type protocolHandler interface { + // waitForStreams waits for the expected streams or a timeout, returning a + // remoteCommandContext if all the streams were received, or an error if not. + waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) + // supportsTerminalResizing returns true if the protocol handler supports terminal resizing + supportsTerminalResizing() bool +} + +// v4ProtocolHandler implements the V4 protocol version for streaming command execution. It only differs +// in from v3 in the error stream format using an json-marshaled metav1.Status which carries +// the process' exit code. +type v4ProtocolHandler struct{} + +func (*v4ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { + ctx := &context{} + receivedStreams := 0 + replyChan := make(chan struct{}) + stop := make(chan struct{}) + defer close(stop) +WaitForStreams: + for { + select { + case stream := <-streams: + streamType := stream.Headers().Get(api.StreamType) + switch streamType { + case api.StreamTypeError: + ctx.writeStatus = v4WriteStatusFunc(stream) // write json errors + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdin: + ctx.stdinStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdout: + ctx.stdoutStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStderr: + ctx.stderrStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeResize: + ctx.resizeStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + default: + runtime.HandleError(fmt.Errorf("unexpected stream type: %q", streamType)) + } + case <-replyChan: + receivedStreams++ + if receivedStreams == expectedStreams { + break WaitForStreams + } + case <-expired: + // TODO find a way to return the error to the user. Maybe use a separate + // stream to report errors? + return nil, errors.New("timed out waiting for client to create streams") + } + } + + return ctx, nil +} + +// supportsTerminalResizing returns true because v4ProtocolHandler supports it +func (*v4ProtocolHandler) supportsTerminalResizing() bool { return true } + +// v3ProtocolHandler implements the V3 protocol version for streaming command execution. +type v3ProtocolHandler struct{} + +func (*v3ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { + ctx := &context{} + receivedStreams := 0 + replyChan := make(chan struct{}) + stop := make(chan struct{}) + defer close(stop) +WaitForStreams: + for { + select { + case stream := <-streams: + streamType := stream.Headers().Get(api.StreamType) + switch streamType { + case api.StreamTypeError: + ctx.writeStatus = v1WriteStatusFunc(stream) + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdin: + ctx.stdinStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdout: + ctx.stdoutStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStderr: + ctx.stderrStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeResize: + ctx.resizeStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + default: + runtime.HandleError(fmt.Errorf("unexpected stream type: %q", streamType)) + } + case <-replyChan: + receivedStreams++ + if receivedStreams == expectedStreams { + break WaitForStreams + } + case <-expired: + // TODO find a way to return the error to the user. Maybe use a separate + // stream to report errors? + return nil, errors.New("timed out waiting for client to create streams") + } + } + + return ctx, nil +} + +// supportsTerminalResizing returns true because v3ProtocolHandler supports it +func (*v3ProtocolHandler) supportsTerminalResizing() bool { return true } + +// v2ProtocolHandler implements the V2 protocol version for streaming command execution. +type v2ProtocolHandler struct{} + +func (*v2ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { + ctx := &context{} + receivedStreams := 0 + replyChan := make(chan struct{}) + stop := make(chan struct{}) + defer close(stop) +WaitForStreams: + for { + select { + case stream := <-streams: + streamType := stream.Headers().Get(api.StreamType) + switch streamType { + case api.StreamTypeError: + ctx.writeStatus = v1WriteStatusFunc(stream) + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdin: + ctx.stdinStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdout: + ctx.stdoutStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStderr: + ctx.stderrStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + default: + runtime.HandleError(fmt.Errorf("unexpected stream type: %q", streamType)) + } + case <-replyChan: + receivedStreams++ + if receivedStreams == expectedStreams { + break WaitForStreams + } + case <-expired: + // TODO find a way to return the error to the user. Maybe use a separate + // stream to report errors? + return nil, errors.New("timed out waiting for client to create streams") + } + } + + return ctx, nil +} + +// supportsTerminalResizing returns false because v2ProtocolHandler doesn't support it. +func (*v2ProtocolHandler) supportsTerminalResizing() bool { return false } + +// v1ProtocolHandler implements the V1 protocol version for streaming command execution. +type v1ProtocolHandler struct{} + +func (*v1ProtocolHandler) waitForStreams(streams <-chan streamAndReply, expectedStreams int, expired <-chan time.Time) (*context, error) { + ctx := &context{} + receivedStreams := 0 + replyChan := make(chan struct{}) + stop := make(chan struct{}) + defer close(stop) +WaitForStreams: + for { + select { + case stream := <-streams: + streamType := stream.Headers().Get(api.StreamType) + switch streamType { + case api.StreamTypeError: + ctx.writeStatus = v1WriteStatusFunc(stream) + + // This defer statement shouldn't be here, but due to previous refactoring, it ended up in + // here. This is what 1.0.x kubelets do, so we're retaining that behavior. This is fixed in + // the v2ProtocolHandler. + defer stream.Reset() + + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdin: + ctx.stdinStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStdout: + ctx.stdoutStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + case api.StreamTypeStderr: + ctx.stderrStream = stream + go waitStreamReply(stream.replySent, replyChan, stop) + default: + runtime.HandleError(fmt.Errorf("unexpected stream type: %q", streamType)) + } + case <-replyChan: + receivedStreams++ + if receivedStreams == expectedStreams { + break WaitForStreams + } + case <-expired: + // TODO find a way to return the error to the user. Maybe use a separate + // stream to report errors? + return nil, errors.New("timed out waiting for client to create streams") + } + } + + if ctx.stdinStream != nil { + ctx.stdinStream.Close() + } + + return ctx, nil +} + +// supportsTerminalResizing returns false because v1ProtocolHandler doesn't support it. +func (*v1ProtocolHandler) supportsTerminalResizing() bool { return false } + +func handleResizeEvents(stream io.Reader, channel chan<- remotecommand.TerminalSize) { + defer runtime.HandleCrash() + defer close(channel) + + decoder := json.NewDecoder(stream) + for { + size := remotecommand.TerminalSize{} + if err := decoder.Decode(&size); err != nil { + break + } + channel <- size + } +} + +func v1WriteStatusFunc(stream io.Writer) func(status *apierrors.StatusError) error { + return func(status *apierrors.StatusError) error { + if status.Status().Status == metav1.StatusSuccess { + return nil // send error messages + } + _, err := stream.Write([]byte(status.Error())) + return err + } +} + +// v4WriteStatusFunc returns a WriteStatusFunc that marshals a given api Status +// as json in the error channel. +func v4WriteStatusFunc(stream io.Writer) func(status *apierrors.StatusError) error { + return func(status *apierrors.StatusError) error { + bs, err := json.Marshal(status.Status()) + if err != nil { + return err + } + _, err = stream.Write(bs) + return err + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/remotecommand/websocket.go containerd-1.5.9/pkg/cri/streaming/remotecommand/websocket.go --- containerd-1.2.6/pkg/cri/streaming/remotecommand/websocket.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/remotecommand/websocket.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,148 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remotecommand + +import ( + "fmt" + "net/http" + "time" + + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/server/httplog" + "k8s.io/apiserver/pkg/util/wsstream" +) + +const ( + stdinChannel = iota + stdoutChannel + stderrChannel + errorChannel + resizeChannel + + preV4BinaryWebsocketProtocol = wsstream.ChannelWebSocketProtocol + preV4Base64WebsocketProtocol = wsstream.Base64ChannelWebSocketProtocol + v4BinaryWebsocketProtocol = "v4." + wsstream.ChannelWebSocketProtocol + v4Base64WebsocketProtocol = "v4." + wsstream.Base64ChannelWebSocketProtocol +) + +// createChannels returns the standard channel types for a shell connection (STDIN 0, STDOUT 1, STDERR 2) +// along with the approximate duplex value. It also creates the error (3) and resize (4) channels. +func createChannels(opts *Options) []wsstream.ChannelType { + // open the requested channels, and always open the error channel + channels := make([]wsstream.ChannelType, 5) + channels[stdinChannel] = readChannel(opts.Stdin) + channels[stdoutChannel] = writeChannel(opts.Stdout) + channels[stderrChannel] = writeChannel(opts.Stderr) + channels[errorChannel] = wsstream.WriteChannel + channels[resizeChannel] = wsstream.ReadChannel + return channels +} + +// readChannel returns wsstream.ReadChannel if real is true, or wsstream.IgnoreChannel. +func readChannel(real bool) wsstream.ChannelType { + if real { + return wsstream.ReadChannel + } + return wsstream.IgnoreChannel +} + +// writeChannel returns wsstream.WriteChannel if real is true, or wsstream.IgnoreChannel. +func writeChannel(real bool) wsstream.ChannelType { + if real { + return wsstream.WriteChannel + } + return wsstream.IgnoreChannel +} + +// createWebSocketStreams returns a context containing the websocket connection and +// streams needed to perform an exec or an attach. +func createWebSocketStreams(req *http.Request, w http.ResponseWriter, opts *Options, idleTimeout time.Duration) (*context, bool) { + channels := createChannels(opts) + conn := wsstream.NewConn(map[string]wsstream.ChannelProtocolConfig{ + "": { + Binary: true, + Channels: channels, + }, + preV4BinaryWebsocketProtocol: { + Binary: true, + Channels: channels, + }, + preV4Base64WebsocketProtocol: { + Binary: false, + Channels: channels, + }, + v4BinaryWebsocketProtocol: { + Binary: true, + Channels: channels, + }, + v4Base64WebsocketProtocol: { + Binary: false, + Channels: channels, + }, + }) + conn.SetIdleTimeout(idleTimeout) + negotiatedProtocol, streams, err := conn.Open(httplog.Unlogged(req, w), req) + if err != nil { + runtime.HandleError(fmt.Errorf("unable to upgrade websocket connection: %v", err)) + return nil, false + } + + // Send an empty message to the lowest writable channel to notify the client the connection is established + // TODO: make generic to SPDY and WebSockets and do it outside of this method? + switch { + case opts.Stdout: + streams[stdoutChannel].Write([]byte{}) + case opts.Stderr: + streams[stderrChannel].Write([]byte{}) + default: + streams[errorChannel].Write([]byte{}) + } + + ctx := &context{ + conn: conn, + stdinStream: streams[stdinChannel], + stdoutStream: streams[stdoutChannel], + stderrStream: streams[stderrChannel], + tty: opts.TTY, + resizeStream: streams[resizeChannel], + } + + switch negotiatedProtocol { + case v4BinaryWebsocketProtocol, v4Base64WebsocketProtocol: + ctx.writeStatus = v4WriteStatusFunc(streams[errorChannel]) + default: + ctx.writeStatus = v1WriteStatusFunc(streams[errorChannel]) + } + + return ctx, true +} diff -Nru containerd-1.2.6/pkg/cri/streaming/request_cache.go containerd-1.5.9/pkg/cri/streaming/request_cache.go --- containerd-1.2.6/pkg/cri/streaming/request_cache.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/request_cache.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,162 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package streaming + +import ( + "container/list" + "crypto/rand" + "encoding/base64" + "fmt" + "math" + "sync" + "time" + + "k8s.io/apimachinery/pkg/util/clock" +) + +var ( + // cacheTTL is the timeout after which tokens become invalid. + cacheTTL = 1 * time.Minute + // maxInFlight is the maximum number of in-flight requests to allow. + maxInFlight = 1000 + // tokenLen is the length of the random base64 encoded token identifying the request. + tokenLen = 8 +) + +// requestCache caches streaming (exec/attach/port-forward) requests and generates a single-use +// random token for their retrieval. The requestCache is used for building streaming URLs without +// the need to encode every request parameter in the URL. +type requestCache struct { + // clock is used to obtain the current time + clock clock.Clock + + // tokens maps the generate token to the request for fast retrieval. + tokens map[string]*list.Element + // ll maintains an age-ordered request list for faster garbage collection of expired requests. + ll *list.List + + lock sync.Mutex +} + +// Type representing an *ExecRequest, *AttachRequest, or *PortForwardRequest. +type request interface{} + +type cacheEntry struct { + token string + req request + expireTime time.Time +} + +func newRequestCache() *requestCache { + return &requestCache{ + clock: clock.RealClock{}, + ll: list.New(), + tokens: make(map[string]*list.Element), + } +} + +// Insert the given request into the cache and returns the token used for fetching it out. +func (c *requestCache) Insert(req request) (token string, err error) { + c.lock.Lock() + defer c.lock.Unlock() + + // Remove expired entries. + c.gc() + // If the cache is full, reject the request. + if c.ll.Len() == maxInFlight { + return "", NewErrorTooManyInFlight() + } + token, err = c.uniqueToken() + if err != nil { + return "", err + } + ele := c.ll.PushFront(&cacheEntry{token, req, c.clock.Now().Add(cacheTTL)}) + + c.tokens[token] = ele + return token, nil +} + +// Consume the token (remove it from the cache) and return the cached request, if found. +func (c *requestCache) Consume(token string) (req request, found bool) { + c.lock.Lock() + defer c.lock.Unlock() + ele, ok := c.tokens[token] + if !ok { + return nil, false + } + c.ll.Remove(ele) + delete(c.tokens, token) + + entry := ele.Value.(*cacheEntry) + if c.clock.Now().After(entry.expireTime) { + // Entry already expired. + return nil, false + } + return entry.req, true +} + +// uniqueToken generates a random URL-safe token and ensures uniqueness. +func (c *requestCache) uniqueToken() (string, error) { + const maxTries = 10 + // Number of bytes to be tokenLen when base64 encoded. + tokenSize := math.Ceil(float64(tokenLen) * 6 / 8) + rawToken := make([]byte, int(tokenSize)) + for i := 0; i < maxTries; i++ { + if _, err := rand.Read(rawToken); err != nil { + return "", err + } + encoded := base64.RawURLEncoding.EncodeToString(rawToken) + token := encoded[:tokenLen] + // If it's unique, return it. Otherwise retry. + if _, exists := c.tokens[encoded]; !exists { + return token, nil + } + } + return "", fmt.Errorf("failed to generate unique token") +} + +// Must be write-locked prior to calling. +func (c *requestCache) gc() { + now := c.clock.Now() + for c.ll.Len() > 0 { + oldest := c.ll.Back() + entry := oldest.Value.(*cacheEntry) + if !now.After(entry.expireTime) { + return + } + + // Oldest value is expired; remove it. + c.ll.Remove(oldest) + delete(c.tokens, entry.token) + } +} diff -Nru containerd-1.2.6/pkg/cri/streaming/server.go containerd-1.5.9/pkg/cri/streaming/server.go --- containerd-1.2.6/pkg/cri/streaming/server.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/streaming/server.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,399 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package streaming + +import ( + "crypto/tls" + "errors" + "io" + "net" + "net/http" + "net/url" + "path" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + restful "github.com/emicklei/go-restful" + + "k8s.io/apimachinery/pkg/types" + remotecommandconsts "k8s.io/apimachinery/pkg/util/remotecommand" + "k8s.io/client-go/tools/remotecommand" + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + + "github.com/containerd/containerd/pkg/cri/streaming/portforward" + remotecommandserver "github.com/containerd/containerd/pkg/cri/streaming/remotecommand" +) + +// Server is the library interface to serve the stream requests. +type Server interface { + http.Handler + + // Get the serving URL for the requests. + // Requests must not be nil. Responses may be nil iff an error is returned. + GetExec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) + GetAttach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) + GetPortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) + + // Start the server. + // addr is the address to serve on (address:port) stayUp indicates whether the server should + // listen until Stop() is called, or automatically stop after all expected connections are + // closed. Calling Get{Exec,Attach,PortForward} increments the expected connection count. + // Function does not return until the server is stopped. + Start(stayUp bool) error + // Stop the server, and terminate any open connections. + Stop() error +} + +// Runtime is the interface to execute the commands and provide the streams. +type Runtime interface { + Exec(containerID string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error + Attach(containerID string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error + PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error +} + +// Config defines the options used for running the stream server. +type Config struct { + // The host:port address the server will listen on. + Addr string + // The optional base URL for constructing streaming URLs. If empty, the baseURL will be + // constructed from the serve address. + // Note that for port "0", the URL port will be set to actual port in use. + BaseURL *url.URL + + // How long to leave idle connections open for. + StreamIdleTimeout time.Duration + // How long to wait for clients to create streams. Only used for SPDY streaming. + StreamCreationTimeout time.Duration + + // The streaming protocols the server supports (understands and permits). See + // k8s.io/kubernetes/pkg/kubelet/server/remotecommand/constants.go for available protocols. + // Only used for SPDY streaming. + SupportedRemoteCommandProtocols []string + + // The streaming protocols the server supports (understands and permits). See + // k8s.io/kubernetes/pkg/kubelet/server/portforward/constants.go for available protocols. + // Only used for SPDY streaming. + SupportedPortForwardProtocols []string + + // The config for serving over TLS. If nil, TLS will not be used. + TLSConfig *tls.Config +} + +// DefaultConfig provides default values for server Config. The DefaultConfig is partial, so +// some fields like Addr must still be provided. +var DefaultConfig = Config{ + StreamIdleTimeout: 4 * time.Hour, + StreamCreationTimeout: remotecommandconsts.DefaultStreamCreationTimeout, + SupportedRemoteCommandProtocols: remotecommandconsts.SupportedStreamingProtocols, + SupportedPortForwardProtocols: portforward.SupportedProtocols, +} + +// NewServer creates a new Server for stream requests. +// TODO(tallclair): Add auth(n/z) interface & handling. +func NewServer(config Config, runtime Runtime) (Server, error) { + s := &server{ + config: config, + runtime: &criAdapter{runtime}, + cache: newRequestCache(), + } + + if s.config.BaseURL == nil { + s.config.BaseURL = &url.URL{ + Scheme: "http", + Host: s.config.Addr, + } + if s.config.TLSConfig != nil { + s.config.BaseURL.Scheme = "https" + } + } + + ws := &restful.WebService{} + endpoints := []struct { + path string + handler restful.RouteFunction + }{ + {"/exec/{token}", s.serveExec}, + {"/attach/{token}", s.serveAttach}, + {"/portforward/{token}", s.servePortForward}, + } + // If serving relative to a base path, set that here. + pathPrefix := path.Dir(s.config.BaseURL.Path) + for _, e := range endpoints { + for _, method := range []string{"GET", "POST"} { + ws.Route(ws. + Method(method). + Path(path.Join(pathPrefix, e.path)). + To(e.handler)) + } + } + handler := restful.NewContainer() + handler.Add(ws) + s.handler = handler + s.server = &http.Server{ + Addr: s.config.Addr, + Handler: s.handler, + TLSConfig: s.config.TLSConfig, + } + + return s, nil +} + +type server struct { + config Config + runtime *criAdapter + handler http.Handler + cache *requestCache + server *http.Server +} + +func validateExecRequest(req *runtimeapi.ExecRequest) error { + if req.ContainerId == "" { + return status.Errorf(codes.InvalidArgument, "missing required container_id") + } + if req.Tty && req.Stderr { + // If TTY is set, stderr cannot be true because multiplexing is not + // supported. + return status.Errorf(codes.InvalidArgument, "tty and stderr cannot both be true") + } + if !req.Stdin && !req.Stdout && !req.Stderr { + return status.Errorf(codes.InvalidArgument, "one of stdin, stdout, or stderr must be set") + } + return nil +} + +func (s *server) GetExec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) { + if err := validateExecRequest(req); err != nil { + return nil, err + } + token, err := s.cache.Insert(req) + if err != nil { + return nil, err + } + return &runtimeapi.ExecResponse{ + Url: s.buildURL("exec", token), + }, nil +} + +func validateAttachRequest(req *runtimeapi.AttachRequest) error { + if req.ContainerId == "" { + return status.Errorf(codes.InvalidArgument, "missing required container_id") + } + if req.Tty && req.Stderr { + // If TTY is set, stderr cannot be true because multiplexing is not + // supported. + return status.Errorf(codes.InvalidArgument, "tty and stderr cannot both be true") + } + if !req.Stdin && !req.Stdout && !req.Stderr { + return status.Errorf(codes.InvalidArgument, "one of stdin, stdout, and stderr must be set") + } + return nil +} + +func (s *server) GetAttach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) { + if err := validateAttachRequest(req); err != nil { + return nil, err + } + token, err := s.cache.Insert(req) + if err != nil { + return nil, err + } + return &runtimeapi.AttachResponse{ + Url: s.buildURL("attach", token), + }, nil +} + +func (s *server) GetPortForward(req *runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) { + if req.PodSandboxId == "" { + return nil, status.Errorf(codes.InvalidArgument, "missing required pod_sandbox_id") + } + token, err := s.cache.Insert(req) + if err != nil { + return nil, err + } + return &runtimeapi.PortForwardResponse{ + Url: s.buildURL("portforward", token), + }, nil +} + +func (s *server) Start(stayUp bool) error { + if !stayUp { + // TODO(tallclair): Implement this. + return errors.New("stayUp=false is not yet implemented") + } + + listener, err := net.Listen("tcp", s.config.Addr) + if err != nil { + return err + } + // Use the actual address as baseURL host. This handles the "0" port case. + s.config.BaseURL.Host = listener.Addr().String() + if s.config.TLSConfig != nil { + return s.server.ServeTLS(listener, "", "") // Use certs from TLSConfig. + } + return s.server.Serve(listener) +} + +func (s *server) Stop() error { + return s.server.Close() +} + +func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + s.handler.ServeHTTP(w, r) +} + +func (s *server) buildURL(method, token string) string { + return s.config.BaseURL.ResolveReference(&url.URL{ + Path: path.Join(method, token), + }).String() +} + +func (s *server) serveExec(req *restful.Request, resp *restful.Response) { + token := req.PathParameter("token") + cachedRequest, ok := s.cache.Consume(token) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + exec, ok := cachedRequest.(*runtimeapi.ExecRequest) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + + streamOpts := &remotecommandserver.Options{ + Stdin: exec.Stdin, + Stdout: exec.Stdout, + Stderr: exec.Stderr, + TTY: exec.Tty, + } + + remotecommandserver.ServeExec( + resp.ResponseWriter, + req.Request, + s.runtime, + "", // unused: podName + "", // unusued: podUID + exec.ContainerId, + exec.Cmd, + streamOpts, + s.config.StreamIdleTimeout, + s.config.StreamCreationTimeout, + s.config.SupportedRemoteCommandProtocols) +} + +func (s *server) serveAttach(req *restful.Request, resp *restful.Response) { + token := req.PathParameter("token") + cachedRequest, ok := s.cache.Consume(token) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + attach, ok := cachedRequest.(*runtimeapi.AttachRequest) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + + streamOpts := &remotecommandserver.Options{ + Stdin: attach.Stdin, + Stdout: attach.Stdout, + Stderr: attach.Stderr, + TTY: attach.Tty, + } + remotecommandserver.ServeAttach( + resp.ResponseWriter, + req.Request, + s.runtime, + "", // unused: podName + "", // unusued: podUID + attach.ContainerId, + streamOpts, + s.config.StreamIdleTimeout, + s.config.StreamCreationTimeout, + s.config.SupportedRemoteCommandProtocols) +} + +func (s *server) servePortForward(req *restful.Request, resp *restful.Response) { + token := req.PathParameter("token") + cachedRequest, ok := s.cache.Consume(token) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + pf, ok := cachedRequest.(*runtimeapi.PortForwardRequest) + if !ok { + http.NotFound(resp.ResponseWriter, req.Request) + return + } + + portForwardOptions, err := portforward.BuildV4Options(pf.Port) + if err != nil { + resp.WriteError(http.StatusBadRequest, err) + return + } + + portforward.ServePortForward( + resp.ResponseWriter, + req.Request, + s.runtime, + pf.PodSandboxId, + "", // unused: podUID + portForwardOptions, + s.config.StreamIdleTimeout, + s.config.StreamCreationTimeout, + s.config.SupportedPortForwardProtocols) +} + +// criAdapter wraps the Runtime functions to conform to the remotecommand interfaces. +// The adapter binds the container ID to the container name argument, and the pod sandbox ID to the pod name. +type criAdapter struct { + Runtime +} + +var _ remotecommandserver.Executor = &criAdapter{} +var _ remotecommandserver.Attacher = &criAdapter{} +var _ portforward.PortForwarder = &criAdapter{} + +func (a *criAdapter) ExecInContainer(podName string, podUID types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error { + return a.Runtime.Exec(container, cmd, in, out, err, tty, resize) +} + +func (a *criAdapter) AttachContainer(podName string, podUID types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error { + return a.Runtime.Attach(container, in, out, err, tty, resize) +} + +func (a *criAdapter) PortForward(podName string, podUID types.UID, port int32, stream io.ReadWriteCloser) error { + return a.Runtime.PortForward(podName, port, stream) +} diff -Nru containerd-1.2.6/pkg/cri/util/deep_copy.go containerd-1.5.9/pkg/cri/util/deep_copy.go --- containerd-1.2.6/pkg/cri/util/deep_copy.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/deep_copy.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "encoding/json" + + "github.com/pkg/errors" +) + +// DeepCopy makes a deep copy from src into dst. +func DeepCopy(dst interface{}, src interface{}) error { + if dst == nil { + return errors.New("dst cannot be nil") + } + if src == nil { + return errors.New("src cannot be nil") + } + bytes, err := json.Marshal(src) + if err != nil { + return errors.Wrap(err, "unable to marshal src") + } + err = json.Unmarshal(bytes, dst) + if err != nil { + return errors.Wrap(err, "unable to unmarshal into dst") + } + return nil +} diff -Nru containerd-1.2.6/pkg/cri/util/deep_copy_test.go containerd-1.5.9/pkg/cri/util/deep_copy_test.go --- containerd-1.2.6/pkg/cri/util/deep_copy_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/deep_copy_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +type A struct { + String string + Int int + Strings []string + Ints map[string]int + As map[string]*A +} + +func TestCopy(t *testing.T) { + src := &A{ + String: "Hello World", + Int: 5, + Strings: []string{"A", "B"}, + Ints: map[string]int{"A": 1, "B": 2, "C": 4}, + As: map[string]*A{ + "One": {String: "2"}, + "Two": {String: "3"}, + }, + } + dst := &A{ + Strings: []string{"C"}, + Ints: map[string]int{"B": 3, "C": 4}, + As: map[string]*A{"One": {String: "1", Int: 5}}, + } + expected := &A{ + String: "Hello World", + Int: 5, + Strings: []string{"A", "B"}, + Ints: map[string]int{"A": 1, "B": 2, "C": 4}, + As: map[string]*A{ + "One": {String: "2"}, + "Two": {String: "3"}, + }, + } + assert.NotEqual(t, expected, dst) + err := DeepCopy(dst, src) + assert.NoError(t, err) + assert.Equal(t, expected, dst) +} diff -Nru containerd-1.2.6/pkg/cri/util/id.go containerd-1.5.9/pkg/cri/util/id.go --- containerd-1.2.6/pkg/cri/util/id.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/id.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "encoding/hex" + "math/rand" +) + +// GenerateID generates a random unique id. +func GenerateID() string { + b := make([]byte, 32) + rand.Read(b) + return hex.EncodeToString(b) +} diff -Nru containerd-1.2.6/pkg/cri/util/image.go containerd-1.5.9/pkg/cri/util/image.go --- containerd-1.2.6/pkg/cri/util/image.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/image.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "github.com/containerd/containerd/reference/docker" +) + +// NormalizeImageRef normalizes the image reference following the docker convention. This is added +// mainly for backward compatibility. +// The reference returned can only be either tagged or digested. For reference contains both tag +// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ +// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as +// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. +// +// Deprecated: use github.com/containerd/containerd/reference/docker.ParseDockerRef() instead +func NormalizeImageRef(ref string) (docker.Named, error) { + return docker.ParseDockerRef(ref) +} diff -Nru containerd-1.2.6/pkg/cri/util/image_test.go containerd-1.5.9/pkg/cri/util/image_test.go --- containerd-1.2.6/pkg/cri/util/image_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/image_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "testing" + + "github.com/containerd/containerd/reference" + "github.com/stretchr/testify/assert" +) + +func TestNormalizeImageRef(t *testing.T) { + for _, test := range []struct { + input string + expect string + }{ + { // has nothing + input: "busybox", + expect: "docker.io/library/busybox:latest", + }, + { // only has tag + input: "busybox:latest", + expect: "docker.io/library/busybox:latest", + }, + { // only has digest + input: "busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + expect: "docker.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + { // only has path + input: "library/busybox", + expect: "docker.io/library/busybox:latest", + }, + { // only has hostname + input: "docker.io/busybox", + expect: "docker.io/library/busybox:latest", + }, + { // has no tag + input: "docker.io/library/busybox", + expect: "docker.io/library/busybox:latest", + }, + { // has no path + input: "docker.io/busybox:latest", + expect: "docker.io/library/busybox:latest", + }, + { // has no hostname + input: "library/busybox:latest", + expect: "docker.io/library/busybox:latest", + }, + { // full reference + input: "docker.io/library/busybox:latest", + expect: "docker.io/library/busybox:latest", + }, + { // gcr reference + input: "gcr.io/library/busybox", + expect: "gcr.io/library/busybox:latest", + }, + { // both tag and digest + input: "gcr.io/library/busybox:latest@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + expect: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582", + }, + } { + t.Logf("TestCase %q", test.input) + normalized, err := NormalizeImageRef(test.input) + assert.NoError(t, err) + output := normalized.String() + assert.Equal(t, test.expect, output) + _, err = reference.Parse(output) + assert.NoError(t, err, "%q should be containerd supported reference", output) + } +} diff -Nru containerd-1.2.6/pkg/cri/util/strings.go containerd-1.5.9/pkg/cri/util/strings.go --- containerd-1.2.6/pkg/cri/util/strings.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/strings.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import "strings" + +// InStringSlice checks whether a string is inside a string slice. +// Comparison is case insensitive. +func InStringSlice(ss []string, str string) bool { + for _, s := range ss { + if strings.EqualFold(s, str) { + return true + } + } + return false +} + +// SubtractStringSlice subtracts string from string slice. +// Comparison is case insensitive. +func SubtractStringSlice(ss []string, str string) []string { + var res []string + for _, s := range ss { + if strings.EqualFold(s, str) { + continue + } + res = append(res, s) + } + return res +} + +// MergeStringSlices merges 2 string slices into one and remove duplicated elements. +func MergeStringSlices(a []string, b []string) []string { + set := map[string]struct{}{} + for _, s := range a { + set[s] = struct{}{} + } + for _, s := range b { + set[s] = struct{}{} + } + var ss []string + for s := range set { + ss = append(ss, s) + } + return ss +} diff -Nru containerd-1.2.6/pkg/cri/util/strings_test.go containerd-1.5.9/pkg/cri/util/strings_test.go --- containerd-1.2.6/pkg/cri/util/strings_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/strings_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,59 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestInStringSlice(t *testing.T) { + ss := []string{"ABC", "def", "ghi"} + + assert.True(t, InStringSlice(ss, "ABC")) + assert.True(t, InStringSlice(ss, "abc")) + assert.True(t, InStringSlice(ss, "def")) + assert.True(t, InStringSlice(ss, "DEF")) + assert.False(t, InStringSlice(ss, "hij")) + assert.False(t, InStringSlice(ss, "HIJ")) + assert.False(t, InStringSlice(nil, "HIJ")) +} + +func TestSubtractStringSlice(t *testing.T) { + ss := []string{"ABC", "def", "ghi"} + + assert.Equal(t, []string{"def", "ghi"}, SubtractStringSlice(ss, "abc")) + assert.Equal(t, []string{"def", "ghi"}, SubtractStringSlice(ss, "ABC")) + assert.Equal(t, []string{"ABC", "ghi"}, SubtractStringSlice(ss, "def")) + assert.Equal(t, []string{"ABC", "ghi"}, SubtractStringSlice(ss, "DEF")) + assert.Equal(t, []string{"ABC", "def", "ghi"}, SubtractStringSlice(ss, "hij")) + assert.Equal(t, []string{"ABC", "def", "ghi"}, SubtractStringSlice(ss, "HIJ")) + assert.Empty(t, SubtractStringSlice(nil, "hij")) + assert.Empty(t, SubtractStringSlice([]string{}, "hij")) +} + +func TestMergeStringSlices(t *testing.T) { + s1 := []string{"abc", "def", "ghi"} + s2 := []string{"def", "jkl", "mno"} + expect := []string{"abc", "def", "ghi", "jkl", "mno"} + result := MergeStringSlices(s1, s2) + assert.Len(t, result, len(expect)) + for _, s := range expect { + assert.Contains(t, result, s) + } +} diff -Nru containerd-1.2.6/pkg/cri/util/util.go containerd-1.5.9/pkg/cri/util/util.go --- containerd-1.2.6/pkg/cri/util/util.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/cri/util/util.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "time" + + "github.com/containerd/containerd/namespaces" + "golang.org/x/net/context" + + "github.com/containerd/containerd/pkg/cri/constants" +) + +// deferCleanupTimeout is the default timeout for containerd cleanup operations +// in defer. +const deferCleanupTimeout = 1 * time.Minute + +// DeferContext returns a context for containerd cleanup operations in defer. +// A default timeout is applied to avoid cleanup operation pending forever. +func DeferContext() (context.Context, context.CancelFunc) { + return context.WithTimeout(NamespacedContext(), deferCleanupTimeout) +} + +// NamespacedContext returns a context with kubernetes namespace set. +func NamespacedContext() context.Context { + return WithNamespace(context.Background()) +} + +// WithNamespace adds kubernetes namespace to the context. +func WithNamespace(ctx context.Context) context.Context { + return namespaces.WithNamespace(ctx, constants.K8sContainerdNamespace) +} diff -Nru containerd-1.2.6/pkg/dialer/dialer.go containerd-1.5.9/pkg/dialer/dialer.go --- containerd-1.2.6/pkg/dialer/dialer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/pkg/dialer/dialer.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package dialer import ( + "context" "net" "time" @@ -28,8 +29,19 @@ err error } +// ContextDialer returns a GRPC net.Conn connected to the provided address +func ContextDialer(ctx context.Context, address string) (net.Conn, error) { + if deadline, ok := ctx.Deadline(); ok { + return timeoutDialer(address, time.Until(deadline)) + } + return timeoutDialer(address, 0) +} + // Dialer returns a GRPC net.Conn connected to the provided address -func Dialer(address string, timeout time.Duration) (net.Conn, error) { +// Deprecated: use ContextDialer and grpc.WithContextDialer. +var Dialer = timeoutDialer + +func timeoutDialer(address string, timeout time.Duration) (net.Conn, error) { var ( stopC = make(chan struct{}) synC = make(chan *dialResult) diff -Nru containerd-1.2.6/pkg/dialer/dialer_windows.go containerd-1.5.9/pkg/dialer/dialer_windows.go --- containerd-1.2.6/pkg/dialer/dialer_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/pkg/dialer/dialer_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,21 +19,13 @@ import ( "net" "os" - "syscall" "time" winio "github.com/Microsoft/go-winio" ) func isNoent(err error) bool { - if err != nil { - if oerr, ok := err.(*os.PathError); ok { - if oerr.Err == syscall.ENOENT { - return true - } - } - } - return false + return os.IsNotExist(err) } func dialer(address string, timeout time.Duration) (net.Conn, error) { diff -Nru containerd-1.2.6/pkg/ioutil/read_closer.go containerd-1.5.9/pkg/ioutil/read_closer.go --- containerd-1.2.6/pkg/ioutil/read_closer.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/read_closer.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import "io" + +// writeCloseInformer wraps a reader with a close function. +type wrapReadCloser struct { + reader *io.PipeReader + writer *io.PipeWriter +} + +// NewWrapReadCloser creates a wrapReadCloser from a reader. +// NOTE(random-liu): To avoid goroutine leakage, the reader passed in +// must be eventually closed by the caller. +func NewWrapReadCloser(r io.Reader) io.ReadCloser { + pr, pw := io.Pipe() + go func() { + _, _ = io.Copy(pw, r) + pr.Close() + pw.Close() + }() + return &wrapReadCloser{ + reader: pr, + writer: pw, + } +} + +// Read reads up to len(p) bytes into p. +func (w *wrapReadCloser) Read(p []byte) (int, error) { + n, err := w.reader.Read(p) + if err == io.ErrClosedPipe { + return n, io.EOF + } + return n, err +} + +// Close closes read closer. +func (w *wrapReadCloser) Close() error { + w.reader.Close() + w.writer.Close() + return nil +} diff -Nru containerd-1.2.6/pkg/ioutil/read_closer_test.go containerd-1.5.9/pkg/ioutil/read_closer_test.go --- containerd-1.2.6/pkg/ioutil/read_closer_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/read_closer_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import ( + "bytes" + "io" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWrapReadCloser(t *testing.T) { + buf := bytes.NewBufferString("abc") + + rc := NewWrapReadCloser(buf) + dst := make([]byte, 1) + n, err := rc.Read(dst) + assert.Equal(t, 1, n) + assert.NoError(t, err) + assert.Equal(t, []byte("a"), dst) + + n, err = rc.Read(dst) + assert.Equal(t, 1, n) + assert.NoError(t, err) + assert.Equal(t, []byte("b"), dst) + + rc.Close() + n, err = rc.Read(dst) + assert.Equal(t, 0, n) + assert.Equal(t, io.EOF, err) + assert.Equal(t, []byte("b"), dst) +} diff -Nru containerd-1.2.6/pkg/ioutil/write_closer.go containerd-1.5.9/pkg/ioutil/write_closer.go --- containerd-1.2.6/pkg/ioutil/write_closer.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/write_closer.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,102 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import ( + "io" + "sync" +) + +// writeCloseInformer wraps passed in write closer with a close channel. +// Caller could wait on the close channel for the write closer to be +// closed. +type writeCloseInformer struct { + close chan struct{} + wc io.WriteCloser +} + +// NewWriteCloseInformer creates the writeCloseInformer from a write closer. +func NewWriteCloseInformer(wc io.WriteCloser) (io.WriteCloser, <-chan struct{}) { + close := make(chan struct{}) + return &writeCloseInformer{ + close: close, + wc: wc, + }, close +} + +// Write passes through the data into the internal write closer. +func (w *writeCloseInformer) Write(p []byte) (int, error) { + return w.wc.Write(p) +} + +// Close closes the internal write closer and inform the close channel. +func (w *writeCloseInformer) Close() error { + err := w.wc.Close() + close(w.close) + return err +} + +// nopWriteCloser wraps passed in writer with a nop close function. +type nopWriteCloser struct { + w io.Writer +} + +// NewNopWriteCloser creates the nopWriteCloser from a writer. +func NewNopWriteCloser(w io.Writer) io.WriteCloser { + return &nopWriteCloser{w: w} +} + +// Write passes through the data into the internal writer. +func (n *nopWriteCloser) Write(p []byte) (int, error) { + return n.w.Write(p) +} + +// Close is a nop close function. +func (n *nopWriteCloser) Close() error { + return nil +} + +// serialWriteCloser wraps a write closer and makes sure all writes +// are done in serial. +// Parallel write won't intersect with each other. Use case: +// 1) Pipe: Write content longer than PIPE_BUF. +// See http://man7.org/linux/man-pages/man7/pipe.7.html +// 2) <3.14 Linux Kernel: write is not atomic +// See http://man7.org/linux/man-pages/man2/write.2.html +type serialWriteCloser struct { + mu sync.Mutex + wc io.WriteCloser +} + +// NewSerialWriteCloser creates a SerialWriteCloser from a write closer. +func NewSerialWriteCloser(wc io.WriteCloser) io.WriteCloser { + return &serialWriteCloser{wc: wc} +} + +// Write writes a group of byte arrays in order atomically. +func (s *serialWriteCloser) Write(data []byte) (int, error) { + s.mu.Lock() + defer s.mu.Unlock() + return s.wc.Write(data) +} + +// Close closes the write closer. +func (s *serialWriteCloser) Close() error { + s.mu.Lock() + defer s.mu.Unlock() + return s.wc.Close() +} diff -Nru containerd-1.2.6/pkg/ioutil/write_closer_test.go containerd-1.5.9/pkg/ioutil/write_closer_test.go --- containerd-1.2.6/pkg/ioutil/write_closer_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/write_closer_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,108 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import ( + "io/ioutil" + "os" + "sort" + "strconv" + "strings" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWriteCloseInformer(t *testing.T) { + original := &writeCloser{} + wci, close := NewWriteCloseInformer(original) + data := "test" + + n, err := wci.Write([]byte(data)) + assert.Equal(t, len(data), n) + assert.Equal(t, data, original.buf.String()) + assert.NoError(t, err) + + select { + case <-close: + assert.Fail(t, "write closer closed") + default: + } + + wci.Close() + assert.True(t, original.closed) + + select { + case <-close: + default: + assert.Fail(t, "write closer not closed") + } +} + +func TestSerialWriteCloser(t *testing.T) { + const ( + // Test 10 times to make sure it always pass. + testCount = 10 + + goroutine = 10 + dataLen = 100000 + ) + for n := 0; n < testCount; n++ { + testData := make([][]byte, goroutine) + for i := 0; i < goroutine; i++ { + testData[i] = []byte(repeatNumber(i, dataLen) + "\n") + } + + f, err := ioutil.TempFile("", "serial-write-closer") + require.NoError(t, err) + defer os.RemoveAll(f.Name()) + defer f.Close() + wc := NewSerialWriteCloser(f) + defer wc.Close() + + // Write data in parallel + var wg sync.WaitGroup + wg.Add(goroutine) + for i := 0; i < goroutine; i++ { + go func(id int) { + n, err := wc.Write(testData[id]) + assert.NoError(t, err) + assert.Equal(t, dataLen+1, n) + wg.Done() + }(i) + } + wg.Wait() + wc.Close() + + // Check test result + content, err := ioutil.ReadFile(f.Name()) + require.NoError(t, err) + resultData := strings.Split(strings.TrimSpace(string(content)), "\n") + require.Len(t, resultData, goroutine) + sort.Strings(resultData) + for i := 0; i < goroutine; i++ { + expected := repeatNumber(i, dataLen) + assert.Equal(t, expected, resultData[i]) + } + } +} + +func repeatNumber(num, count int) string { + return strings.Repeat(strconv.Itoa(num), count) +} diff -Nru containerd-1.2.6/pkg/ioutil/writer_group.go containerd-1.5.9/pkg/ioutil/writer_group.go --- containerd-1.2.6/pkg/ioutil/writer_group.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/writer_group.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,105 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import ( + "errors" + "io" + "sync" +) + +// WriterGroup is a group of writers. Writer could be dynamically +// added and removed. +type WriterGroup struct { + mu sync.Mutex + writers map[string]io.WriteCloser + closed bool +} + +var _ io.Writer = &WriterGroup{} + +// NewWriterGroup creates an empty writer group. +func NewWriterGroup() *WriterGroup { + return &WriterGroup{ + writers: make(map[string]io.WriteCloser), + } +} + +// Add adds a writer into the group. The writer will be closed +// if the writer group is closed. +func (g *WriterGroup) Add(key string, w io.WriteCloser) { + g.mu.Lock() + defer g.mu.Unlock() + if g.closed { + w.Close() + return + } + g.writers[key] = w +} + +// Get gets a writer from the group, returns nil if the writer +// doesn't exist. +func (g *WriterGroup) Get(key string) io.WriteCloser { + g.mu.Lock() + defer g.mu.Unlock() + return g.writers[key] +} + +// Remove removes a writer from the group. +func (g *WriterGroup) Remove(key string) { + g.mu.Lock() + defer g.mu.Unlock() + w, ok := g.writers[key] + if !ok { + return + } + w.Close() + delete(g.writers, key) +} + +// Write writes data into each writer. If a writer returns error, +// it will be closed and removed from the writer group. It returns +// error if writer group is empty. +func (g *WriterGroup) Write(p []byte) (int, error) { + g.mu.Lock() + defer g.mu.Unlock() + for k, w := range g.writers { + n, err := w.Write(p) + if err == nil && len(p) == n { + continue + } + // The writer is closed or in bad state, remove it. + w.Close() + delete(g.writers, k) + } + if len(g.writers) == 0 { + return 0, errors.New("writer group is empty") + } + return len(p), nil +} + +// Close closes the writer group. Write will return error after +// closed. +func (g *WriterGroup) Close() { + g.mu.Lock() + defer g.mu.Unlock() + for _, w := range g.writers { + w.Close() + } + g.writers = nil + g.closed = true +} diff -Nru containerd-1.2.6/pkg/ioutil/writer_group_test.go containerd-1.5.9/pkg/ioutil/writer_group_test.go --- containerd-1.2.6/pkg/ioutil/writer_group_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ioutil/writer_group_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,115 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ioutil + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +type writeCloser struct { + buf bytes.Buffer + closed bool +} + +func (wc *writeCloser) Write(p []byte) (int, error) { + return wc.buf.Write(p) +} + +func (wc *writeCloser) Close() error { + wc.closed = true + return nil +} + +func TestEmptyWriterGroup(t *testing.T) { + wg := NewWriterGroup() + _, err := wg.Write([]byte("test")) + assert.Error(t, err) +} + +func TestClosedWriterGroup(t *testing.T) { + wg := NewWriterGroup() + wc := &writeCloser{} + key, data := "test key", "test data" + + wg.Add(key, wc) + + n, err := wg.Write([]byte(data)) + assert.Equal(t, len(data), n) + assert.Equal(t, data, wc.buf.String()) + assert.NoError(t, err) + + wg.Close() + assert.True(t, wc.closed) + + newWC := &writeCloser{} + wg.Add(key, newWC) + assert.True(t, newWC.closed) + + _, err = wg.Write([]byte(data)) + assert.Error(t, err) +} + +func TestAddGetRemoveWriter(t *testing.T) { + wg := NewWriterGroup() + wc1, wc2 := &writeCloser{}, &writeCloser{} + key1, key2 := "test key 1", "test key 2" + + wg.Add(key1, wc1) + _, err := wg.Write([]byte("test data 1")) + assert.NoError(t, err) + assert.Equal(t, "test data 1", wc1.buf.String()) + + wg.Add(key2, wc2) + _, err = wg.Write([]byte("test data 2")) + assert.NoError(t, err) + assert.Equal(t, "test data 1test data 2", wc1.buf.String()) + assert.Equal(t, "test data 2", wc2.buf.String()) + + assert.Equal(t, wc1, wg.Get(key1)) + + wg.Remove(key1) + _, err = wg.Write([]byte("test data 3")) + assert.NoError(t, err) + assert.Equal(t, "test data 1test data 2", wc1.buf.String()) + assert.Equal(t, "test data 2test data 3", wc2.buf.String()) + + assert.Equal(t, nil, wg.Get(key1)) + + wg.Close() +} + +func TestReplaceWriter(t *testing.T) { + wg := NewWriterGroup() + wc1, wc2 := &writeCloser{}, &writeCloser{} + key := "test-key" + + wg.Add(key, wc1) + _, err := wg.Write([]byte("test data 1")) + assert.NoError(t, err) + assert.Equal(t, "test data 1", wc1.buf.String()) + + wg.Add(key, wc2) + _, err = wg.Write([]byte("test data 2")) + assert.NoError(t, err) + assert.Equal(t, "test data 1", wc1.buf.String()) + assert.Equal(t, "test data 2", wc2.buf.String()) + + wg.Close() +} diff -Nru containerd-1.2.6/pkg/netns/netns_linux.go containerd-1.5.9/pkg/netns/netns_linux.go --- containerd-1.2.6/pkg/netns/netns_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/netns/netns_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,218 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Copyright 2018 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software + +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package netns + +import ( + "crypto/rand" + "fmt" + "os" + "path" + "runtime" + "sync" + + "github.com/containerd/containerd/mount" + cnins "github.com/containernetworking/plugins/pkg/ns" + "github.com/moby/sys/symlink" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// Some of the following functions are migrated from +// https://github.com/containernetworking/plugins/blob/master/pkg/testutils/netns_linux.go + +// newNS creates a new persistent (bind-mounted) network namespace and returns the +// path to the network namespace. +func newNS(baseDir string) (nsPath string, err error) { + b := make([]byte, 16) + if _, err := rand.Reader.Read(b); err != nil { + return "", errors.Wrap(err, "failed to generate random netns name") + } + + // Create the directory for mounting network namespaces + // This needs to be a shared mountpoint in case it is mounted in to + // other namespaces (containers) + if err := os.MkdirAll(baseDir, 0755); err != nil { + return "", err + } + + // create an empty file at the mount point + nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) + nsPath = path.Join(baseDir, nsName) + mountPointFd, err := os.Create(nsPath) + if err != nil { + return "", err + } + mountPointFd.Close() + + defer func() { + // Ensure the mount point is cleaned up on errors + if err != nil { + os.RemoveAll(nsPath) // nolint: errcheck + } + }() + + var wg sync.WaitGroup + wg.Add(1) + + // do namespace work in a dedicated goroutine, so that we can safely + // Lock/Unlock OSThread without upsetting the lock/unlock state of + // the caller of this function + go (func() { + defer wg.Done() + runtime.LockOSThread() + // Don't unlock. By not unlocking, golang will kill the OS thread when the + // goroutine is done (for go1.10+) + + var origNS cnins.NetNS + origNS, err = cnins.GetNS(getCurrentThreadNetNSPath()) + if err != nil { + return + } + defer origNS.Close() + + // create a new netns on the current thread + err = unix.Unshare(unix.CLONE_NEWNET) + if err != nil { + return + } + + // Put this thread back to the orig ns, since it might get reused (pre go1.10) + defer origNS.Set() // nolint: errcheck + + // bind mount the netns from the current thread (from /proc) onto the + // mount point. This causes the namespace to persist, even when there + // are no threads in the ns. + err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "") + if err != nil { + err = errors.Wrapf(err, "failed to bind mount ns at %s", nsPath) + } + })() + wg.Wait() + + if err != nil { + return "", errors.Wrap(err, "failed to create namespace") + } + + return nsPath, nil +} + +// unmountNS unmounts the NS held by the netns object. unmountNS is idempotent. +func unmountNS(path string) error { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return nil + } + return errors.Wrap(err, "failed to stat netns") + } + path, err := symlink.FollowSymlinkInScope(path, "/") + if err != nil { + return errors.Wrap(err, "failed to follow symlink") + } + if err := mount.Unmount(path, unix.MNT_DETACH); err != nil && !os.IsNotExist(err) { + return errors.Wrap(err, "failed to umount netns") + } + if err := os.RemoveAll(path); err != nil { + return errors.Wrap(err, "failed to remove netns") + } + return nil +} + +// getCurrentThreadNetNSPath copied from pkg/ns +func getCurrentThreadNetNSPath() string { + // /proc/self/ns/net returns the namespace of the main thread, not + // of whatever thread this goroutine is running on. Make sure we + // use the thread's net namespace since the thread is switching around + return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()) +} + +// NetNS holds network namespace. +type NetNS struct { + path string +} + +// NewNetNS creates a network namespace. +func NewNetNS(baseDir string) (*NetNS, error) { + path, err := newNS(baseDir) + if err != nil { + return nil, errors.Wrap(err, "failed to setup netns") + } + return &NetNS{path: path}, nil +} + +// LoadNetNS loads existing network namespace. +func LoadNetNS(path string) *NetNS { + return &NetNS{path: path} +} + +// Remove removes network namespace. Remove is idempotent, meaning it might +// be invoked multiple times and provides consistent result. +func (n *NetNS) Remove() error { + return unmountNS(n.path) +} + +// Closed checks whether the network namespace has been closed. +func (n *NetNS) Closed() (bool, error) { + ns, err := cnins.GetNS(n.path) + if err != nil { + if _, ok := err.(cnins.NSPathNotExistErr); ok { + // The network namespace has already been removed. + return true, nil + } + if _, ok := err.(cnins.NSPathNotNSErr); ok { + // The network namespace is not mounted, remove it. + if err := os.RemoveAll(n.path); err != nil { + return false, errors.Wrap(err, "remove netns") + } + return true, nil + } + return false, errors.Wrap(err, "get netns fd") + } + if err := ns.Close(); err != nil { + return false, errors.Wrap(err, "close netns fd") + } + return false, nil +} + +// GetPath returns network namespace path for sandbox container +func (n *NetNS) GetPath() string { + return n.path +} + +// Do runs a function in the network namespace. +func (n *NetNS) Do(f func(cnins.NetNS) error) error { + ns, err := cnins.GetNS(n.path) + if err != nil { + return errors.Wrap(err, "get netns fd") + } + defer ns.Close() // nolint: errcheck + return ns.Do(f) +} diff -Nru containerd-1.2.6/pkg/netns/netns_other.go containerd-1.5.9/pkg/netns/netns_other.go --- containerd-1.2.6/pkg/netns/netns_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/netns/netns_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,58 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package netns + +import ( + "github.com/pkg/errors" +) + +var errNotImplementedOnUnix = errors.New("not implemented on unix") + +// NetNS holds network namespace. +type NetNS struct { + path string +} + +// NewNetNS creates a network namespace. +func NewNetNS(baseDir string) (*NetNS, error) { + return nil, errNotImplementedOnUnix +} + +// LoadNetNS loads existing network namespace. +func LoadNetNS(path string) *NetNS { + return &NetNS{path: path} +} + +// Remove removes network namespace. Remove is idempotent, meaning it might +// be invoked multiple times and provides consistent result. +func (n *NetNS) Remove() error { + return errNotImplementedOnUnix +} + +// Closed checks whether the network namespace has been closed. +func (n *NetNS) Closed() (bool, error) { + return false, errNotImplementedOnUnix +} + +// GetPath returns network namespace path for sandbox container +func (n *NetNS) GetPath() string { + return n.path +} + +// NOTE: Do function is not supported. diff -Nru containerd-1.2.6/pkg/netns/netns_windows.go containerd-1.5.9/pkg/netns/netns_windows.go --- containerd-1.2.6/pkg/netns/netns_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/netns/netns_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,78 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package netns + +import "github.com/Microsoft/hcsshim/hcn" + +// NetNS holds network namespace for sandbox +type NetNS struct { + path string +} + +// NewNetNS creates a network namespace for the sandbox +func NewNetNS(baseDir string) (*NetNS, error) { + temp := hcn.HostComputeNamespace{} + hcnNamespace, err := temp.Create() + if err != nil { + return nil, err + } + + return &NetNS{path: hcnNamespace.Id}, nil +} + +// LoadNetNS loads existing network namespace. +func LoadNetNS(path string) *NetNS { + return &NetNS{path: path} +} + +// Remove removes network namespace if it exists and not closed. Remove is idempotent, +// meaning it might be invoked multiple times and provides consistent result. +func (n *NetNS) Remove() error { + hcnNamespace, err := hcn.GetNamespaceByID(n.path) + if err != nil { + if hcn.IsNotFoundError(err) { + return nil + } + return err + } + err = hcnNamespace.Delete() + if err == nil || hcn.IsNotFoundError(err) { + return nil + } + return err +} + +// Closed checks whether the network namespace has been closed. +func (n *NetNS) Closed() (bool, error) { + _, err := hcn.GetNamespaceByID(n.path) + if err == nil { + return false, nil + } + if hcn.IsNotFoundError(err) { + return true, nil + } + return false, err +} + +// GetPath returns network namespace path for sandbox container +func (n *NetNS) GetPath() string { + return n.path +} + +// NOTE: Do function is not supported. diff -Nru containerd-1.2.6/pkg/oom/oom.go containerd-1.5.9/pkg/oom/oom.go --- containerd-1.2.6/pkg/oom/oom.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/oom/oom.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,30 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package oom + +import ( + "context" +) + +// Watcher watches OOM events +type Watcher interface { + Close() error + Run(ctx context.Context) + Add(id string, cg interface{}) error +} diff -Nru containerd-1.2.6/pkg/oom/v1/v1.go containerd-1.5.9/pkg/oom/v1/v1.go --- containerd-1.2.6/pkg/oom/v1/v1.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/oom/v1/v1.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,141 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "context" + "sync" + + "github.com/containerd/cgroups" + eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/pkg/oom" + "github.com/containerd/containerd/runtime" + "github.com/containerd/containerd/runtime/v2/shim" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +// New returns an epoll implementation that listens to OOM events +// from a container's cgroups. +func New(publisher shim.Publisher) (oom.Watcher, 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 +} + +// epoller implementation for handling OOM events from a container's cgroup +type epoller struct { + mu sync.Mutex + + fd int + publisher shim.Publisher + set map[uintptr]*item +} + +type item struct { + id string + cg cgroups.Cgroup +} + +// Close the epoll fd +func (e *epoller) Close() error { + return unix.Close(e.fd) +} + +// Run the epoll loop +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 { + continue + } + logrus.WithError(err).Error("cgroups: epoll wait") + } + for i := 0; i < n; i++ { + e.process(ctx, uintptr(events[i].Fd)) + } + } + } +} + +// Add cgroups.Cgroup to the epoll monitor +func (e *epoller) Add(id string, cgx interface{}) error { + cg, ok := cgx.(cgroups.Cgroup) + if !ok { + return errors.Errorf("expected cgroups.Cgroup, got: %T", cgx) + } + 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, &eventstypes.TaskOOM{ + ContainerID: i.id, + }); err != nil { + logrus.WithError(err).Error("publish OOM event") + } +} + +func flush(fd uintptr) error { + var buf [8]byte + _, err := unix.Read(int(fd), buf[:]) + return err +} diff -Nru containerd-1.2.6/pkg/oom/v2/v2.go containerd-1.5.9/pkg/oom/v2/v2.go --- containerd-1.2.6/pkg/oom/v2/v2.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/oom/v2/v2.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,113 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + + cgroupsv2 "github.com/containerd/cgroups/v2" + eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/pkg/oom" + "github.com/containerd/containerd/runtime" + "github.com/containerd/containerd/runtime/v2/shim" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// New returns an implementation that listens to OOM events +// from a container's cgroups. +func New(publisher shim.Publisher) (oom.Watcher, error) { + return &watcher{ + itemCh: make(chan item), + publisher: publisher, + }, nil +} + +// watcher implementation for handling OOM events from a container's cgroup +type watcher struct { + itemCh chan item + publisher shim.Publisher +} + +type item struct { + id string + ev cgroupsv2.Event + err error +} + +// Close closes the watcher +func (w *watcher) Close() error { + return nil +} + +// Run the loop +func (w *watcher) Run(ctx context.Context) { + lastOOMMap := make(map[string]uint64) // key: id, value: ev.OOM + for { + select { + case <-ctx.Done(): + w.Close() + return + case i := <-w.itemCh: + if i.err != nil { + delete(lastOOMMap, i.id) + continue + } + lastOOM := lastOOMMap[i.id] + if i.ev.OOM > lastOOM { + if err := w.publisher.Publish(ctx, runtime.TaskOOMEventTopic, &eventstypes.TaskOOM{ + ContainerID: i.id, + }); err != nil { + logrus.WithError(err).Error("publish OOM event") + } + } + if i.ev.OOM > 0 { + lastOOMMap[i.id] = i.ev.OOM + } + } + } +} + +// Add cgroups.Cgroup to the epoll monitor +func (w *watcher) Add(id string, cgx interface{}) error { + cg, ok := cgx.(*cgroupsv2.Manager) + if !ok { + return errors.Errorf("expected *cgroupsv2.Manager, got: %T", cgx) + } + // FIXME: cgroupsv2.Manager does not support closing eventCh routine currently. + // The routine shuts down when an error happens, mostly when the cgroup is deleted. + eventCh, errCh := cg.EventChan() + go func() { + for { + i := item{id: id} + select { + case ev := <-eventCh: + i.ev = ev + w.itemCh <- i + case err := <-errCh: + i.err = err + w.itemCh <- i + // we no longer get any event/err when we got an err + logrus.WithError(err).Warn("error from *cgroupsv2.Manager.EventChan") + return + } + } + }() + return nil +} diff -Nru containerd-1.2.6/pkg/os/mount_linux.go containerd-1.5.9/pkg/os/mount_linux.go --- containerd-1.2.6/pkg/os/mount_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/mount_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "github.com/containerd/containerd/mount" + "golang.org/x/sys/unix" +) + +// Mount will call unix.Mount to mount the file. +func (RealOS) Mount(source string, target string, fstype string, flags uintptr, data string) error { + return unix.Mount(source, target, fstype, flags, data) +} + +// Unmount will call Unmount to unmount the file. +func (RealOS) Unmount(target string) error { + return mount.Unmount(target, unix.MNT_DETACH) +} + +// LookupMount gets mount info of a given path. +func (RealOS) LookupMount(path string) (mount.Info, error) { + return mount.Lookup(path) +} diff -Nru containerd-1.2.6/pkg/os/mount_other.go containerd-1.5.9/pkg/os/mount_other.go --- containerd-1.2.6/pkg/os/mount_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/mount_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import "github.com/containerd/containerd/mount" + +// LookupMount gets mount info of a given path. +func (RealOS) LookupMount(path string) (mount.Info, error) { + return mount.Lookup(path) +} diff -Nru containerd-1.2.6/pkg/os/mount_unix.go containerd-1.5.9/pkg/os/mount_unix.go --- containerd-1.2.6/pkg/os/mount_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/mount_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +// +build !windows,!linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "github.com/containerd/containerd/mount" +) + +// Mount will call unix.Mount to mount the file. +func (RealOS) Mount(source string, target string, fstype string, flags uintptr, data string) error { + return mount.ErrNotImplementOnUnix +} + +// Unmount will call Unmount to unmount the file. +func (RealOS) Unmount(target string) error { + return mount.Unmount(target, 0) +} diff -Nru containerd-1.2.6/pkg/os/os.go containerd-1.5.9/pkg/os/os.go --- containerd-1.2.6/pkg/os/os.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/os.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,89 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "io" + "io/ioutil" + "os" + + "github.com/moby/sys/symlink" +) + +// OS collects system level operations that need to be mocked out +// during tests. +type OS interface { + MkdirAll(path string, perm os.FileMode) error + RemoveAll(path string) error + Stat(name string) (os.FileInfo, error) + ResolveSymbolicLink(name string) (string, error) + FollowSymlinkInScope(path, scope string) (string, error) + CopyFile(src, dest string, perm os.FileMode) error + WriteFile(filename string, data []byte, perm os.FileMode) error + Hostname() (string, error) +} + +// RealOS is used to dispatch the real system level operations. +type RealOS struct{} + +// MkdirAll will call os.MkdirAll to create a directory. +func (RealOS) MkdirAll(path string, perm os.FileMode) error { + return os.MkdirAll(path, perm) +} + +// RemoveAll will call os.RemoveAll to remove the path and its children. +func (RealOS) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +// Stat will call os.Stat to get the status of the given file. +func (RealOS) Stat(name string) (os.FileInfo, error) { + return os.Stat(name) +} + +// FollowSymlinkInScope will call symlink.FollowSymlinkInScope. +func (RealOS) FollowSymlinkInScope(path, scope string) (string, error) { + return symlink.FollowSymlinkInScope(path, scope) +} + +// CopyFile will copy src file to dest file +func (RealOS) CopyFile(src, dest string, perm os.FileMode) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + + out, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, in) + return err +} + +// WriteFile will call ioutil.WriteFile to write data into a file. +func (RealOS) WriteFile(filename string, data []byte, perm os.FileMode) error { + return ioutil.WriteFile(filename, data, perm) +} + +// Hostname will call os.Hostname to get the hostname of the host. +func (RealOS) Hostname() (string, error) { + return os.Hostname() +} diff -Nru containerd-1.2.6/pkg/os/os_unix.go containerd-1.5.9/pkg/os/os_unix.go --- containerd-1.2.6/pkg/os/os_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/os_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "os" + "path/filepath" + + "github.com/containerd/containerd/mount" +) + +// UNIX collects unix system level operations that need to be +// mocked out during tests. +type UNIX interface { + Mount(source string, target string, fstype string, flags uintptr, data string) error + Unmount(target string) error + LookupMount(path string) (mount.Info, error) +} + +// ResolveSymbolicLink will follow any symbolic links +func (RealOS) ResolveSymbolicLink(path string) (string, error) { + info, err := os.Lstat(path) + if err != nil { + return "", err + } + if info.Mode()&os.ModeSymlink != os.ModeSymlink { + return path, nil + } + return filepath.EvalSymlinks(path) +} diff -Nru containerd-1.2.6/pkg/os/os_windows.go containerd-1.5.9/pkg/os/os_windows.go --- containerd-1.2.6/pkg/os/os_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/os_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,180 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "os" + "strings" + "sync" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +// openPath takes a path, opens it, and returns the resulting handle. +// It works for both file and directory paths. +// +// We are not able to use builtin Go functionality for opening a directory path: +// - os.Open on a directory returns a os.File where Fd() is a search handle from FindFirstFile. +// - syscall.Open does not provide a way to specify FILE_FLAG_BACKUP_SEMANTICS, which is needed to +// open a directory. +// We could use os.Open if the path is a file, but it's easier to just use the same code for both. +// Therefore, we call windows.CreateFile directly. +func openPath(path string) (windows.Handle, error) { + u16, err := windows.UTF16PtrFromString(path) + if err != nil { + return 0, err + } + h, err := windows.CreateFile( + u16, + 0, + windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, + nil, + windows.OPEN_EXISTING, + windows.FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory handle. + 0) + if err != nil { + return 0, &os.PathError{ + Op: "CreateFile", + Path: path, + Err: err, + } + } + return h, nil +} + +// GetFinalPathNameByHandle flags. +//nolint:golint +const ( + cFILE_NAME_OPENED = 0x8 + + cVOLUME_NAME_DOS = 0x0 + cVOLUME_NAME_GUID = 0x1 +) + +var pool = sync.Pool{ + New: func() interface{} { + // Size of buffer chosen somewhat arbitrarily to accommodate a large number of path strings. + // MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310. + b := make([]uint16, 310) + return &b + }, +} + +// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle +// with the given handle and flags. It transparently takes care of creating a buffer of the +// correct size for the call. +func getFinalPathNameByHandle(h windows.Handle, flags uint32) (string, error) { + b := *(pool.Get().(*[]uint16)) + defer func() { pool.Put(&b) }() + for { + n, err := windows.GetFinalPathNameByHandle(h, &b[0], uint32(len(b)), flags) + if err != nil { + return "", err + } + // If the buffer wasn't large enough, n will be the total size needed (including null terminator). + // Resize and try again. + if n > uint32(len(b)) { + b = make([]uint16, n) + continue + } + // If the buffer is large enough, n will be the size not including the null terminator. + // Convert to a Go string and return. + return string(utf16.Decode(b[:n])), nil + } +} + +// resolvePath implements path resolution for Windows. It attempts to return the "real" path to the +// file or directory represented by the given path. +// The resolution works by using the Windows API GetFinalPathNameByHandle, which takes a handle and +// returns the final path to that file. +func resolvePath(path string) (string, error) { + h, err := openPath(path) + if err != nil { + return "", err + } + defer windows.CloseHandle(h) + + // We use the Windows API GetFinalPathNameByHandle to handle path resolution. GetFinalPathNameByHandle + // returns a resolved path name for a file or directory. The returned path can be in several different + // formats, based on the flags passed. There are several goals behind the design here: + // - Do as little manual path manipulation as possible. Since Windows path formatting can be quite + // complex, we try to just let the Windows APIs handle that for us. + // - Retain as much compatibility with existing Go path functions as we can. In particular, we try to + // ensure paths returned from resolvePath can be passed to EvalSymlinks. + // + // First, we query for the VOLUME_NAME_GUID path of the file. This will return a path in the form + // "\\?\Volume{8a25748f-cf34-4ac6-9ee2-c89400e886db}\dir\file.txt". If the path is a UNC share + // (e.g. "\\server\share\dir\file.txt"), then the VOLUME_NAME_GUID query will fail with ERROR_PATH_NOT_FOUND. + // In this case, we will next try a VOLUME_NAME_DOS query. This query will return a path for a UNC share + // in the form "\\?\UNC\server\share\dir\file.txt". This path will work with most functions, but EvalSymlinks + // fails on it. Therefore, we rewrite the path to the form "\\server\share\dir\file.txt" before returning it. + // This path rewrite may not be valid in all cases (see the notes in the next paragraph), but those should + // be very rare edge cases, and this case wouldn't have worked with EvalSymlinks anyways. + // + // The "\\?\" prefix indicates that no path parsing or normalization should be performed by Windows. + // Instead the path is passed directly to the object manager. The lack of parsing means that "." and ".." are + // interpreted literally and "\"" must be used as a path separator. Additionally, because normalization is + // not done, certain paths can only be represented in this format. For instance, "\\?\C:\foo." (with a trailing .) + // cannot be written as "C:\foo.", because path normalization will remove the trailing ".". + // + // We use FILE_NAME_OPENED instead of FILE_NAME_NORMALIZED, as FILE_NAME_NORMALIZED can fail on some + // UNC paths based on access restrictions. The additional normalization done is also quite minimal in + // most cases. + // + // Querying for VOLUME_NAME_DOS first instead of VOLUME_NAME_GUID would yield a "nicer looking" path in some cases. + // For instance, it could return "\\?\C:\dir\file.txt" instead of "\\?\Volume{8a25748f-cf34-4ac6-9ee2-c89400e886db}\dir\file.txt". + // However, we query for VOLUME_NAME_GUID first for two reasons: + // - The volume GUID path is more stable. A volume's mount point can change when it is remounted, but its + // volume GUID should not change. + // - If the volume is mounted at a non-drive letter path (e.g. mounted to "C:\mnt"), then VOLUME_NAME_DOS + // will return the mount path. EvalSymlinks fails on a path like this due to a bug. + // + // References: + // - GetFinalPathNameByHandle: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea + // - Naming Files, Paths, and Namespaces: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // - Naming a Volume: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-volume + + rPath, err := getFinalPathNameByHandle(h, cFILE_NAME_OPENED|cVOLUME_NAME_GUID) + if err == windows.ERROR_PATH_NOT_FOUND { + // ERROR_PATH_NOT_FOUND is returned from the VOLUME_NAME_GUID query if the path is a + // network share (UNC path). In this case, query for the DOS name instead, then translate + // the returned path to make it more palatable to other path functions. + rPath, err = getFinalPathNameByHandle(h, cFILE_NAME_OPENED|cVOLUME_NAME_DOS) + if err != nil { + return "", err + } + if strings.HasPrefix(rPath, `\\?\UNC\`) { + // Convert \\?\UNC\server\share -> \\server\share. The \\?\UNC syntax does not work with + // some Go filepath functions such as EvalSymlinks. In the future if other components + // move away from EvalSymlinks and use GetFinalPathNameByHandle instead, we could remove + // this path munging. + rPath = `\\` + rPath[len(`\\?\UNC\`):] + } + } else if err != nil { + return "", err + } + return rPath, nil +} + +// ResolveSymbolicLink will follow any symbolic links +func (RealOS) ResolveSymbolicLink(path string) (string, error) { + // filepath.EvalSymlinks does not work very well on Windows, so instead we resolve the path + // via resolvePath which uses GetFinalPathNameByHandle. This returns either a path prefixed with `\\?\`, + // or a remote share path in the form \\server\share. These should work with most Go and Windows APIs. + return resolvePath(path) +} diff -Nru containerd-1.2.6/pkg/os/os_windows_test.go containerd-1.5.9/pkg/os/os_windows_test.go --- containerd-1.2.6/pkg/os/os_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/os_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,258 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package os + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "syscall" + "testing" + + "github.com/Microsoft/go-winio/vhd" + "github.com/Microsoft/hcsshim/computestorage" + "github.com/Microsoft/hcsshim/osversion" + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" +) + +// Getting build number via osversion.Build() requires the program to be properly manifested, which +// requires importing `github.com/Microsoft/hcsshim/test/functional/manifest`, which is a dependency +// we want to avoid here. Instead, since this is just test code, simply parse the build number from +// the registry. +func getWindowsBuildNumber() (int, error) { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) + if err != nil { + return 0, fmt.Errorf("read CurrentVersion reg key: %s", err) + } + defer k.Close() + buildNumStr, _, err := k.GetStringValue("CurrentBuild") + if err != nil { + return 0, fmt.Errorf("read CurrentBuild reg value: %s", err) + } + buildNum, err := strconv.Atoi(buildNumStr) + if err != nil { + return 0, err + } + return buildNum, nil +} + +func makeSymlink(t *testing.T, oldName string, newName string) { + if err := os.Symlink(oldName, newName); err != nil { + t.Fatalf("creating symlink: %s", err) + } +} + +func getVolumeGUIDPath(t *testing.T, path string) string { + h, err := openPath(path) + if err != nil { + t.Fatal(err) + } + defer windows.CloseHandle(h) + final, err := getFinalPathNameByHandle(h, cFILE_NAME_OPENED|cVOLUME_NAME_GUID) + if err != nil { + t.Fatal(err) + } + return final +} + +func openDisk(path string) (windows.Handle, error) { + u16, err := windows.UTF16PtrFromString(path) + if err != nil { + return 0, err + } + h, err := windows.CreateFile( + u16, + windows.GENERIC_READ|windows.GENERIC_WRITE, + windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, + nil, + windows.OPEN_EXISTING, + windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_NO_BUFFERING, + 0) + if err != nil { + return 0, &os.PathError{ + Op: "CreateFile", + Path: path, + Err: err, + } + } + return h, nil +} + +func formatVHD(vhdHandle windows.Handle) error { + h := vhdHandle + // Pre-19H1 HcsFormatWritableLayerVhd expects a disk handle. + // On newer builds it expects a VHD handle instead. + // Open a handle to the VHD's disk object if needed. + build, err := getWindowsBuildNumber() + if err != nil { + return err + } + if build < osversion.V19H1 { + diskPath, err := vhd.GetVirtualDiskPhysicalPath(syscall.Handle(h)) + if err != nil { + return err + } + diskHandle, err := openDisk(diskPath) + if err != nil { + return err + } + defer windows.CloseHandle(diskHandle) + h = diskHandle + } + // Formatting a disk directly in Windows is a pain, so we use FormatWritableLayerVhd to do it. + // It has a side effect of creating a sandbox directory on the formatted volume, but it's safe + // to just ignore that for our purposes here. + if err := computestorage.FormatWritableLayerVhd(context.Background(), h); err != nil { + return err + } + return nil +} + +// Creates a VHD with a NTFS volume. Returns the volume path. +func setupVHDVolume(t *testing.T, vhdPath string) string { + vhdHandle, err := vhd.CreateVirtualDisk(vhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, &vhd.CreateVirtualDiskParameters{ + Version: 2, + Version2: vhd.CreateVersion2{ + MaximumSize: 5 * 1024 * 1024 * 1024, // 5GB, thin provisioned + BlockSizeInBytes: 1 * 1024 * 1024, // 1MB + }, + }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + windows.CloseHandle(windows.Handle(vhdHandle)) + }) + if err := vhd.AttachVirtualDisk(vhdHandle, vhd.AttachVirtualDiskFlagNone, &vhd.AttachVirtualDiskParameters{Version: 1}); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + if err := vhd.DetachVirtualDisk(vhdHandle); err != nil { + t.Fatal(err) + } + }) + if err := formatVHD(windows.Handle(vhdHandle)); err != nil { + t.Fatalf("failed to format VHD: %s", err) + } + // Get the path for the volume that was just created on the disk. + volumePath, err := computestorage.GetLayerVhdMountPath(context.Background(), windows.Handle(vhdHandle)) + if err != nil { + t.Fatal(err) + } + return volumePath +} + +func writeFile(t *testing.T, path string, content []byte) { + if err := ioutil.WriteFile(path, content, 0644); err != nil { + t.Fatal(err) + } +} + +func mountVolume(t *testing.T, volumePath string, mountPoint string) { + // Create the mount point directory. + if err := os.Mkdir(mountPoint, 0644); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + if err := os.Remove(mountPoint); err != nil { + t.Fatal(err) + } + }) + // Volume path must end in a slash. + if !strings.HasSuffix(volumePath, `\`) { + volumePath += `\` + } + volumePathU16, err := windows.UTF16PtrFromString(volumePath) + if err != nil { + t.Fatal(err) + } + // Mount point must end in a slash. + if !strings.HasSuffix(mountPoint, `\`) { + mountPoint += `\` + } + mountPointU16, err := windows.UTF16PtrFromString(mountPoint) + if err != nil { + t.Fatal(err) + } + if err := windows.SetVolumeMountPoint(mountPointU16, volumePathU16); err != nil { + t.Fatalf("failed to mount %s onto %s: %s", volumePath, mountPoint, err) + } + t.Cleanup(func() { + if err := windows.DeleteVolumeMountPoint(mountPointU16); err != nil { + t.Fatalf("failed to delete mount on %s: %s", mountPoint, err) + } + }) +} + +func TestResolvePath(t *testing.T) { + // Set up some data to be used by the test cases. + volumePathC := getVolumeGUIDPath(t, `C:\`) + dir := t.TempDir() + + makeSymlink(t, `C:\windows`, filepath.Join(dir, "lnk1")) + makeSymlink(t, `\\localhost\c$\windows`, filepath.Join(dir, "lnk2")) + + volumePathVHD1 := setupVHDVolume(t, filepath.Join(dir, "foo.vhdx")) + writeFile(t, filepath.Join(volumePathVHD1, "data.txt"), []byte("test content 1")) + makeSymlink(t, filepath.Join(volumePathVHD1, "data.txt"), filepath.Join(dir, "lnk3")) + + volumePathVHD2 := setupVHDVolume(t, filepath.Join(dir, "bar.vhdx")) + writeFile(t, filepath.Join(volumePathVHD2, "data.txt"), []byte("test content 2")) + makeSymlink(t, filepath.Join(volumePathVHD2, "data.txt"), filepath.Join(dir, "lnk4")) + mountVolume(t, volumePathVHD2, filepath.Join(dir, "mnt")) + + for _, tc := range []struct { + input string + expected string + description string + }{ + {`C:\windows`, volumePathC + `Windows`, "local path"}, + {filepath.Join(dir, "lnk1"), volumePathC + `Windows`, "symlink to local path"}, + {`\\localhost\c$\windows`, `\\localhost\c$\windows`, "UNC path"}, + {filepath.Join(dir, "lnk2"), `\\localhost\c$\windows`, "symlink to UNC path"}, + {filepath.Join(volumePathVHD1, "data.txt"), filepath.Join(volumePathVHD1, "data.txt"), "volume with no mount point"}, + {filepath.Join(dir, "lnk3"), filepath.Join(volumePathVHD1, "data.txt"), "symlink to volume with no mount point"}, + {filepath.Join(dir, "mnt", "data.txt"), filepath.Join(volumePathVHD2, "data.txt"), "volume with mount point"}, + {filepath.Join(dir, "lnk4"), filepath.Join(volumePathVHD2, "data.txt"), "symlink to volume with mount point"}, + } { + t.Run(tc.description, func(t *testing.T) { + actual, err := resolvePath(tc.input) + if err != nil { + t.Fatalf("resolvePath should return no error, but %v", err) + } + if actual != tc.expected { + t.Fatalf("expected %v but got %v", tc.expected, actual) + } + // Make sure EvalSymlinks works with the resolved path, as an extra safety measure. + p, err := filepath.EvalSymlinks(actual) + if err != nil { + t.Fatalf("EvalSymlinks should return no error, but %v", err) + } + // As an extra-extra safety, check that resolvePath(x) == EvalSymlinks(resolvePath(x)). + // EvalSymlinks normalizes UNC path casing, but resolvePath doesn't, so compare with + // case-insensitivity here. + if !strings.EqualFold(actual, p) { + t.Fatalf("EvalSymlinks should resolve to the same path. Expected %v but got %v", actual, p) + } + }) + } +} diff -Nru containerd-1.2.6/pkg/os/testing/fake_os.go containerd-1.5.9/pkg/os/testing/fake_os.go --- containerd-1.2.6/pkg/os/testing/fake_os.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/testing/fake_os.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,254 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testing + +import ( + "os" + "sync" + + containerdmount "github.com/containerd/containerd/mount" + + osInterface "github.com/containerd/containerd/pkg/os" +) + +// CalledDetail is the struct contains called function name and arguments. +type CalledDetail struct { + // Name of the function called. + Name string + // Arguments of the function called. + Arguments []interface{} +} + +// FakeOS mocks out certain OS calls to avoid perturbing the filesystem +// If a member of the form `*Fn` is set, that function will be called in place +// of the real call. +type FakeOS struct { + sync.Mutex + MkdirAllFn func(string, os.FileMode) error + RemoveAllFn func(string) error + StatFn func(string) (os.FileInfo, error) + ResolveSymbolicLinkFn func(string) (string, error) + FollowSymlinkInScopeFn func(string, string) (string, error) + CopyFileFn func(string, string, os.FileMode) error + WriteFileFn func(string, []byte, os.FileMode) error + MountFn func(source string, target string, fstype string, flags uintptr, data string) error + UnmountFn func(target string) error + LookupMountFn func(path string) (containerdmount.Info, error) + HostnameFn func() (string, error) + calls []CalledDetail + errors map[string]error +} + +var _ osInterface.OS = &FakeOS{} + +// getError get error for call +func (f *FakeOS) getError(op string) error { + f.Lock() + defer f.Unlock() + err, ok := f.errors[op] + if ok { + delete(f.errors, op) + return err + } + return nil +} + +// InjectError inject error for call +func (f *FakeOS) InjectError(fn string, err error) { + f.Lock() + defer f.Unlock() + f.errors[fn] = err +} + +// InjectErrors inject errors for calls +func (f *FakeOS) InjectErrors(errs map[string]error) { + f.Lock() + defer f.Unlock() + for fn, err := range errs { + f.errors[fn] = err + } +} + +// ClearErrors clear errors for call +func (f *FakeOS) ClearErrors() { + f.Lock() + defer f.Unlock() + f.errors = make(map[string]error) +} + +func (f *FakeOS) appendCalls(name string, args ...interface{}) { + f.Lock() + defer f.Unlock() + f.calls = append(f.calls, CalledDetail{Name: name, Arguments: args}) +} + +// GetCalls get detail of calls. +func (f *FakeOS) GetCalls() []CalledDetail { + f.Lock() + defer f.Unlock() + return append([]CalledDetail{}, f.calls...) +} + +// NewFakeOS creates a FakeOS. +func NewFakeOS() *FakeOS { + return &FakeOS{ + errors: make(map[string]error), + } +} + +// MkdirAll is a fake call that invokes MkdirAllFn or just returns nil. +func (f *FakeOS) MkdirAll(path string, perm os.FileMode) error { + f.appendCalls("MkdirAll", path, perm) + if err := f.getError("MkdirAll"); err != nil { + return err + } + + if f.MkdirAllFn != nil { + return f.MkdirAllFn(path, perm) + } + return nil +} + +// RemoveAll is a fake call that invokes RemoveAllFn or just returns nil. +func (f *FakeOS) RemoveAll(path string) error { + f.appendCalls("RemoveAll", path) + if err := f.getError("RemoveAll"); err != nil { + return err + } + + if f.RemoveAllFn != nil { + return f.RemoveAllFn(path) + } + return nil +} + +// Stat is a fake call that invokes StatFn or just return nil. +func (f *FakeOS) Stat(name string) (os.FileInfo, error) { + f.appendCalls("Stat", name) + if err := f.getError("Stat"); err != nil { + return nil, err + } + + if f.StatFn != nil { + return f.StatFn(name) + } + return nil, nil +} + +// ResolveSymbolicLink is a fake call that invokes ResolveSymbolicLinkFn or returns its input +func (f *FakeOS) ResolveSymbolicLink(path string) (string, error) { + f.appendCalls("ResolveSymbolicLink", path) + if err := f.getError("ResolveSymbolicLink"); err != nil { + return "", err + } + + if f.ResolveSymbolicLinkFn != nil { + return f.ResolveSymbolicLinkFn(path) + } + return path, nil +} + +// FollowSymlinkInScope is a fake call that invokes FollowSymlinkInScope or returns its input +func (f *FakeOS) FollowSymlinkInScope(path, scope string) (string, error) { + f.appendCalls("FollowSymlinkInScope", path, scope) + if err := f.getError("FollowSymlinkInScope"); err != nil { + return "", err + } + + if f.FollowSymlinkInScopeFn != nil { + return f.FollowSymlinkInScopeFn(path, scope) + } + return path, nil +} + +// CopyFile is a fake call that invokes CopyFileFn or just return nil. +func (f *FakeOS) CopyFile(src, dest string, perm os.FileMode) error { + f.appendCalls("CopyFile", src, dest, perm) + if err := f.getError("CopyFile"); err != nil { + return err + } + + if f.CopyFileFn != nil { + return f.CopyFileFn(src, dest, perm) + } + return nil +} + +// WriteFile is a fake call that invokes WriteFileFn or just return nil. +func (f *FakeOS) WriteFile(filename string, data []byte, perm os.FileMode) error { + f.appendCalls("WriteFile", filename, data, perm) + if err := f.getError("WriteFile"); err != nil { + return err + } + + if f.WriteFileFn != nil { + return f.WriteFileFn(filename, data, perm) + } + return nil +} + +// Mount is a fake call that invokes MountFn or just return nil. +func (f *FakeOS) Mount(source string, target string, fstype string, flags uintptr, data string) error { + f.appendCalls("Mount", source, target, fstype, flags, data) + if err := f.getError("Mount"); err != nil { + return err + } + + if f.MountFn != nil { + return f.MountFn(source, target, fstype, flags, data) + } + return nil +} + +// Unmount is a fake call that invokes UnmountFn or just return nil. +func (f *FakeOS) Unmount(target string) error { + f.appendCalls("Unmount", target) + if err := f.getError("Unmount"); err != nil { + return err + } + + if f.UnmountFn != nil { + return f.UnmountFn(target) + } + return nil +} + +// LookupMount is a fake call that invokes LookupMountFn or just return nil. +func (f *FakeOS) LookupMount(path string) (containerdmount.Info, error) { + f.appendCalls("LookupMount", path) + if err := f.getError("LookupMount"); err != nil { + return containerdmount.Info{}, err + } + + if f.LookupMountFn != nil { + return f.LookupMountFn(path) + } + return containerdmount.Info{}, nil +} + +// Hostname is a fake call that invokes HostnameFn or just return nil. +func (f *FakeOS) Hostname() (string, error) { + f.appendCalls("Hostname") + if err := f.getError("Hostname"); err != nil { + return "", err + } + + if f.HostnameFn != nil { + return f.HostnameFn() + } + return "", nil +} diff -Nru containerd-1.2.6/pkg/os/testing/fake_os_unix.go containerd-1.5.9/pkg/os/testing/fake_os_unix.go --- containerd-1.2.6/pkg/os/testing/fake_os_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/os/testing/fake_os_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testing + +import osInterface "github.com/containerd/containerd/pkg/os" + +var _ osInterface.UNIX = &FakeOS{} diff -Nru containerd-1.2.6/pkg/process/deleted_state.go containerd-1.5.9/pkg/process/deleted_state.go --- containerd-1.2.6/pkg/process/deleted_state.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/deleted_state.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,75 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + + "github.com/containerd/console" + "github.com/containerd/containerd/errdefs" + google_protobuf "github.com/gogo/protobuf/types" + "github.com/pkg/errors" +) + +type deletedState struct { +} + +func (s *deletedState) Pause(ctx context.Context) error { + return errors.Errorf("cannot pause a deleted process") +} + +func (s *deletedState) Resume(ctx context.Context) error { + return errors.Errorf("cannot resume a deleted process") +} + +func (s *deletedState) Update(context context.Context, r *google_protobuf.Any) error { + return errors.Errorf("cannot update a deleted process") +} + +func (s *deletedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return errors.Errorf("cannot checkpoint a deleted process") +} + +func (s *deletedState) Resize(ws console.WinSize) error { + return errors.Errorf("cannot resize a deleted process") +} + +func (s *deletedState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a deleted process") +} + +func (s *deletedState) Delete(ctx context.Context) error { + return errors.Wrap(errdefs.ErrNotFound, "cannot delete a deleted process") +} + +func (s *deletedState) Kill(ctx context.Context, sig uint32, all bool) error { + return errors.Wrap(errdefs.ErrNotFound, "cannot kill a deleted process") +} + +func (s *deletedState) SetExited(status int) { + // no op +} + +func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return nil, errors.Errorf("cannot exec in a deleted state") +} + +func (s *deletedState) Status(ctx context.Context) (string, error) { + return "stopped", nil +} diff -Nru containerd-1.2.6/pkg/process/exec.go containerd-1.5.9/pkg/process/exec.go --- containerd-1.2.6/pkg/process/exec.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,264 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "sync" + "syscall" + "time" + + "golang.org/x/sys/unix" + + "github.com/containerd/console" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +type execProcess struct { + wg sync.WaitGroup + + execState execState + + mu sync.Mutex + id string + console console.Console + io *processIO + status int + exited time.Time + pid safePid + closers []io.Closer + stdin io.Closer + stdio stdio.Stdio + path string + spec specs.Process + + parent *Init + waitBlock chan struct{} +} + +func (e *execProcess) Wait() { + <-e.waitBlock +} + +func (e *execProcess) ID() string { + return e.id +} + +func (e *execProcess) Pid() int { + return e.pid.get() +} + +func (e *execProcess) ExitStatus() int { + e.mu.Lock() + defer e.mu.Unlock() + return e.status +} + +func (e *execProcess) ExitedAt() time.Time { + e.mu.Lock() + defer e.mu.Unlock() + return e.exited +} + +func (e *execProcess) SetExited(status int) { + e.mu.Lock() + defer e.mu.Unlock() + + e.execState.SetExited(status) +} + +func (e *execProcess) setExited(status int) { + e.status = status + e.exited = time.Now() + e.parent.Platform.ShutdownConsole(context.Background(), e.console) + close(e.waitBlock) +} + +func (e *execProcess) Delete(ctx context.Context) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Delete(ctx) +} + +func (e *execProcess) delete(ctx context.Context) error { + waitTimeout(ctx, &e.wg, 2*time.Second) + if e.io != nil { + for _, c := range e.closers { + c.Close() + } + e.io.Close() + } + pidfile := filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id)) + // silently ignore error + os.Remove(pidfile) + return nil +} + +func (e *execProcess) Resize(ws console.WinSize) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Resize(ws) +} + +func (e *execProcess) resize(ws console.WinSize) error { + if e.console == nil { + return nil + } + return e.console.Resize(ws) +} + +func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Kill(ctx, sig, false) +} + +func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error { + pid := e.pid.get() + switch { + case pid == 0: + return errors.Wrap(errdefs.ErrFailedPrecondition, "process not created") + case !e.exited.IsZero(): + return errors.Wrapf(errdefs.ErrNotFound, "process already finished") + default: + if err := unix.Kill(pid, syscall.Signal(sig)); err != nil { + return errors.Wrapf(checkKillError(err), "exec kill error") + } + } + return nil +} + +func (e *execProcess) Stdin() io.Closer { + return e.stdin +} + +func (e *execProcess) Stdio() stdio.Stdio { + return e.stdio +} + +func (e *execProcess) Start(ctx context.Context) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Start(ctx) +} + +func (e *execProcess) start(ctx context.Context) (err error) { + // The reaper may receive exit signal right after + // the container is started, before the e.pid is updated. + // In that case, we want to block the signal handler to + // access e.pid until it is updated. + e.pid.Lock() + defer e.pid.Unlock() + + var ( + socket *runc.Socket + pio *processIO + pidFile = newExecPidFile(e.path, e.id) + ) + if e.stdio.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return errors.Wrap(err, "failed to create runc console socket") + } + defer socket.Close() + } else { + if pio, err = createIO(ctx, e.id, e.parent.IoUID, e.parent.IoGID, e.stdio); err != nil { + return errors.Wrap(err, "failed to create init process I/O") + } + e.io = pio + } + opts := &runc.ExecOpts{ + PidFile: pidFile.Path(), + Detach: true, + } + if pio != nil { + opts.IO = pio.IO() + } + if socket != nil { + opts.ConsoleSocket = socket + } + if err := e.parent.runtime.Exec(ctx, e.parent.id, e.spec, opts); err != nil { + close(e.waitBlock) + return e.parent.runtimeError(err, "OCI runtime exec failed") + } + if e.stdio.Stdin != "" { + if err := e.openStdin(e.stdio.Stdin); err != nil { + return err + } + } + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return errors.Wrap(err, "failed to retrieve console master") + } + if e.console, err = e.parent.Platform.CopyConsole(ctx, console, e.id, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg); err != nil { + return errors.Wrap(err, "failed to start console copy") + } + } else { + if err := pio.Copy(ctx, &e.wg); err != nil { + return errors.Wrap(err, "failed to start io pipe copy") + } + } + pid, err := pidFile.Read() + if err != nil { + return errors.Wrap(err, "failed to retrieve OCI runtime exec pid") + } + e.pid.pid = pid + return nil +} + +func (e *execProcess) openStdin(path string) error { + sc, err := fifo.OpenFifo(context.Background(), path, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return errors.Wrapf(err, "failed to open stdin fifo %s", path) + } + e.stdin = sc + e.closers = append(e.closers, sc) + return nil +} + +func (e *execProcess) Status(ctx context.Context) (string, error) { + s, err := e.parent.Status(ctx) + if err != nil { + return "", err + } + // if the container as a whole is in the pausing/paused state, so are all + // other processes inside the container, use container state here + switch s { + case "paused", "pausing": + return s, nil + } + e.mu.Lock() + defer e.mu.Unlock() + return e.execState.Status(ctx) +} diff -Nru containerd-1.2.6/pkg/process/exec_state.go containerd-1.5.9/pkg/process/exec_state.go --- containerd-1.2.6/pkg/process/exec_state.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/exec_state.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,172 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + + "github.com/containerd/console" + "github.com/pkg/errors" +) + +type execState interface { + Resize(console.WinSize) error + Start(context.Context) error + Delete(context.Context) error + Kill(context.Context, uint32, bool) error + SetExited(int) + Status(context.Context) (string, error) +} + +type execCreatedState struct { + p *execProcess +} + +func (s *execCreatedState) transition(name string) error { + switch name { + case "running": + s.p.execState = &execRunningState{p: s.p} + case "stopped": + s.p.execState = &execStoppedState{p: s.p} + case "deleted": + s.p.execState = &deletedState{} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *execCreatedState) Resize(ws console.WinSize) error { + return s.p.resize(ws) +} + +func (s *execCreatedState) Start(ctx context.Context) error { + if err := s.p.start(ctx); err != nil { + return err + } + return s.transition("running") +} + +func (s *execCreatedState) Delete(ctx context.Context) error { + if err := s.p.delete(ctx); err != nil { + return err + } + + return s.transition("deleted") +} + +func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *execCreatedState) SetExited(status int) { + s.p.setExited(status) + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *execCreatedState) Status(ctx context.Context) (string, error) { + return "created", nil +} + +type execRunningState struct { + p *execProcess +} + +func (s *execRunningState) transition(name string) error { + switch name { + case "stopped": + s.p.execState = &execStoppedState{p: s.p} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *execRunningState) Resize(ws console.WinSize) error { + return s.p.resize(ws) +} + +func (s *execRunningState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a running process") +} + +func (s *execRunningState) Delete(ctx context.Context) error { + return errors.Errorf("cannot delete a running process") +} + +func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *execRunningState) SetExited(status int) { + s.p.setExited(status) + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *execRunningState) Status(ctx context.Context) (string, error) { + return "running", nil +} + +type execStoppedState struct { + p *execProcess +} + +func (s *execStoppedState) transition(name string) error { + switch name { + case "deleted": + s.p.execState = &deletedState{} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *execStoppedState) Resize(ws console.WinSize) error { + return errors.Errorf("cannot resize a stopped container") +} + +func (s *execStoppedState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a stopped process") +} + +func (s *execStoppedState) Delete(ctx context.Context) error { + if err := s.p.delete(ctx); err != nil { + return err + } + + return s.transition("deleted") +} + +func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *execStoppedState) SetExited(status int) { + // no op +} + +func (s *execStoppedState) Status(ctx context.Context) (string, error) { + return "stopped", nil +} diff -Nru containerd-1.2.6/pkg/process/init.go containerd-1.5.9/pkg/process/init.go --- containerd-1.2.6/pkg/process/init.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/init.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,498 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/containerd/console" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + google_protobuf "github.com/gogo/protobuf/types" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// Init represents an initial process for a container +type Init struct { + wg sync.WaitGroup + initState initState + + // mu is used to ensure that `Start()` and `Exited()` calls return in + // the right order when invoked in separate go routines. + // This is the case within the shim implementation as it makes use of + // the reaper interface. + mu sync.Mutex + + waitBlock chan struct{} + + WorkDir string + + id string + Bundle string + console console.Console + Platform stdio.Platform + io *processIO + runtime *runc.Runc + // pausing preserves the pausing state. + pausing *atomicBool + status int + exited time.Time + pid int + closers []io.Closer + stdin io.Closer + stdio stdio.Stdio + Rootfs string + IoUID int + IoGID int + NoPivotRoot bool + NoNewKeyring bool + CriuWorkPath string +} + +// NewRunc returns a new runc instance for a process +func NewRunc(root, path, namespace, runtime, criu string, systemd bool) *runc.Runc { + if root == "" { + root = RuncRoot + } + return &runc.Runc{ + Command: runtime, + Log: filepath.Join(path, "log.json"), + LogFormat: runc.JSON, + PdeathSignal: unix.SIGKILL, + Root: filepath.Join(root, namespace), + Criu: criu, + SystemdCgroup: systemd, + } +} + +// New returns a new process +func New(id string, runtime *runc.Runc, stdio stdio.Stdio) *Init { + p := &Init{ + id: id, + runtime: runtime, + pausing: new(atomicBool), + stdio: stdio, + status: 0, + waitBlock: make(chan struct{}), + } + p.initState = &createdState{p: p} + return p +} + +// Create the process with the provided config +func (p *Init) Create(ctx context.Context, r *CreateConfig) error { + var ( + err error + socket *runc.Socket + pio *processIO + pidFile = newPidFile(p.Bundle) + ) + + if r.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return errors.Wrap(err, "failed to create OCI runtime console socket") + } + defer socket.Close() + } else { + if pio, err = createIO(ctx, p.id, p.IoUID, p.IoGID, p.stdio); err != nil { + return errors.Wrap(err, "failed to create init process I/O") + } + p.io = pio + } + if r.Checkpoint != "" { + return p.createCheckpointedState(r, pidFile) + } + opts := &runc.CreateOpts{ + PidFile: pidFile.Path(), + NoPivot: p.NoPivotRoot, + NoNewKeyring: p.NoNewKeyring, + } + if p.io != nil { + opts.IO = p.io.IO() + } + if socket != nil { + opts.ConsoleSocket = socket + } + if err := p.runtime.Create(ctx, r.ID, r.Bundle, opts); err != nil { + return p.runtimeError(err, "OCI runtime create failed") + } + if r.Stdin != "" { + if err := p.openStdin(r.Stdin); err != nil { + return err + } + } + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return errors.Wrap(err, "failed to retrieve console master") + } + console, err = p.Platform.CopyConsole(ctx, console, p.id, r.Stdin, r.Stdout, r.Stderr, &p.wg) + if err != nil { + return errors.Wrap(err, "failed to start console copy") + } + p.console = console + } else { + if err := pio.Copy(ctx, &p.wg); err != nil { + return errors.Wrap(err, "failed to start io pipe copy") + } + } + pid, err := pidFile.Read() + if err != nil { + return errors.Wrap(err, "failed to retrieve OCI runtime container pid") + } + p.pid = pid + return nil +} + +func (p *Init) openStdin(path string) error { + sc, err := fifo.OpenFifo(context.Background(), path, unix.O_WRONLY|unix.O_NONBLOCK, 0) + if err != nil { + return errors.Wrapf(err, "failed to open stdin fifo %s", path) + } + p.stdin = sc + p.closers = append(p.closers, sc) + return nil +} + +func (p *Init) createCheckpointedState(r *CreateConfig, pidFile *pidFile) error { + opts := &runc.RestoreOpts{ + CheckpointOpts: runc.CheckpointOpts{ + ImagePath: r.Checkpoint, + WorkDir: p.CriuWorkPath, + ParentPath: r.ParentCheckpoint, + }, + PidFile: pidFile.Path(), + NoPivot: p.NoPivotRoot, + Detach: true, + NoSubreaper: true, + } + + if p.io != nil { + opts.IO = p.io.IO() + } + + p.initState = &createdCheckpointState{ + p: p, + opts: opts, + } + return nil +} + +// Wait for the process to exit +func (p *Init) Wait() { + <-p.waitBlock +} + +// ID of the process +func (p *Init) ID() string { + return p.id +} + +// Pid of the process +func (p *Init) Pid() int { + return p.pid +} + +// ExitStatus of the process +func (p *Init) ExitStatus() int { + p.mu.Lock() + defer p.mu.Unlock() + + return p.status +} + +// ExitedAt at time when the process exited +func (p *Init) ExitedAt() time.Time { + p.mu.Lock() + defer p.mu.Unlock() + + return p.exited +} + +// Status of the process +func (p *Init) Status(ctx context.Context) (string, error) { + if p.pausing.get() { + return "pausing", nil + } + + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Status(ctx) +} + +// Start the init process +func (p *Init) Start(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Start(ctx) +} + +func (p *Init) start(ctx context.Context) error { + err := p.runtime.Start(ctx, p.id) + return p.runtimeError(err, "OCI runtime start failed") +} + +// SetExited of the init process with the next status +func (p *Init) SetExited(status int) { + p.mu.Lock() + defer p.mu.Unlock() + + p.initState.SetExited(status) +} + +func (p *Init) setExited(status int) { + p.exited = time.Now() + p.status = status + p.Platform.ShutdownConsole(context.Background(), p.console) + close(p.waitBlock) +} + +// Delete the init process +func (p *Init) Delete(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Delete(ctx) +} + +func (p *Init) delete(ctx context.Context) error { + waitTimeout(ctx, &p.wg, 2*time.Second) + err := p.runtime.Delete(ctx, p.id, nil) + // ignore errors if a runtime has already deleted the process + // but we still hold metadata and pipes + // + // this is common during a checkpoint, runc will delete the container state + // after a checkpoint and the container will no longer exist within runc + if err != nil { + if strings.Contains(err.Error(), "does not exist") { + err = nil + } else { + err = p.runtimeError(err, "failed to delete task") + } + } + if p.io != nil { + for _, c := range p.closers { + c.Close() + } + p.io.Close() + } + if err2 := mount.UnmountAll(p.Rootfs, 0); err2 != nil { + log.G(ctx).WithError(err2).Warn("failed to cleanup rootfs mount") + if err == nil { + err = errors.Wrap(err2, "failed rootfs umount") + } + } + return err +} + +// Resize the init processes console +func (p *Init) Resize(ws console.WinSize) error { + p.mu.Lock() + defer p.mu.Unlock() + + if p.console == nil { + return nil + } + return p.console.Resize(ws) +} + +// Pause the init process and all its child processes +func (p *Init) Pause(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Pause(ctx) +} + +// Resume the init process and all its child processes +func (p *Init) Resume(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Resume(ctx) +} + +// Kill the init process +func (p *Init) Kill(ctx context.Context, signal uint32, all bool) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Kill(ctx, signal, all) +} + +func (p *Init) kill(ctx context.Context, signal uint32, all bool) error { + err := p.runtime.Kill(ctx, p.id, int(signal), &runc.KillOpts{ + All: all, + }) + return checkKillError(err) +} + +// KillAll processes belonging to the init process +func (p *Init) KillAll(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + err := p.runtime.Kill(ctx, p.id, int(unix.SIGKILL), &runc.KillOpts{ + All: true, + }) + return p.runtimeError(err, "OCI runtime killall failed") +} + +// Stdin of the process +func (p *Init) Stdin() io.Closer { + return p.stdin +} + +// Runtime returns the OCI runtime configured for the init process +func (p *Init) Runtime() *runc.Runc { + return p.runtime +} + +// Exec returns a new child process +func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Exec(ctx, path, r) +} + +// exec returns a new exec'd process +func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + // process exec request + var spec specs.Process + if err := json.Unmarshal(r.Spec.Value, &spec); err != nil { + return nil, err + } + spec.Terminal = r.Terminal + + e := &execProcess{ + id: r.ID, + path: path, + parent: p, + spec: spec, + stdio: stdio.Stdio{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }, + waitBlock: make(chan struct{}), + } + e.execState = &execCreatedState{p: e} + return e, nil +} + +// Checkpoint the init process +func (p *Init) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Checkpoint(ctx, r) +} + +func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error { + var actions []runc.CheckpointAction + if !r.Exit { + actions = append(actions, runc.LeaveRunning) + } + // keep criu work directory if criu work dir is set + work := r.WorkDir + if work == "" { + work = filepath.Join(p.WorkDir, "criu-work") + defer os.RemoveAll(work) + } + if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{ + WorkDir: work, + ImagePath: r.Path, + AllowOpenTCP: r.AllowOpenTCP, + AllowExternalUnixSockets: r.AllowExternalUnixSockets, + AllowTerminal: r.AllowTerminal, + FileLocks: r.FileLocks, + EmptyNamespaces: r.EmptyNamespaces, + }, actions...); err != nil { + dumpLog := filepath.Join(p.Bundle, "criu-dump.log") + if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil { + log.G(ctx).WithError(cerr).Error("failed to copy dump.log to criu-dump.log") + } + return fmt.Errorf("%s path= %s", criuError(err), dumpLog) + } + return nil +} + +// Update the processes resource configuration +func (p *Init) Update(ctx context.Context, r *google_protobuf.Any) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Update(ctx, r) +} + +func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error { + var resources specs.LinuxResources + if err := json.Unmarshal(r.Value, &resources); err != nil { + return err + } + return p.runtime.Update(ctx, p.id, &resources) +} + +// Stdio of the process +func (p *Init) Stdio() stdio.Stdio { + return p.stdio +} + +func (p *Init) runtimeError(rErr error, msg string) error { + if rErr == nil { + return nil + } + + rMsg, err := getLastRuntimeError(p.runtime) + switch { + case err != nil: + return errors.Wrapf(rErr, "%s: %s (%s)", msg, "unable to retrieve OCI runtime error", err.Error()) + case rMsg == "": + return errors.Wrap(rErr, msg) + default: + return errors.Errorf("%s: %s", msg, rMsg) + } +} + +func withConditionalIO(c stdio.Stdio) runc.IOOpt { + return func(o *runc.IOOption) { + o.OpenStdin = c.Stdin != "" + o.OpenStdout = c.Stdout != "" + o.OpenStderr = c.Stderr != "" + } +} diff -Nru containerd-1.2.6/pkg/process/init_state.go containerd-1.5.9/pkg/process/init_state.go --- containerd-1.2.6/pkg/process/init_state.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/init_state.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,414 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + + runc "github.com/containerd/go-runc" + google_protobuf "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +type initState interface { + Start(context.Context) error + Delete(context.Context) error + Pause(context.Context) error + Resume(context.Context) error + Update(context.Context, *google_protobuf.Any) error + Checkpoint(context.Context, *CheckpointConfig) error + Exec(context.Context, string, *ExecConfig) (Process, error) + Kill(context.Context, uint32, bool) error + SetExited(int) + Status(context.Context) (string, error) +} + +type createdState struct { + p *Init +} + +func (s *createdState) transition(name string) error { + switch name { + case "running": + s.p.initState = &runningState{p: s.p} + case "stopped": + s.p.initState = &stoppedState{p: s.p} + case "deleted": + s.p.initState = &deletedState{} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *createdState) Pause(ctx context.Context) error { + return errors.Errorf("cannot pause task in created state") +} + +func (s *createdState) Resume(ctx context.Context) error { + return errors.Errorf("cannot resume task in created state") +} + +func (s *createdState) Update(ctx context.Context, r *google_protobuf.Any) error { + return s.p.update(ctx, r) +} + +func (s *createdState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return errors.Errorf("cannot checkpoint a task in created state") +} + +func (s *createdState) Start(ctx context.Context) error { + if err := s.p.start(ctx); err != nil { + return err + } + return s.transition("running") +} + +func (s *createdState) Delete(ctx context.Context) error { + if err := s.p.delete(ctx); err != nil { + return err + } + return s.transition("deleted") +} + +func (s *createdState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *createdState) SetExited(status int) { + s.p.setExited(status) + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return s.p.exec(ctx, path, r) +} + +func (s *createdState) Status(ctx context.Context) (string, error) { + return "created", nil +} + +type createdCheckpointState struct { + p *Init + opts *runc.RestoreOpts +} + +func (s *createdCheckpointState) transition(name string) error { + switch name { + case "running": + s.p.initState = &runningState{p: s.p} + case "stopped": + s.p.initState = &stoppedState{p: s.p} + case "deleted": + s.p.initState = &deletedState{} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *createdCheckpointState) Pause(ctx context.Context) error { + return errors.Errorf("cannot pause task in created state") +} + +func (s *createdCheckpointState) Resume(ctx context.Context) error { + return errors.Errorf("cannot resume task in created state") +} + +func (s *createdCheckpointState) Update(ctx context.Context, r *google_protobuf.Any) error { + return s.p.update(ctx, r) +} + +func (s *createdCheckpointState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return errors.Errorf("cannot checkpoint a task in created state") +} + +func (s *createdCheckpointState) Start(ctx context.Context) error { + p := s.p + sio := p.stdio + + var ( + err error + socket *runc.Socket + ) + if sio.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return errors.Wrap(err, "failed to create OCI runtime console socket") + } + defer socket.Close() + s.opts.ConsoleSocket = socket + } + + if _, err := s.p.runtime.Restore(ctx, p.id, p.Bundle, s.opts); err != nil { + return p.runtimeError(err, "OCI runtime restore failed") + } + if sio.Stdin != "" { + if err := p.openStdin(sio.Stdin); err != nil { + return errors.Wrapf(err, "failed to open stdin fifo %s", sio.Stdin) + } + } + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return errors.Wrap(err, "failed to retrieve console master") + } + console, err = p.Platform.CopyConsole(ctx, console, p.id, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg) + if err != nil { + return errors.Wrap(err, "failed to start console copy") + } + p.console = console + } else { + if err := p.io.Copy(ctx, &p.wg); err != nil { + return errors.Wrap(err, "failed to start io pipe copy") + } + } + pid, err := runc.ReadPidFile(s.opts.PidFile) + if err != nil { + return errors.Wrap(err, "failed to retrieve OCI runtime container pid") + } + p.pid = pid + return s.transition("running") +} + +func (s *createdCheckpointState) Delete(ctx context.Context) error { + if err := s.p.delete(ctx); err != nil { + return err + } + return s.transition("deleted") +} + +func (s *createdCheckpointState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *createdCheckpointState) SetExited(status int) { + s.p.setExited(status) + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return nil, errors.Errorf("cannot exec in a created state") +} + +func (s *createdCheckpointState) Status(ctx context.Context) (string, error) { + return "created", nil +} + +type runningState struct { + p *Init +} + +func (s *runningState) transition(name string) error { + switch name { + case "stopped": + s.p.initState = &stoppedState{p: s.p} + case "paused": + s.p.initState = &pausedState{p: s.p} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *runningState) Pause(ctx context.Context) error { + s.p.pausing.set(true) + // NOTE "pausing" will be returned in the short window + // after `transition("paused")`, before `pausing` is reset + // to false. That doesn't break the state machine, just + // delays the "paused" state a little bit. + defer s.p.pausing.set(false) + + if err := s.p.runtime.Pause(ctx, s.p.id); err != nil { + return s.p.runtimeError(err, "OCI runtime pause failed") + } + + return s.transition("paused") +} + +func (s *runningState) Resume(ctx context.Context) error { + return errors.Errorf("cannot resume a running process") +} + +func (s *runningState) Update(ctx context.Context, r *google_protobuf.Any) error { + return s.p.update(ctx, r) +} + +func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return s.p.checkpoint(ctx, r) +} + +func (s *runningState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a running process") +} + +func (s *runningState) Delete(ctx context.Context) error { + return errors.Errorf("cannot delete a running process") +} + +func (s *runningState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *runningState) SetExited(status int) { + s.p.setExited(status) + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return s.p.exec(ctx, path, r) +} + +func (s *runningState) Status(ctx context.Context) (string, error) { + return "running", nil +} + +type pausedState struct { + p *Init +} + +func (s *pausedState) transition(name string) error { + switch name { + case "running": + s.p.initState = &runningState{p: s.p} + case "stopped": + s.p.initState = &stoppedState{p: s.p} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *pausedState) Pause(ctx context.Context) error { + return errors.Errorf("cannot pause a paused container") +} + +func (s *pausedState) Resume(ctx context.Context) error { + if err := s.p.runtime.Resume(ctx, s.p.id); err != nil { + return s.p.runtimeError(err, "OCI runtime resume failed") + } + + return s.transition("running") +} + +func (s *pausedState) Update(ctx context.Context, r *google_protobuf.Any) error { + return s.p.update(ctx, r) +} + +func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return s.p.checkpoint(ctx, r) +} + +func (s *pausedState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a paused process") +} + +func (s *pausedState) Delete(ctx context.Context) error { + return errors.Errorf("cannot delete a paused process") +} + +func (s *pausedState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *pausedState) SetExited(status int) { + s.p.setExited(status) + + if err := s.p.runtime.Resume(context.Background(), s.p.id); err != nil { + logrus.WithError(err).Error("resuming exited container from paused state") + } + + if err := s.transition("stopped"); err != nil { + panic(err) + } +} + +func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return nil, errors.Errorf("cannot exec in a paused state") +} + +func (s *pausedState) Status(ctx context.Context) (string, error) { + return "paused", nil +} + +type stoppedState struct { + p *Init +} + +func (s *stoppedState) transition(name string) error { + switch name { + case "deleted": + s.p.initState = &deletedState{} + default: + return errors.Errorf("invalid state transition %q to %q", stateName(s), name) + } + return nil +} + +func (s *stoppedState) Pause(ctx context.Context) error { + return errors.Errorf("cannot pause a stopped container") +} + +func (s *stoppedState) Resume(ctx context.Context) error { + return errors.Errorf("cannot resume a stopped container") +} + +func (s *stoppedState) Update(ctx context.Context, r *google_protobuf.Any) error { + return errors.Errorf("cannot update a stopped container") +} + +func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + return errors.Errorf("cannot checkpoint a stopped container") +} + +func (s *stoppedState) Start(ctx context.Context) error { + return errors.Errorf("cannot start a stopped process") +} + +func (s *stoppedState) Delete(ctx context.Context) error { + if err := s.p.delete(ctx); err != nil { + return err + } + return s.transition("deleted") +} + +func (s *stoppedState) Kill(ctx context.Context, sig uint32, all bool) error { + return s.p.kill(ctx, sig, all) +} + +func (s *stoppedState) SetExited(status int) { + // no op +} + +func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + return nil, errors.Errorf("cannot exec in a stopped state") +} + +func (s *stoppedState) Status(ctx context.Context) (string, error) { + return "stopped", nil +} diff -Nru containerd-1.2.6/pkg/process/io.go containerd-1.5.9/pkg/process/io.go --- containerd-1.2.6/pkg/process/io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,439 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "fmt" + "io" + "net/url" + "os" + "os/exec" + "path/filepath" + "sync" + "sync/atomic" + "syscall" + "time" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" +) + +const binaryIOProcTermTimeout = 12 * time.Second // Give logger process solid 10 seconds for cleanup + +var bufPool = sync.Pool{ + New: func() interface{} { + // setting to 4096 to align with PIPE_BUF + // http://man7.org/linux/man-pages/man7/pipe.7.html + buffer := make([]byte, 4096) + return &buffer + }, +} + +type processIO struct { + io runc.IO + + uri *url.URL + copy bool + stdio stdio.Stdio +} + +func (p *processIO) Close() error { + if p.io != nil { + return p.io.Close() + } + return nil +} + +func (p *processIO) IO() runc.IO { + return p.io +} + +func (p *processIO) Copy(ctx context.Context, wg *sync.WaitGroup) error { + if !p.copy { + return nil + } + var cwg sync.WaitGroup + if err := copyPipes(ctx, p.IO(), p.stdio.Stdin, p.stdio.Stdout, p.stdio.Stderr, wg, &cwg); err != nil { + return errors.Wrap(err, "unable to copy pipes") + } + cwg.Wait() + return nil +} + +func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio stdio.Stdio) (*processIO, error) { + pio := &processIO{ + stdio: stdio, + } + if stdio.IsNull() { + i, err := runc.NewNullIO() + if err != nil { + return nil, err + } + pio.io = i + return pio, nil + } + u, err := url.Parse(stdio.Stdout) + if err != nil { + return nil, errors.Wrap(err, "unable to parse stdout uri") + } + if u.Scheme == "" { + u.Scheme = "fifo" + } + pio.uri = u + switch u.Scheme { + case "fifo": + pio.copy = true + pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio)) + case "binary": + pio.io, err = NewBinaryIO(ctx, id, u) + case "file": + filePath := u.Path + if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil { + return nil, err + } + var f *os.File + f, err = os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, err + } + f.Close() + pio.stdio.Stdout = filePath + pio.stdio.Stderr = filePath + pio.copy = true + pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio)) + default: + return nil, errors.Errorf("unknown STDIO scheme %s", u.Scheme) + } + if err != nil { + return nil, err + } + return pio, nil +} + +func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error { + var sameFile *countingWriteCloser + for _, i := range []struct { + name string + dest func(wc io.WriteCloser, rc io.Closer) + }{ + { + name: stdout, + dest: func(wc io.WriteCloser, rc io.Closer) { + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + if _, err := io.CopyBuffer(wc, rio.Stdout(), *p); err != nil { + log.G(ctx).Warn("error copying stdout") + } + wg.Done() + wc.Close() + if rc != nil { + rc.Close() + } + }() + }, + }, { + name: stderr, + dest: func(wc io.WriteCloser, rc io.Closer) { + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + if _, err := io.CopyBuffer(wc, rio.Stderr(), *p); err != nil { + log.G(ctx).Warn("error copying stderr") + } + wg.Done() + wc.Close() + if rc != nil { + rc.Close() + } + }() + }, + }, + } { + ok, err := fifo.IsFifo(i.name) + if err != nil { + return err + } + var ( + fw io.WriteCloser + fr io.Closer + ) + if ok { + if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil { + return errors.Wrapf(err, "containerd-shim: opening w/o fifo %q failed", i.name) + } + if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil { + return errors.Wrapf(err, "containerd-shim: opening r/o fifo %q failed", i.name) + } + } else { + if sameFile != nil { + sameFile.count++ + i.dest(sameFile, nil) + continue + } + if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil { + return errors.Wrapf(err, "containerd-shim: opening file %q failed", i.name) + } + if stdout == stderr { + sameFile = &countingWriteCloser{ + WriteCloser: fw, + count: 1, + } + } + } + i.dest(fw, fr) + } + if stdin == "" { + return nil + } + f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) + } + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + + io.CopyBuffer(rio.Stdin(), f, *p) + rio.Stdin().Close() + f.Close() + }() + return nil +} + +// countingWriteCloser masks io.Closer() until close has been invoked a certain number of times. +type countingWriteCloser struct { + io.WriteCloser + count int64 +} + +func (c *countingWriteCloser) Close() error { + if atomic.AddInt64(&c.count, -1) > 0 { + return nil + } + return c.WriteCloser.Close() +} + +// NewBinaryIO runs a custom binary process for pluggable shim logging +func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (_ runc.IO, err error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + var closers []func() error + defer func() { + if err == nil { + return + } + result := multierror.Append(err) + for _, fn := range closers { + result = multierror.Append(result, fn()) + } + err = multierror.Flatten(result) + }() + + out, err := newPipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stdout pipes") + } + closers = append(closers, out.Close) + + serr, err := newPipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stderr pipes") + } + closers = append(closers, serr.Close) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + closers = append(closers, r.Close, w.Close) + + cmd := NewBinaryCmd(uri, id, ns) + cmd.ExtraFiles = append(cmd.ExtraFiles, out.r, serr.r, w) + // don't need to register this with the reaper or wait when + // running inside a shim + if err := cmd.Start(); err != nil { + return nil, errors.Wrap(err, "failed to start binary process") + } + closers = append(closers, func() error { return cmd.Process.Kill() }) + + // close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, errors.Wrap(err, "failed to close write pipe after start") + } + + // wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, errors.Wrap(err, "failed to read from logging binary") + } + + return &binaryIO{ + cmd: cmd, + out: out, + err: serr, + }, nil +} + +type binaryIO struct { + cmd *exec.Cmd + out, err *pipe +} + +func (b *binaryIO) CloseAfterStart() error { + var ( + result *multierror.Error + ) + + for _, v := range []*pipe{b.out, b.err} { + if v != nil { + if err := v.r.Close(); err != nil { + result = multierror.Append(result, err) + } + } + } + + return result.ErrorOrNil() +} + +func (b *binaryIO) Close() error { + var ( + result *multierror.Error + ) + + for _, v := range []*pipe{b.out, b.err} { + if v != nil { + if err := v.Close(); err != nil { + result = multierror.Append(result, err) + } + } + } + + if err := b.cancel(); err != nil { + result = multierror.Append(result, err) + } + + return result.ErrorOrNil() +} + +func (b *binaryIO) cancel() error { + if b.cmd == nil || b.cmd.Process == nil { + return nil + } + + // Send SIGTERM first, so logger process has a chance to flush and exit properly + if err := b.cmd.Process.Signal(syscall.SIGTERM); err != nil { + result := multierror.Append(errors.Wrap(err, "failed to send SIGTERM")) + + log.L.WithError(err).Warn("failed to send SIGTERM signal, killing logging shim") + + if err := b.cmd.Process.Kill(); err != nil { + result = multierror.Append(result, errors.Wrap(err, "failed to kill process after faulty SIGTERM")) + } + + return result.ErrorOrNil() + } + + done := make(chan error, 1) + go func() { + done <- b.cmd.Wait() + }() + + select { + case err := <-done: + return err + case <-time.After(binaryIOProcTermTimeout): + log.L.Warn("failed to wait for shim logger process to exit, killing") + + err := b.cmd.Process.Kill() + if err != nil { + return errors.Wrap(err, "failed to kill shim logger process") + } + + return nil + } +} + +func (b *binaryIO) Stdin() io.WriteCloser { + return nil +} + +func (b *binaryIO) Stdout() io.ReadCloser { + return nil +} + +func (b *binaryIO) Stderr() io.ReadCloser { + return nil +} + +func (b *binaryIO) Set(cmd *exec.Cmd) { + if b.out != nil { + cmd.Stdout = b.out.w + } + if b.err != nil { + cmd.Stderr = b.err.w + } +} + +func newPipe() (*pipe, error) { + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + return &pipe{ + r: r, + w: w, + }, nil +} + +type pipe struct { + r *os.File + w *os.File +} + +func (p *pipe) Close() error { + var result *multierror.Error + + if err := p.w.Close(); err != nil { + result = multierror.Append(result, errors.Wrap(err, "failed to close write pipe")) + } + + if err := p.r.Close(); err != nil { + result = multierror.Append(result, errors.Wrap(err, "failed to close read pipe")) + } + + return multierror.Prefix(result.ErrorOrNil(), "pipe:") +} diff -Nru containerd-1.2.6/pkg/process/io_test.go containerd-1.5.9/pkg/process/io_test.go --- containerd-1.2.6/pkg/process/io_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/io_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,72 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "io/ioutil" + "net/url" + "testing" + + "github.com/containerd/containerd/namespaces" +) + +func TestNewBinaryIO(t *testing.T) { + ctx := namespaces.WithNamespace(context.Background(), "test") + uri, _ := url.Parse("binary:///bin/echo?test") + + before := descriptorCount(t) + + io, err := NewBinaryIO(ctx, "1", uri) + if err != nil { + t.Fatal(err) + } + + err = io.Close() + if err != nil { + t.Fatal(err) + } + + after := descriptorCount(t) + if before != after-1 { // one descriptor must be closed from shim logger side + t.Fatalf("some descriptors weren't closed (%d != %d)", before, after) + } +} + +func TestNewBinaryIOCleanup(t *testing.T) { + ctx := namespaces.WithNamespace(context.Background(), "test") + uri, _ := url.Parse("binary:///not/existing") + + before := descriptorCount(t) + _, err := NewBinaryIO(ctx, "2", uri) + if err == nil { + t.Fatal("error expected for invalid binary") + } + + after := descriptorCount(t) + if before != after { + t.Fatalf("some descriptors weren't closed (%d != %d)", before, after) + } +} + +func descriptorCount(t *testing.T) int { + t.Helper() + files, _ := ioutil.ReadDir("/proc/self/fd") + return len(files) +} diff -Nru containerd-1.2.6/pkg/process/io_util.go containerd-1.5.9/pkg/process/io_util.go --- containerd-1.2.6/pkg/process/io_util.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/io_util.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,53 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "net/url" + "os" + "os/exec" +) + +// NewBinaryCmd returns a Cmd to be used to start a logging binary. +// The Cmd is generated from the provided uri, and the container ID and +// namespace are appended to the Cmd environment. +func NewBinaryCmd(binaryURI *url.URL, id, ns string) *exec.Cmd { + var args []string + for k, vs := range binaryURI.Query() { + args = append(args, k) + if len(vs) > 0 { + args = append(args, vs[0]) + } + } + + cmd := exec.Command(binaryURI.Path, args...) + + cmd.Env = append(cmd.Env, + "CONTAINER_ID="+id, + "CONTAINER_NAMESPACE="+ns, + ) + + return cmd +} + +// CloseFiles closes any files passed in. +// It it used for cleanup in the event of unexpected errors. +func CloseFiles(files ...*os.File) { + for _, file := range files { + file.Close() + } +} diff -Nru containerd-1.2.6/pkg/process/process.go containerd-1.5.9/pkg/process/process.go --- containerd-1.2.6/pkg/process/process.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/process.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "io" + "time" + + "github.com/containerd/console" + "github.com/containerd/containerd/pkg/stdio" +) + +// Process on a system +type Process interface { + // ID returns the id for the process + ID() string + // Pid returns the pid for the process + Pid() int + // ExitStatus returns the exit status + ExitStatus() int + // ExitedAt is the time the process exited + ExitedAt() time.Time + // Stdin returns the process STDIN + Stdin() io.Closer + // Stdio returns io information for the container + Stdio() stdio.Stdio + // Status returns the process status + Status(context.Context) (string, error) + // Wait blocks until the process has exited + Wait() + // Resize resizes the process console + Resize(ws console.WinSize) error + // Start execution of the process + Start(context.Context) error + // Delete deletes the process and its resourcess + Delete(context.Context) error + // Kill kills the process + Kill(context.Context, uint32, bool) error + // SetExited sets the exit status for the process + SetExited(status int) +} diff -Nru containerd-1.2.6/pkg/process/types.go containerd-1.5.9/pkg/process/types.go --- containerd-1.2.6/pkg/process/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + google_protobuf "github.com/gogo/protobuf/types" +) + +// Mount holds filesystem mount configuration +type Mount struct { + Type string + Source string + Target string + Options []string +} + +// CreateConfig hold task creation configuration +type CreateConfig struct { + ID string + Bundle string + Runtime string + Rootfs []Mount + Terminal bool + Stdin string + Stdout string + Stderr string + Checkpoint string + ParentCheckpoint string + Options *google_protobuf.Any +} + +// ExecConfig holds exec creation configuration +type ExecConfig struct { + ID string + Terminal bool + Stdin string + Stdout string + Stderr string + Spec *google_protobuf.Any +} + +// CheckpointConfig holds task checkpoint configuration +type CheckpointConfig struct { + WorkDir string + Path string + Exit bool + AllowOpenTCP bool + AllowExternalUnixSockets bool + AllowTerminal bool + FileLocks bool + EmptyNamespaces []string +} diff -Nru containerd-1.2.6/pkg/process/utils.go containerd-1.5.9/pkg/process/utils.go --- containerd-1.2.6/pkg/process/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/process/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,202 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/containerd/containerd/errdefs" + runc "github.com/containerd/go-runc" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const ( + // RuncRoot is the path to the root runc state directory + RuncRoot = "/run/containerd/runc" + // InitPidFile name of the file that contains the init pid + InitPidFile = "init.pid" +) + +// safePid is a thread safe wrapper for pid. +type safePid struct { + sync.Mutex + pid int +} + +func (s *safePid) get() int { + s.Lock() + defer s.Unlock() + return s.pid +} + +type atomicBool int32 + +func (ab *atomicBool) set(b bool) { + if b { + atomic.StoreInt32((*int32)(ab), 1) + } else { + atomic.StoreInt32((*int32)(ab), 0) + } +} + +func (ab *atomicBool) get() bool { + return atomic.LoadInt32((*int32)(ab)) == 1 +} + +// TODO(mlaventure): move to runc package? +func getLastRuntimeError(r *runc.Runc) (string, error) { + if r.Log == "" { + return "", nil + } + + f, err := os.OpenFile(r.Log, os.O_RDONLY, 0400) + if err != nil { + return "", err + } + defer f.Close() + + var ( + errMsg string + log struct { + Level string + Msg string + Time time.Time + } + ) + + dec := json.NewDecoder(f) + for err = nil; err == nil; { + if err = dec.Decode(&log); err != nil && err != io.EOF { + return "", err + } + if log.Level == "error" { + errMsg = strings.TrimSpace(log.Msg) + } + } + + return errMsg, nil +} + +// criuError returns only the first line of the error message from criu +// it tries to add an invalid dump log location when returning the message +func criuError(err error) string { + parts := strings.Split(err.Error(), "\n") + return parts[0] +} + +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 checkKillError(err error) error { + if err == nil { + return nil + } + if strings.Contains(err.Error(), "os: process already finished") || + strings.Contains(err.Error(), "container not running") || + strings.Contains(strings.ToLower(err.Error()), "no such process") || + err == unix.ESRCH { + return errors.Wrapf(errdefs.ErrNotFound, "process already finished") + } else if strings.Contains(err.Error(), "does not exist") { + return errors.Wrapf(errdefs.ErrNotFound, "no such container") + } + return errors.Wrapf(err, "unknown error after kill") +} + +func newPidFile(bundle string) *pidFile { + return &pidFile{ + path: filepath.Join(bundle, InitPidFile), + } +} + +func newExecPidFile(bundle, id string) *pidFile { + return &pidFile{ + path: filepath.Join(bundle, fmt.Sprintf("%s.pid", id)), + } +} + +type pidFile struct { + path string +} + +func (p *pidFile) Path() string { + return p.path +} + +func (p *pidFile) Read() (int, error) { + return runc.ReadPidFile(p.path) +} + +// waitTimeout handles waiting on a waitgroup with a specified timeout. +// this is commonly used for waiting on IO to finish after a process has exited +func waitTimeout(ctx context.Context, wg *sync.WaitGroup, timeout time.Duration) error { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +func stateName(v interface{}) string { + switch v.(type) { + case *runningState, *execRunningState: + return "running" + case *createdState, *execCreatedState, *createdCheckpointState: + return "created" + case *pausedState: + return "paused" + case *deletedState: + return "deleted" + case *stoppedState: + return "stopped" + } + panic(errors.Errorf("invalid state %v", v)) +} diff -Nru containerd-1.2.6/pkg/progress/bar.go containerd-1.5.9/pkg/progress/bar.go --- containerd-1.2.6/pkg/progress/bar.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/pkg/progress/bar.go 2022-01-05 17:30:58.000000000 +0000 @@ -70,9 +70,9 @@ negative := width - pad - positive n := 1 - n += copy(p[n:], []byte(green)) + n += copy(p[n:], green) n += copy(p[n:], bytes.Repeat([]byte("+"), positive)) - n += copy(p[n:], []byte(reset)) + n += copy(p[n:], reset) if negative > 0 { copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative)) diff -Nru containerd-1.2.6/pkg/progress/escape.go containerd-1.5.9/pkg/progress/escape.go --- containerd-1.2.6/pkg/progress/escape.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/pkg/progress/escape.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,6 @@ const ( escape = "\x1b" reset = escape + "[0m" - red = escape + "[31m" // nolint: staticcheck, varcheck + red = escape + "[31m" // nolint: deadcode, varcheck, unused green = escape + "[32m" ) diff -Nru containerd-1.2.6/pkg/registrar/registrar.go containerd-1.5.9/pkg/registrar/registrar.go --- containerd-1.2.6/pkg/registrar/registrar.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/registrar/registrar.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,102 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package registrar + +import ( + "sync" + + "github.com/pkg/errors" +) + +// Registrar stores one-to-one name<->key mappings. +// Names and keys must be unique. +// Registrar is safe for concurrent access. +type Registrar struct { + lock sync.Mutex + nameToKey map[string]string + keyToName map[string]string +} + +// NewRegistrar creates a new Registrar with the empty indexes. +func NewRegistrar() *Registrar { + return &Registrar{ + nameToKey: make(map[string]string), + keyToName: make(map[string]string), + } +} + +// Reserve registers a name<->key mapping, name or key must not +// be empty. +// Reserve is idempotent. +// Attempting to reserve a conflict key<->name mapping results +// in an error. +// A name<->key reservation is globally unique. +func (r *Registrar) Reserve(name, key string) error { + r.lock.Lock() + defer r.lock.Unlock() + + if name == "" || key == "" { + return errors.Errorf("invalid name %q or key %q", name, key) + } + + if k, exists := r.nameToKey[name]; exists { + if k != key { + return errors.Errorf("name %q is reserved for %q", name, k) + } + return nil + } + + if n, exists := r.keyToName[key]; exists { + if n != name { + return errors.Errorf("key %q is reserved for %q", key, n) + } + return nil + } + + r.nameToKey[name] = key + r.keyToName[key] = name + return nil +} + +// ReleaseByName releases the reserved name<->key mapping by name. +// Once released, the name and the key can be reserved again. +func (r *Registrar) ReleaseByName(name string) { + r.lock.Lock() + defer r.lock.Unlock() + + key, exists := r.nameToKey[name] + if !exists { + return + } + + delete(r.nameToKey, name) + delete(r.keyToName, key) +} + +// ReleaseByKey release the reserved name<->key mapping by key. +func (r *Registrar) ReleaseByKey(key string) { + r.lock.Lock() + defer r.lock.Unlock() + + name, exists := r.keyToName[key] + if !exists { + return + } + + delete(r.nameToKey, name) + delete(r.keyToName, key) +} diff -Nru containerd-1.2.6/pkg/registrar/registrar_test.go containerd-1.5.9/pkg/registrar/registrar_test.go --- containerd-1.2.6/pkg/registrar/registrar_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/registrar/registrar_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package registrar + +import ( + "testing" + + assertlib "github.com/stretchr/testify/assert" +) + +func TestRegistrar(t *testing.T) { + r := NewRegistrar() + assert := assertlib.New(t) + + t.Logf("should be able to reserve a name<->key mapping") + assert.NoError(r.Reserve("test-name-1", "test-id-1")) + + t.Logf("should be able to reserve a new name<->key mapping") + assert.NoError(r.Reserve("test-name-2", "test-id-2")) + + t.Logf("should be able to reserve the same name<->key mapping") + assert.NoError(r.Reserve("test-name-1", "test-id-1")) + + t.Logf("should not be able to reserve conflict name<->key mapping") + assert.Error(r.Reserve("test-name-1", "test-id-conflict")) + assert.Error(r.Reserve("test-name-conflict", "test-id-2")) + + t.Logf("should be able to release name<->key mapping by key") + r.ReleaseByKey("test-id-1") + + t.Logf("should be able to release name<->key mapping by name") + r.ReleaseByName("test-name-2") + + t.Logf("should be able to reserve new name<->key mapping after release") + assert.NoError(r.Reserve("test-name-1", "test-id-new")) + assert.NoError(r.Reserve("test-name-new", "test-id-2")) + + t.Logf("should be able to reserve same name/key name<->key") + assert.NoError(r.Reserve("same-name-id", "same-name-id")) +} diff -Nru containerd-1.2.6/pkg/runtimeoptions/v1/api.pb.go containerd-1.5.9/pkg/runtimeoptions/v1/api.pb.go --- containerd-1.2.6/pkg/runtimeoptions/v1/api.pb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/runtimeoptions/v1/api.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,397 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto + +package runtimeoptions_v1 + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// 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.GoGoProtoPackageIsVersion3 // 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"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Options) Reset() { *m = Options{} } +func (*Options) ProtoMessage() {} +func (*Options) Descriptor() ([]byte, []int) { + return fileDescriptor_7700dd27e3487aa6, []int{0} +} +func (m *Options) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Options) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Options.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Options) XXX_Merge(src proto.Message) { + xxx_messageInfo_Options.Merge(m, src) +} +func (m *Options) XXX_Size() int { + return m.Size() +} +func (m *Options) XXX_DiscardUnknown() { + xxx_messageInfo_Options.DiscardUnknown(m) +} + +var xxx_messageInfo_Options proto.InternalMessageInfo + +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), "runtimeoptions.v1.Options") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto", fileDescriptor_7700dd27e3487aa6) +} + +var fileDescriptor_7700dd27e3487aa6 = []byte{ + // 214 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x48, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x16, 0x64, 0xa7, 0xeb, 0x17, 0x95, 0xe6, 0x95, 0x64, 0xe6, 0xa6, 0xe6, 0x17, + 0x94, 0x64, 0xe6, 0xe7, 0x15, 0xeb, 0x97, 0x19, 0xea, 0x27, 0x16, 0x64, 0xea, 0x15, 0x14, 0xe5, + 0x97, 0xe4, 0x0b, 0x09, 0xa2, 0x4a, 0xea, 0x95, 0x19, 0x4a, 0xe9, 0x22, 0x19, 0x9a, 0x9e, 0x9f, + 0x9e, 0xaf, 0x0f, 0x56, 0x99, 0x54, 0x9a, 0x06, 0xe6, 0x81, 0x39, 0x60, 0x16, 0xc4, 0x04, 0x25, + 0x57, 0x2e, 0x76, 0x7f, 0x88, 0x66, 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, + 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, + 0x9e, 0x8b, 0x3b, 0x39, 0x3f, 0x2f, 0x2d, 0x33, 0x3d, 0xbe, 0x20, 0xb1, 0x24, 0x43, 0x82, 0x09, + 0x2c, 0xcb, 0x05, 0x11, 0x0a, 0x48, 0x2c, 0xc9, 0x70, 0x4a, 0x3b, 0xf1, 0x50, 0x8e, 0xf1, 0xc6, + 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, + 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x51, 0x1e, 0xe4, 0x79, 0xd4, 0x1a, 0x55, 0x24, + 0xbe, 0xcc, 0x30, 0x89, 0x0d, 0xec, 0x6a, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, 0x3c, + 0x3e, 0x79, 0x3b, 0x01, 0x00, 0x00, +} + +func (m *Options) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Options) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Options) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConfigPath) > 0 { + i -= len(m.ConfigPath) + copy(dAtA[i:], m.ConfigPath) + i = encodeVarintApi(dAtA, i, uint64(len(m.ConfigPath))) + i-- + dAtA[i] = 0x12 + } + if len(m.TypeUrl) > 0 { + i -= len(m.TypeUrl) + copy(dAtA[i:], m.TypeUrl) + i = encodeVarintApi(dAtA, i, uint64(len(m.TypeUrl))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintApi(dAtA []byte, offset int, v uint64) int { + offset -= sovApi(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Options) Size() (n int) { + if m == nil { + return 0 + } + 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) { + return (math_bits.Len64(x|1) + 6) / 7 +} +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 < 0 { + return ErrInvalidLengthApi + } + 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 < 0 { + return ErrInvalidLengthApi + } + 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) || (iNdEx+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 + depth := 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 + } + } + case 1: + iNdEx += 8 + 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 + } + } + if length < 0 { + return 0, ErrInvalidLengthApi + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupApi + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowApi = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupApi = fmt.Errorf("proto: unexpected end of group") +) diff -Nru containerd-1.2.6/pkg/runtimeoptions/v1/api.proto containerd-1.5.9/pkg/runtimeoptions/v1/api.proto --- containerd-1.2.6/pkg/runtimeoptions/v1/api.proto 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/runtimeoptions/v1/api.proto 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +// To regenerate api.pb.go run `make protos` +syntax = "proto3"; + +package 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; + + +option go_package = "github.com/containerd/containerd/pkg/runtimeoptions/v1;runtimeoptions_v1"; + +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; +} diff -Nru containerd-1.2.6/pkg/seccomp/seccomp.go containerd-1.5.9/pkg/seccomp/seccomp.go --- containerd-1.2.6/pkg/seccomp/seccomp.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/seccomp/seccomp.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package seccomp + +// IsEnabled checks whether seccomp support is enabled. On Linux, it returns +// true if the kernel has been configured to support seccomp (kernel options +// CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are set). On non-Linux, it always +// returns false. +func IsEnabled() bool { + return isEnabled() +} diff -Nru containerd-1.2.6/pkg/seccomp/seccomp_linux.go containerd-1.5.9/pkg/seccomp/seccomp_linux.go --- containerd-1.2.6/pkg/seccomp/seccomp_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/seccomp/seccomp_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,80 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + Copyright The runc Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package seccomp + +import ( + "sync" + + "golang.org/x/sys/unix" +) + +var ( + enabled bool + enabledOnce sync.Once +) + +// isEnabled returns whether the kernel has been configured to support seccomp +// (including the check for CONFIG_SECCOMP_FILTER kernel option). +func isEnabled() bool { + // Excerpts from prctl(2), section ERRORS: + // + // EACCES + // option is PR_SET_SECCOMP and arg2 is SECCOMP_MODE_FILTER, but + // the process does not have the CAP_SYS_ADMIN capability or has + // not set the no_new_privs attribute <...>. + // <...> + // EFAULT + // option is PR_SET_SECCOMP, arg2 is SECCOMP_MODE_FILTER, the + // system was built with CONFIG_SECCOMP_FILTER, and arg3 is an + // invalid address. + // <...> + // EINVAL + // option is PR_SET_SECCOMP or PR_GET_SECCOMP, and the kernel + // was not configured with CONFIG_SECCOMP. + // + // EINVAL + // option is PR_SET_SECCOMP, arg2 is SECCOMP_MODE_FILTER, + // and the kernel was not configured with CONFIG_SECCOMP_FILTER. + // + // + // Meaning, in case these kernel options are set (this is what we check + // for here), we will get some other error (most probably EACCES or + // EFAULT). IOW, EINVAL means "seccomp not supported", any other error + // means it is supported. + + enabledOnce.Do(func() { + enabled = unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0) != unix.EINVAL + }) + + return enabled +} diff -Nru containerd-1.2.6/pkg/seccomp/seccomp_unsupported.go containerd-1.5.9/pkg/seccomp/seccomp_unsupported.go --- containerd-1.2.6/pkg/seccomp/seccomp_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/seccomp/seccomp_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package seccomp + +func isEnabled() bool { + return false +} diff -Nru containerd-1.2.6/pkg/seutil/seutil.go containerd-1.5.9/pkg/seutil/seutil.go --- containerd-1.2.6/pkg/seutil/seutil.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/seutil/seutil.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,41 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package seutil + +import ( + "github.com/opencontainers/selinux/go-selinux" +) + +// ChangeToKVM process label +func ChangeToKVM(l string) (string, error) { + if l == "" || !selinux.GetEnabled() { + return "", nil + } + proc, _ := selinux.KVMContainerLabels() + selinux.ReleaseLabel(proc) + + current, err := selinux.NewContext(l) + if err != nil { + return "", err + } + next, err := selinux.NewContext(proc) + if err != nil { + return "", err + } + current["type"] = next["type"] + return current.Get(), nil +} diff -Nru containerd-1.2.6/pkg/stdio/platform.go containerd-1.5.9/pkg/stdio/platform.go --- containerd-1.2.6/pkg/stdio/platform.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/stdio/platform.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package stdio + +import ( + "context" + "sync" + + "github.com/containerd/console" +) + +// Platform handles platform-specific behavior that may differs across +// platform implementations +type Platform interface { + CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, + wg *sync.WaitGroup) (console.Console, error) + ShutdownConsole(ctx context.Context, console console.Console) error + Close() error +} diff -Nru containerd-1.2.6/pkg/stdio/stdio.go containerd-1.5.9/pkg/stdio/stdio.go --- containerd-1.2.6/pkg/stdio/stdio.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/stdio/stdio.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,30 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package stdio + +// Stdio of a process +type Stdio struct { + Stdin string + Stdout string + Stderr string + Terminal bool +} + +// IsNull returns true if the stdio is not defined +func (s Stdio) IsNull() bool { + return s.Stdin == "" && s.Stdout == "" && s.Stderr == "" +} diff -Nru containerd-1.2.6/pkg/testutil/helpers_unix.go containerd-1.5.9/pkg/testutil/helpers_unix.go --- containerd-1.2.6/pkg/testutil/helpers_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/pkg/testutil/helpers_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,7 +24,7 @@ "testing" "github.com/containerd/containerd/mount" - "gotest.tools/assert" + "gotest.tools/v3/assert" ) // Unmount unmounts a given mountPoint and sets t.Error if it fails diff -Nru containerd-1.2.6/pkg/timeout/timeout.go containerd-1.5.9/pkg/timeout/timeout.go --- containerd-1.2.6/pkg/timeout/timeout.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/timeout/timeout.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package timeout + +import ( + "context" + "sync" + "time" +) + +var ( + mu sync.Mutex + timeouts = make(map[string]time.Duration) + + // DefaultTimeout of the timeout package + DefaultTimeout = 1 * time.Second +) + +// Set the timeout for the key +func Set(key string, t time.Duration) { + mu.Lock() + timeouts[key] = t + mu.Unlock() +} + +// Get returns the timeout for the provided key +func Get(key string) time.Duration { + mu.Lock() + t, ok := timeouts[key] + mu.Unlock() + if !ok { + t = DefaultTimeout + } + return t +} + +// WithContext returns a context with the specified timeout for the provided key +func WithContext(ctx context.Context, key string) (context.Context, func()) { + t := Get(key) + return context.WithTimeout(ctx, t) +} + +// All returns all keys and their timeouts +func All() map[string]time.Duration { + out := make(map[string]time.Duration) + mu.Lock() + defer mu.Unlock() + for k, v := range timeouts { + out[k] = v + } + return out +} diff -Nru containerd-1.2.6/pkg/ttrpcutil/client.go containerd-1.5.9/pkg/ttrpcutil/client.go --- containerd-1.2.6/pkg/ttrpcutil/client.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/ttrpcutil/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,119 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ttrpcutil + +import ( + "sync" + "time" + + v1 "github.com/containerd/containerd/api/services/ttrpc/events/v1" + "github.com/containerd/containerd/pkg/dialer" + "github.com/containerd/ttrpc" + "github.com/pkg/errors" +) + +const ttrpcDialTimeout = 5 * time.Second + +type ttrpcConnector func() (*ttrpc.Client, error) + +// Client is the client to interact with TTRPC part of containerd server (plugins, events) +type Client struct { + mu sync.Mutex + connector ttrpcConnector + client *ttrpc.Client + closed bool +} + +// NewClient returns a new containerd TTRPC client that is connected to the containerd instance provided by address +func NewClient(address string, opts ...ttrpc.ClientOpts) (*Client, error) { + connector := func() (*ttrpc.Client, error) { + conn, err := dialer.Dialer(address, ttrpcDialTimeout) + if err != nil { + return nil, errors.Wrap(err, "failed to connect") + } + + client := ttrpc.NewClient(conn, opts...) + return client, nil + } + + return &Client{ + connector: connector, + }, nil +} + +// Reconnect re-establishes the TTRPC connection to the containerd daemon +func (c *Client) Reconnect() error { + c.mu.Lock() + defer c.mu.Unlock() + + if c.connector == nil { + return errors.New("unable to reconnect to containerd, no connector available") + } + + if c.closed { + return errors.New("client is closed") + } + + if c.client != nil { + if err := c.client.Close(); err != nil { + return err + } + } + + client, err := c.connector() + if err != nil { + return err + } + + c.client = client + return nil +} + +// EventsService creates an EventsService client +func (c *Client) EventsService() (v1.EventsService, error) { + client, err := c.Client() + if err != nil { + return nil, err + } + return v1.NewEventsClient(client), nil +} + +// Client returns the underlying TTRPC client object +func (c *Client) Client() (*ttrpc.Client, error) { + c.mu.Lock() + defer c.mu.Unlock() + if c.client == nil { + client, err := c.connector() + if err != nil { + return nil, err + } + c.client = client + } + return c.client, nil +} + +// Close closes the clients TTRPC connection to containerd +func (c *Client) Close() error { + c.mu.Lock() + defer c.mu.Unlock() + + c.closed = true + if c.client != nil { + return c.client.Close() + } + return nil +} diff -Nru containerd-1.2.6/pkg/userns/userns_linux.go containerd-1.5.9/pkg/userns/userns_linux.go --- containerd-1.2.6/pkg/userns/userns_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/userns/userns_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package userns + +import ( + "bufio" + "fmt" + "os" + "sync" +) + +var ( + inUserNS bool + nsOnce sync.Once +) + +// RunningInUserNS detects whether we are currently running in a user namespace. +// Originally copied from github.com/lxc/lxd/shared/util.go +func RunningInUserNS() bool { + nsOnce.Do(func() { + file, err := os.Open("/proc/self/uid_map") + if err != nil { + // This kernel-provided file only exists if user namespaces are supported + return + } + defer file.Close() + + buf := bufio.NewReader(file) + l, _, err := buf.ReadLine() + if err != nil { + return + } + + line := string(l) + var a, b, c int64 + fmt.Sscanf(line, "%d %d %d", &a, &b, &c) + + /* + * We assume we are in the initial user namespace if we have a full + * range - 4294967295 uids starting at uid 0. + */ + if a == 0 && b == 0 && c == 4294967295 { + return + } + inUserNS = true + }) + return inUserNS +} diff -Nru containerd-1.2.6/pkg/userns/userns_unsupported.go containerd-1.5.9/pkg/userns/userns_unsupported.go --- containerd-1.2.6/pkg/userns/userns_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pkg/userns/userns_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package userns + +// RunningInUserNS is a stub for non-Linux systems +// Always returns false +func RunningInUserNS() bool { + return false +} diff -Nru containerd-1.2.6/platforms/compare.go containerd-1.5.9/platforms/compare.go --- containerd-1.2.6/platforms/compare.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/compare.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,7 +16,12 @@ package platforms -import specs "github.com/opencontainers/image-spec/specs-go/v1" +import ( + "strconv" + "strings" + + specs "github.com/opencontainers/image-spec/specs-go/v1" +) // MatchComparer is able to match and compare platforms to // filter and sort platforms. @@ -26,66 +31,70 @@ Less(specs.Platform, specs.Platform) bool } -// Only returns a match comparer for a single platform -// using default resolution logic for the platform. -// -// For ARMv7, will also match ARMv6 and ARMv5 -// For ARMv6, will also match ARMv5 -func Only(platform specs.Platform) MatchComparer { - platform = Normalize(platform) - if platform.Architecture == "arm" { - if platform.Variant == "v7" { - return orderedPlatformComparer{ - matchers: []Matcher{ - &matcher{ - Platform: platform, - }, - &matcher{ - Platform: specs.Platform{ - Architecture: platform.Architecture, - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: "v6", - }, - }, - &matcher{ - Platform: specs.Platform{ - Architecture: platform.Architecture, - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: "v5", - }, - }, - }, +// platformVector returns an (ordered) vector of appropriate specs.Platform +// objects to try matching for the given platform object (see platforms.Only). +func platformVector(platform specs.Platform) []specs.Platform { + vector := []specs.Platform{platform} + + switch platform.Architecture { + case "amd64": + vector = append(vector, specs.Platform{ + Architecture: "386", + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: platform.Variant, + }) + case "arm": + if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 { + for armVersion--; armVersion >= 5; armVersion-- { + vector = append(vector, specs.Platform{ + Architecture: platform.Architecture, + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: "v" + strconv.Itoa(armVersion), + }) } } - if platform.Variant == "v6" { - return orderedPlatformComparer{ - matchers: []Matcher{ - &matcher{ - Platform: platform, - }, - &matcher{ - Platform: specs.Platform{ - Architecture: platform.Architecture, - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: "v5", - }, - }, - }, - } + case "arm64": + variant := platform.Variant + if variant == "" { + variant = "v8" } + vector = append(vector, platformVector(specs.Platform{ + Architecture: "arm", + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: variant, + })...) } - return singlePlatformComparer{ - Matcher: &matcher{ - Platform: platform, - }, - } + return vector +} + +// Only returns a match comparer for a single platform +// using default resolution logic for the platform. +// +// For arm/v8, will also match arm/v7, arm/v6 and arm/v5 +// For arm/v7, will also match arm/v6 and arm/v5 +// For arm/v6, will also match arm/v5 +// For amd64, will also match 386 +func Only(platform specs.Platform) MatchComparer { + return Ordered(platformVector(Normalize(platform))...) +} + +// OnlyStrict returns a match comparer for a single platform. +// +// Unlike Only, OnlyStrict does not match sub platforms. +// So, "arm/vN" will not match "arm/vM" where M < N, +// and "amd64" will not also match "386". +// +// OnlyStrict matches non-canonical forms. +// So, "arm64" matches "arm/64/v8". +func OnlyStrict(platform specs.Platform) MatchComparer { + return Ordered(Normalize(platform)) } // Ordered returns a platform MatchComparer which matches any of the platforms @@ -116,14 +125,6 @@ // with preference for ordering. var All MatchComparer = allPlatformComparer{} -type singlePlatformComparer struct { - Matcher -} - -func (c singlePlatformComparer) Less(p1, p2 specs.Platform) bool { - return c.Match(p1) && !c.Match(p2) -} - type orderedPlatformComparer struct { matchers []Matcher } diff -Nru containerd-1.2.6/platforms/compare_test.go containerd-1.5.9/platforms/compare_test.go --- containerd-1.2.6/platforms/compare_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/platforms/compare_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,395 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package platforms + +import ( + "testing" +) + +func TestOnly(t *testing.T) { + for _, tc := range []struct { + platform string + matches map[bool][]string + }{ + { + platform: "linux/amd64", + matches: map[bool][]string{ + true: { + "linux/amd64", + "linux/386", + }, + false: { + "linux/arm/v7", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/386", + matches: map[bool][]string{ + true: { + "linux/386", + }, + false: { + "linux/amd64", + "linux/arm/v7", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "windows/amd64", + matches: map[bool][]string{ + true: {"windows/amd64"}, + false: { + "linux/amd64", + "linux/arm/v7", + "linux/arm64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v8", + matches: map[bool][]string{ + true: { + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + }, + false: { + "linux/amd64", + "linux/arm/v4", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v7", + matches: map[bool][]string{ + true: { + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + }, + false: { + "linux/amd64", + "linux/arm/v4", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v6", + matches: map[bool][]string{ + true: { + "linux/arm/v5", + "linux/arm/v6", + }, + false: { + "linux/amd64", + "linux/arm", + "linux/arm/v4", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v5", + matches: map[bool][]string{ + true: { + "linux/arm/v5", + }, + false: { + "linux/amd64", + "linux/arm", + "linux/arm/v4", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v4", + matches: map[bool][]string{ + true: { + "linux/arm/v4", + }, + false: { + "linux/amd64", + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm64", + matches: map[bool][]string{ + true: { + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "linux/arm64/v8", + }, + false: { + "linux/amd64", + "linux/arm/v4", + "linux/arm/v9", + "linux/arm64/v9", + "windows/amd64", + "windows/arm", + }, + }, + }, + } { + testcase := tc + t.Run(testcase.platform, func(t *testing.T) { + p, err := Parse(testcase.platform) + if err != nil { + t.Fatal(err) + } + m := Only(p) + for shouldMatch, platforms := range testcase.matches { + for _, matchPlatform := range platforms { + mp, err := Parse(matchPlatform) + if err != nil { + t.Fatal(err) + } + if match := m.Match(mp); shouldMatch != match { + t.Errorf("Only(%q).Match(%q) should return %v, but returns %v", testcase.platform, matchPlatform, shouldMatch, match) + } + } + } + }) + } +} + +func TestOnlyStrict(t *testing.T) { + for _, tc := range []struct { + platform string + matches map[bool][]string + }{ + { + platform: "linux/amd64", + matches: map[bool][]string{ + true: { + "linux/amd64", + }, + false: { + "linux/386", + "linux/arm/v7", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/386", + matches: map[bool][]string{ + true: { + "linux/386", + }, + false: { + "linux/amd64", + "linux/arm/v7", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "windows/amd64", + matches: map[bool][]string{ + true: {"windows/amd64"}, + false: { + "linux/amd64", + "linux/arm/v7", + "linux/arm64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v8", + matches: map[bool][]string{ + true: { + "linux/arm/v8", + }, + false: { + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/amd64", + "linux/arm/v4", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v7", + matches: map[bool][]string{ + true: { + "linux/arm", + "linux/arm/v7", + }, + false: { + "linux/arm/v5", + "linux/arm/v6", + "linux/amd64", + "linux/arm/v4", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v6", + matches: map[bool][]string{ + true: { + "linux/arm/v6", + }, + false: { + "linux/arm/v5", + "linux/amd64", + "linux/arm", + "linux/arm/v4", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v5", + matches: map[bool][]string{ + true: { + "linux/arm/v5", + }, + false: { + "linux/amd64", + "linux/arm", + "linux/arm/v4", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm/v4", + matches: map[bool][]string{ + true: { + "linux/arm/v4", + }, + false: { + "linux/amd64", + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/arm64", + "windows/amd64", + "windows/arm", + }, + }, + }, + { + platform: "linux/arm64", + matches: map[bool][]string{ + true: { + "linux/arm64", + "linux/arm64/v8", + }, + false: { + "linux/arm", + "linux/arm/v5", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm/v8", + "linux/amd64", + "linux/arm/v4", + "linux/arm/v9", + "linux/arm64/v9", + "windows/amd64", + "windows/arm", + }, + }, + }, + } { + testcase := tc + t.Run(testcase.platform, func(t *testing.T) { + p, err := Parse(testcase.platform) + if err != nil { + t.Fatal(err) + } + m := OnlyStrict(p) + for shouldMatch, platforms := range testcase.matches { + for _, matchPlatform := range platforms { + mp, err := Parse(matchPlatform) + if err != nil { + t.Fatal(err) + } + if match := m.Match(mp); shouldMatch != match { + t.Errorf("OnlyStrict(%q).Match(%q) should return %v, but returns %v", testcase.platform, matchPlatform, shouldMatch, match) + } + } + } + }) + } +} diff -Nru containerd-1.2.6/platforms/cpuinfo.go containerd-1.5.9/platforms/cpuinfo.go --- containerd-1.2.6/platforms/cpuinfo.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/cpuinfo.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "os" "runtime" "strings" + "sync" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" @@ -28,14 +29,18 @@ ) // Present the ARM instruction set architecture, eg: v7, v8 -var cpuVariant string +// Don't use this value directly; call cpuVariant() instead. +var cpuVariantValue string -func init() { - if isArmArch(runtime.GOARCH) { - cpuVariant = getCPUVariant() - } else { - cpuVariant = "" - } +var cpuVariantOnce sync.Once + +func cpuVariant() string { + cpuVariantOnce.Do(func() { + if isArmArch(runtime.GOARCH) { + cpuVariantValue = getCPUVariant() + } + }) + return cpuVariantValue } // For Linux, the kernel has already detected the ABI, ISA and Features. @@ -74,8 +79,8 @@ } func getCPUVariant() string { - if runtime.GOOS == "windows" { - // Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use // runtime.GOARCH to determine the variants var variant string switch runtime.GOARCH { @@ -96,16 +101,25 @@ return "" } - switch variant { - case "8": + // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7") + // https://www.raspberrypi.org/forums/viewtopic.php?t=12614 + if runtime.GOARCH == "arm" && variant == "7" { + model, err := getCPUInfo("model name") + if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") { + variant = "6" + } + } + + switch strings.ToLower(variant) { + case "8", "aarch64": variant = "v8" - case "7", "7M", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)": + case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)": variant = "v7" - case "6", "6TEJ": + case "6", "6tej": variant = "v6" - case "5", "5T", "5TE", "5TEJ": + case "5", "5t", "5te", "5tej": variant = "v5" - case "4", "4T": + case "4", "4t": variant = "v4" case "3": variant = "v3" diff -Nru containerd-1.2.6/platforms/database.go containerd-1.5.9/platforms/database.go --- containerd-1.2.6/platforms/database.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/database.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,7 +28,7 @@ return os == "linux" } -// These function are generated from from https://golang.org/src/go/build/syslist.go. +// These function are generated from https://golang.org/src/go/build/syslist.go. // // We use switch statements because they are slightly faster than map lookups // and use a little less memory. @@ -38,7 +38,7 @@ // The OS value should be normalized before calling this function. func isKnownOS(os string) bool { switch os { - case "android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos": + case "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos": return true } return false @@ -60,7 +60,7 @@ // The arch value should be normalized before being passed to this function. func isKnownArch(arch string) bool { switch arch { - case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "s390", "s390x", "sparc", "sparc64": + case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm": return true } return false diff -Nru containerd-1.2.6/platforms/defaults.go containerd-1.5.9/platforms/defaults.go --- containerd-1.2.6/platforms/defaults.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/defaults.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,6 +33,11 @@ OS: runtime.GOOS, Architecture: runtime.GOARCH, // The Variant field will be empty if arch != ARM. - Variant: cpuVariant, + Variant: cpuVariant(), } } + +// DefaultStrict returns strict form of Default. +func DefaultStrict() MatchComparer { + return OnlyStrict(DefaultSpec()) +} diff -Nru containerd-1.2.6/platforms/defaults_test.go containerd-1.5.9/platforms/defaults_test.go --- containerd-1.2.6/platforms/defaults_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/defaults_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,7 +28,7 @@ expected := specs.Platform{ OS: runtime.GOOS, Architecture: runtime.GOARCH, - Variant: cpuVariant, + Variant: cpuVariant(), } p := DefaultSpec() if !reflect.DeepEqual(p, expected) { diff -Nru containerd-1.2.6/platforms/defaults_windows.go containerd-1.5.9/platforms/defaults_windows.go --- containerd-1.2.6/platforms/defaults_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/defaults_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,13 +19,63 @@ package platforms import ( + "fmt" + "runtime" + "strconv" + "strings" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/sys/windows" ) -// Default returns the default matcher for the platform. +type matchComparer struct { + defaults Matcher + osVersionPrefix string +} + +// Match matches platform with the same windows major, minor +// and build version. +func (m matchComparer) Match(p imagespec.Platform) bool { + if m.defaults.Match(p) { + // TODO(windows): Figure out whether OSVersion is deprecated. + return strings.HasPrefix(p.OSVersion, m.osVersionPrefix) + } + return false +} + +// Less sorts matched platforms in front of other platforms. +// For matched platforms, it puts platforms with larger revision +// number in front. +func (m matchComparer) Less(p1, p2 imagespec.Platform) bool { + m1, m2 := m.Match(p1), m.Match(p2) + if m1 && m2 { + r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion) + return r1 > r2 + } + return m1 && !m2 +} + +func revision(v string) int { + parts := strings.Split(v, ".") + if len(parts) < 4 { + return 0 + } + r, err := strconv.Atoi(parts[3]) + if err != nil { + return 0 + } + return r +} + +// Default returns the current platform's default platform specification. func Default() MatchComparer { - return Ordered(DefaultSpec(), specs.Platform{ - OS: "linux", - Architecture: "amd64", - }) + major, minor, build := windows.RtlGetNtVersionNumbers() + return matchComparer{ + defaults: Ordered(DefaultSpec(), specs.Platform{ + OS: "linux", + Architecture: runtime.GOARCH, + }), + osVersionPrefix: fmt.Sprintf("%d.%d.%d", major, minor, build), + } } diff -Nru containerd-1.2.6/platforms/defaults_windows_test.go containerd-1.5.9/platforms/defaults_windows_test.go --- containerd-1.2.6/platforms/defaults_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/platforms/defaults_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,149 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package platforms + +import ( + "sort" + "testing" + + imagespec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/stretchr/testify/assert" +) + +func TestMatchComparerMatch(t *testing.T) { + m := matchComparer{ + defaults: Only(imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + }), + osVersionPrefix: "10.0.17763", + } + for _, test := range []struct { + platform imagespec.Platform + match bool + }{ + { + platform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.1", + }, + match: true, + }, + { + platform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.2", + }, + match: true, + }, + { + platform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17762.1", + }, + match: false, + }, + { + platform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17764.1", + }, + match: false, + }, + { + platform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + }, + match: false, + }, + } { + assert.Equal(t, test.match, m.Match(test.platform)) + } +} + +func TestMatchComparerLess(t *testing.T) { + m := matchComparer{ + defaults: Only(imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + }), + osVersionPrefix: "10.0.17763", + } + platforms := []imagespec.Platform{ + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17764.1", + }, + { + Architecture: "amd64", + OS: "windows", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.1", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.2", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17762.1", + }, + } + expected := []imagespec.Platform{ + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.2", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763.1", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17764.1", + }, + { + Architecture: "amd64", + OS: "windows", + }, + { + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17762.1", + }, + } + sort.SliceStable(platforms, func(i, j int) bool { + return m.Less(platforms[i], platforms[j]) + }) + assert.Equal(t, expected, platforms) +} diff -Nru containerd-1.2.6/platforms/platforms.go containerd-1.5.9/platforms/platforms.go --- containerd-1.2.6/platforms/platforms.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/platforms.go 2022-01-05 17:30:58.000000000 +0000 @@ -130,7 +130,7 @@ // specification. The returned matcher only looks for equality based on os, // architecture and variant. // -// One may implement their own matcher if this doesn't provide the the required +// One may implement their own matcher if this doesn't provide the required // functionality. // // Applications should opt to use `Match` over directly parsing specifiers. @@ -189,9 +189,8 @@ if isKnownOS(p.OS) { // picks a default architecture p.Architecture = runtime.GOARCH - if p.Architecture == "arm" { - // TODO(stevvooe): Resolve arm variant, if not v6 (default) - return specs.Platform{}, errors.Wrapf(errdefs.ErrNotImplemented, "arm support not fully implemented") + if p.Architecture == "arm" && cpuVariant() != "v7" { + p.Variant = cpuVariant() } return p, nil diff -Nru containerd-1.2.6/platforms/platforms_test.go containerd-1.5.9/platforms/platforms_test.go --- containerd-1.2.6/platforms/platforms_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/platforms/platforms_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,10 +26,15 @@ func TestParseSelector(t *testing.T) { var ( - defaultOS = runtime.GOOS - defaultArch = runtime.GOARCH + defaultOS = runtime.GOOS + defaultArch = runtime.GOARCH + defaultVariant = "" ) + if defaultArch == "arm" && cpuVariant() != "v7" { + defaultVariant = cpuVariant() + } + for _, testcase := range []struct { skip bool input string @@ -255,8 +260,9 @@ expected: specs.Platform{ OS: "linux", Architecture: defaultArch, + Variant: defaultVariant, }, - formatted: joinNotEmpty("linux", defaultArch), + formatted: joinNotEmpty("linux", defaultArch, defaultVariant), }, { input: "s390x", @@ -279,8 +285,9 @@ expected: specs.Platform{ OS: "darwin", Architecture: defaultArch, + Variant: defaultVariant, }, - formatted: joinNotEmpty("darwin", defaultArch), + formatted: joinNotEmpty("darwin", defaultArch, defaultVariant), }, } { t.Run(testcase.input, func(t *testing.T) { diff -Nru containerd-1.2.6/plugin/context.go containerd-1.5.9/plugin/context.go --- containerd-1.2.6/plugin/context.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/plugin/context.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,12 +28,13 @@ // InitContext is used for plugin inititalization type InitContext struct { - Context context.Context - Root string - State string - Config interface{} - Address string - Events *exchange.Exchange + Context context.Context + Root string + State string + Config interface{} + Address string + TTRPCAddress string + Events *exchange.Exchange Meta *Meta // plugins can fill in metadata at init. diff -Nru containerd-1.2.6/plugin/plugin.go containerd-1.5.9/plugin/plugin.go --- containerd-1.2.6/plugin/plugin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ "fmt" "sync" + "github.com/containerd/ttrpc" "github.com/pkg/errors" "google.golang.org/grpc" ) @@ -29,7 +30,8 @@ ErrNoType = errors.New("plugin: no type") // ErrNoPluginID is returned when no id is specified ErrNoPluginID = errors.New("plugin: no id") - + // ErrIDRegistered is returned when a duplicate id is already registered + ErrIDRegistered = errors.New("plugin: id already registered") // ErrSkipPlugin is used when a plugin is not initialized and should not be loaded, // this allows the plugin loader differentiate between a plugin which is configured // not to load and one that fails to load. @@ -42,7 +44,7 @@ // IsSkipPlugin returns true if the error is skipping the plugin func IsSkipPlugin(err error) bool { - return errors.Cause(err) == ErrSkipPlugin + return errors.Is(err, ErrSkipPlugin) } // Type is the type of the plugin @@ -75,6 +77,15 @@ GCPlugin Type = "io.containerd.gc.v1" ) +const ( + // RuntimeLinuxV1 is the legacy linux runtime + RuntimeLinuxV1 = "io.containerd.runtime.v1.linux" + // RuntimeRuncV1 is the runc runtime that supports a single container + RuntimeRuncV1 = "io.containerd.runc.v1" + // RuntimeRuncV2 is the runc runtime that supports multiple containers per shim + RuntimeRuncV2 = "io.containerd.runc.v2" +) + // Registration contains information for registering a plugin type Registration struct { // Type of the plugin @@ -90,6 +101,8 @@ // context are passed in. The init function may modify the registration to // add exports, capabilities and platform support declarations. InitFn func(*InitContext) (interface{}, error) + // Disable the plugin from loading + Disable bool } // Init the registered plugin @@ -114,6 +127,16 @@ Register(*grpc.Server) error } +// TTRPCService allows TTRPC services to be registered with the underlying server +type TTRPCService interface { + RegisterTTRPC(*ttrpc.Server) error +} + +// TCPService allows GRPC services to be registered with the underlying tcp server +type TCPService interface { + RegisterTCP(*grpc.Server) error +} + var register = struct { sync.RWMutex r []*Registration @@ -137,12 +160,16 @@ func Register(r *Registration) { register.Lock() defer register.Unlock() + if r.Type == "" { panic(ErrNoType) } if r.ID == "" { panic(ErrNoPluginID) } + if err := checkUnique(r); err != nil { + panic(err) + } var last bool for _, requires := range r.Requires { @@ -157,24 +184,36 @@ register.r = append(register.r, r) } +func checkUnique(r *Registration) error { + for _, registered := range register.r { + if r.URI() == registered.URI() { + return errors.Wrap(ErrIDRegistered, r.URI()) + } + } + return nil +} + +// DisableFilter filters out disabled plugins +type DisableFilter func(r *Registration) bool + // Graph returns an ordered list of registered plugins for initialization. // Plugins in disableList specified by id will be disabled. -func Graph(disableList []string) (ordered []*Registration) { +func Graph(filter DisableFilter) (ordered []*Registration) { register.RLock() defer register.RUnlock() - for _, d := range disableList { - for i, r := range register.r { - if r.ID == d { - register.r = append(register.r[:i], register.r[i+1:]...) - break - } + + for _, r := range register.r { + if filter(r) { + r.Disable = true } } added := map[*Registration]bool{} for _, r := range register.r { - - children(r.ID, r.Requires, added, &ordered) + if r.Disable { + continue + } + children(r, added, &ordered) if !added[r] { ordered = append(ordered, r) added[r] = true @@ -183,11 +222,13 @@ return ordered } -func children(id string, types []Type, added map[*Registration]bool, ordered *[]*Registration) { - for _, t := range types { +func children(reg *Registration, added map[*Registration]bool, ordered *[]*Registration) { + for _, t := range reg.Requires { for _, r := range register.r { - if r.ID != id && (t == "*" || r.Type == t) { - children(r.ID, r.Requires, added, ordered) + if !r.Disable && + r.URI() != reg.URI() && + (t == "*" || r.Type == t) { + children(r, added, ordered) if !added[r] { *ordered = append(*ordered, r) added[r] = true diff -Nru containerd-1.2.6/plugin/plugin_go18.go containerd-1.5.9/plugin/plugin_go18.go --- containerd-1.2.6/plugin/plugin_go18.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/plugin/plugin_go18.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build go1.8,!windows,amd64,!static_build +// +build go1.8,!windows,amd64,!static_build,!gccgo /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/plugin/plugin_other.go containerd-1.5.9/plugin/plugin_other.go --- containerd-1.2.6/plugin/plugin_other.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/plugin/plugin_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !go1.8 windows !amd64 static_build +// +build !go1.8 windows !amd64 static_build gccgo /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/PLUGINS.md containerd-1.5.9/PLUGINS.md --- containerd-1.2.6/PLUGINS.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/PLUGINS.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,267 +0,0 @@ -# containerd Plugins - -containerd supports extending its functionality using most of its defined -interfaces. This includes using a customized runtime, snapshotter, content -store, and even adding gRPC interfaces. - -## Smart Client Model - -containerd has a smart client architecture, meaning any functionality which is -not required by the daemon is done by the client. This includes most high -level interactions such as creating a container's specification, interacting -with an image registry, or loading an image from tar. containerd's Go client -gives a user access to many points of extensions from creating their own -options on container creation to resolving image registry names. - -See [containerd's Go documentation](https://godoc.org/github.com/containerd/containerd) - -## External Plugins - -External plugins allow extending containerd's functionality using an officially -released version of containerd without needing to recompile the daemon to add a -plugin. - -containerd allows extensions through two method: - - via a binary available in containerd's PATH - - by configuring containerd to proxy to another gRPC service - -### V2 Runtimes - -The runtime v2 interface allows resolving runtimes to binaries on the system. -These binaries are used to start the shim process for containerd and allows -containerd to manage those containers using the runtime shim api returned by -the binary. - -See [runtime v2 documentation](runtime/v2/README.md) - -### Proxy Plugins - -A proxy plugin is configured using containerd's config file and will be loaded -alongside the internal plugins when containerd is started. These plugins are -connected to containerd using a local socket serving one of containerd's gRPC -API services. Each plugin is configured with a type and name just as internal -plugins are. - -#### Configuration - -Update the containerd config file, which by default is at -`/etc/containerd/config.toml`. Add a `[proxy_plugins]` section along with a -section for your given plugin `[proxy_plugins.myplugin]`. The `address` must -refer to a local socket file which the containerd process has access to. The -currently supported types are `snapshot` and `content`. - -``` -[proxy_plugins] - [proxy_plugins.customsnapshot] - type = "snapshot" - address = "/var/run/mysnapshotter.sock" -``` - -#### Implementation - -Implementing a proxy plugin is as easy as implementing the gRPC API for a -service. For implementing a proxy plugin in Go, look at the go doc for -[content store service](https://godoc.org/github.com/containerd/containerd/api/services/content/v1#ContentServer) -and [snapshotter service](https://godoc.org/github.com/containerd/containerd/api/services/snapshots/v1#SnapshotsServer). - -The following example creates a snapshot plugin binary which can be used -with any implementation of -[containerd's Snapshotter interface](https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter) -```go -package main - -import ( - "fmt" - "net" - "os" - - "google.golang.org/grpc" - - snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" - "github.com/containerd/containerd/contrib/snapshotservice" - "github.com/containerd/containerd/snapshots/native" -) - -func main() { - // Provide a unix address to listen to, this will be the `address` - // in the `proxy_plugin` configuration. - // The root will be used to store the snapshots. - if len(os.Args) < 3 { - fmt.Printf("invalid args: usage: %s \n", os.Args[0]) - os.Exit(1) - } - - // Create a gRPC server - rpc := grpc.NewServer() - - // Configure your custom snapshotter, this example uses the native - // snapshotter and a root directory. Your custom snapshotter will be - // much more useful than using a snapshotter which is already included. - // https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter - sn, err := native.NewSnapshotter(os.Args[2]) - if err != nil { - fmt.Printf("error: %v\n", err) - os.Exit(1) - } - - // Convert the snapshotter to a gRPC service, - // example in github.com/containerd/containerd/contrib/snapshotservice - service := snapshotservice.FromSnapshotter(sn) - - // Register the service with the gRPC server - snapshotsapi.RegisterSnapshotsServer(rpc, service) - - // Listen and serve - l, err := net.Listen("unix", os.Args[1]) - if err != nil { - fmt.Printf("error: %v\n", err) - os.Exit(1) - } - if err := rpc.Serve(l); err != nil { - fmt.Printf("error: %v\n", err) - os.Exit(1) - } -} -``` - -Using the previous configuration and example, you could run a snapshot plugin -with -``` -# Start plugin in one terminal -$ go run ./main.go /var/run/mysnapshotter.sock /tmp/snapshots - -# Use ctr in another -$ CONTAINERD_SNAPSHOTTER=customsnapshot ctr images pull docker.io/library/alpine:latest -$ tree -L 3 /tmp/snapshots -/tmp/snapshots -|-- metadata.db -`-- snapshots - `-- 1 - |-- bin - |-- dev - |-- etc - |-- home - |-- lib - |-- media - |-- mnt - |-- proc - |-- root - |-- run - |-- sbin - |-- srv - |-- sys - |-- tmp - |-- usr - `-- var - -18 directories, 1 file -``` - -## Built-in Plugins - -containerd uses plugins internally to ensure that internal implementations are -decoupled, stable, and treated equally with external plugins. To see all the -plugins containerd has, use `ctr plugins ls` - -``` -$ ctr plugins ls -TYPE ID PLATFORMS STATUS -io.containerd.content.v1 content - ok -io.containerd.snapshotter.v1 btrfs linux/amd64 ok -io.containerd.snapshotter.v1 aufs linux/amd64 error -io.containerd.snapshotter.v1 native linux/amd64 ok -io.containerd.snapshotter.v1 overlayfs linux/amd64 ok -io.containerd.snapshotter.v1 zfs linux/amd64 error -io.containerd.metadata.v1 bolt - ok -io.containerd.differ.v1 walking linux/amd64 ok -io.containerd.gc.v1 scheduler - ok -io.containerd.service.v1 containers-service - ok -io.containerd.service.v1 content-service - ok -io.containerd.service.v1 diff-service - ok -io.containerd.service.v1 images-service - ok -io.containerd.service.v1 leases-service - ok -io.containerd.service.v1 namespaces-service - ok -io.containerd.service.v1 snapshots-service - ok -io.containerd.runtime.v1 linux linux/amd64 ok -io.containerd.runtime.v2 task linux/amd64 ok -io.containerd.monitor.v1 cgroups linux/amd64 ok -io.containerd.service.v1 tasks-service - ok -io.containerd.internal.v1 restart - ok -io.containerd.grpc.v1 containers - ok -io.containerd.grpc.v1 content - ok -io.containerd.grpc.v1 diff - ok -io.containerd.grpc.v1 events - ok -io.containerd.grpc.v1 healthcheck - ok -io.containerd.grpc.v1 images - ok -io.containerd.grpc.v1 leases - ok -io.containerd.grpc.v1 namespaces - ok -io.containerd.grpc.v1 snapshots - ok -io.containerd.grpc.v1 tasks - ok -io.containerd.grpc.v1 version - ok -io.containerd.grpc.v1 cri linux/amd64 ok -``` - -From the output all the plugins can be seen as well those which did not -successfully load. In this case `aufs` and `zfs` are expected not to load -since they are not support on the machine. The logs will show why it failed, -but you can also get more details using the `-d` option. - -``` -$ ctr plugins ls -d id==aufs id==zfs -Type: io.containerd.snapshotter.v1 -ID: aufs -Platforms: linux/amd64 -Exports: - root /var/lib/containerd/io.containerd.snapshotter.v1.aufs -Error: - Code: Unknown - Message: modprobe aufs failed: "modprobe: FATAL: Module aufs not found in directory /lib/modules/4.17.2-1-ARCH\n": exit status 1 - -Type: io.containerd.snapshotter.v1 -ID: zfs -Platforms: linux/amd64 -Exports: - root /var/lib/containerd/io.containerd.snapshotter.v1.zfs -Error: - Code: Unknown - Message: path /var/lib/containerd/io.containerd.snapshotter.v1.zfs must be a zfs filesystem to be used with the zfs snapshotter -``` - -The error message which the plugin returned explains why the plugin was unable -to load. - -#### Configuration - -Plugins are configured using the `[plugins]` section of containerd's config. -Every plugin can have its own section using the pattern `[plugins.]`. - -example configuration -``` -[plugins] - [plugins.cgroups] - no_prometheus = false - [plugins.cri] - stream_server_address = "" - stream_server_port = "10010" - enable_selinux = false - sandbox_image = "k8s.gcr.io/pause:3.1" - stats_collect_period = 10 - systemd_cgroup = false - [plugins.cri.containerd] - snapshotter = "overlayfs" - [plugins.cri.containerd.default_runtime] - runtime_type = "io.containerd.runtime.v1.linux" - runtime_engine = "" - runtime_root = "" - [plugins.cri.containerd.untrusted_workload_runtime] - runtime_type = "" - runtime_engine = "" - runtime_root = "" - [plugins.cri.cni] - bin_dir = "/opt/cni/bin" - conf_dir = "/etc/cni/net.d" - [plugins.cri.registry] - [plugins.cri.registry.mirrors] - [plugins.cri.registry.mirrors."docker.io"] - endpoint = ["https://registry-1.docker.io"] -``` diff -Nru containerd-1.2.6/process.go containerd-1.5.9/process.go --- containerd-1.2.6/process.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/process.go 2022-01-05 17:30:58.000000000 +0000 @@ -44,7 +44,7 @@ Wait(context.Context) (<-chan ExitStatus, error) // CloseIO allows various pipes to be closed on the process CloseIO(context.Context, ...IOCloserOpts) error - // Resize changes the width and heigh of the process's terminal + // Resize changes the width and height of the process's terminal Resize(ctx context.Context, w, h uint32) error // IO returns the io set for the process IO() cio.IO @@ -52,7 +52,16 @@ Status(context.Context) (Status, error) } -// ExitStatus encapsulates a process' exit status. +// NewExitStatus populates an ExitStatus +func NewExitStatus(code uint32, t time.Time, err error) *ExitStatus { + return &ExitStatus{ + code: code, + exitedAt: t, + err: err, + } +} + +// ExitStatus encapsulates a process's exit status. // It is used by `Wait()` to return either a process exit code or an error type ExitStatus struct { code uint32 diff -Nru containerd-1.2.6/protobuf/plugin/fieldpath.pb.go containerd-1.5.9/protobuf/plugin/fieldpath.pb.go --- containerd-1.2.6/protobuf/plugin/fieldpath.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/protobuf/plugin/fieldpath.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,20 +1,14 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/protobuf/plugin/fieldpath.proto -/* -Package plugin is a generated protocol buffer package. - -It is generated from these files: - github.com/containerd/containerd/protobuf/plugin/fieldpath.proto - -It has these top-level messages: -*/ package plugin -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" + math "math" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -25,19 +19,19 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package var E_FieldpathAll = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.FileOptions)(nil), + ExtendedType: (*descriptor.FileOptions)(nil), ExtensionType: (*bool)(nil), Field: 63300, Name: "containerd.plugin.fieldpath_all", - Tag: "varint,63300,opt,name=fieldpath_all,json=fieldpathAll", + Tag: "varint,63300,opt,name=fieldpath_all", Filename: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto", } var E_Fieldpath = &proto.ExtensionDesc{ - ExtendedType: (*google_protobuf.MessageOptions)(nil), + ExtendedType: (*descriptor.MessageOptions)(nil), ExtensionType: (*bool)(nil), Field: 64400, Name: "containerd.plugin.fieldpath", @@ -51,10 +45,10 @@ } func init() { - proto.RegisterFile("github.com/containerd/containerd/protobuf/plugin/fieldpath.proto", fileDescriptorFieldpath) + proto.RegisterFile("github.com/containerd/containerd/protobuf/plugin/fieldpath.proto", fileDescriptor_604a244430167409) } -var fileDescriptorFieldpath = []byte{ +var fileDescriptor_604a244430167409 = []byte{ // 203 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x48, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, diff -Nru containerd-1.2.6/Protobuild.toml containerd-1.5.9/Protobuild.toml --- containerd-1.2.6/Protobuild.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/Protobuild.toml 2022-01-05 17:30:58.000000000 +0000 @@ -17,7 +17,7 @@ # Paths that will be added untouched to the end of the includes. We use # `/usr/local/include` to pickup the common install location of protobuf. # This is the default. - after = ["/usr/local/include"] + after = ["/usr/local/include", "/usr/include"] # This section maps protobuf imports to Go packages. These will become # `-M` directives in the call to the go protobuf generator. @@ -36,6 +36,10 @@ plugins = ["fieldpath"] # disable grpc for this package [[overrides]] +prefixes = ["github.com/containerd/containerd/api/services/ttrpc/events/v1"] +plugins = ["ttrpc", "fieldpath"] + +[[overrides]] # enable ttrpc and disable fieldpath and grpc for the shim prefixes = ["github.com/containerd/containerd/runtime/v1/shim/v1", "github.com/containerd/containerd/runtime/v2/task"] plugins = ["ttrpc"] @@ -64,20 +68,4 @@ ignore_files = [ "google/protobuf/descriptor.proto", "gogoproto/gogo.proto" -] - -[[descriptors]] -prefix = "github.com/containerd/containerd/runtime/v2/runhcs/options" -target = "runtime/v2/runhcs/options/next.pb.txt" -ignore_files = [ - "google/protobuf/descriptor.proto", - "gogoproto/gogo.proto" -] - -[[descriptors]] -prefix = "github.com/containerd/containerd/windows/hcsshimtypes" -target = "windows/hcsshimtypes/next.pb.txt" -ignore_files = [ - "google/protobuf/descriptor.proto", - "gogoproto/gogo.proto" ] diff -Nru containerd-1.2.6/pull.go containerd-1.5.9/pull.go --- containerd-1.2.6/pull.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/pull.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,255 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "context" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/remotes/docker" + "github.com/containerd/containerd/remotes/docker/schema1" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "golang.org/x/sync/errgroup" + "golang.org/x/sync/semaphore" +) + +// Pull downloads the provided content into containerd's content store +// and returns a platform specific image object +func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Image, retErr error) { + pullCtx := defaultRemoteContext() + for _, o := range opts { + if err := o(c, pullCtx); err != nil { + return nil, err + } + } + + if pullCtx.PlatformMatcher == nil { + if len(pullCtx.Platforms) > 1 { + return nil, errors.New("cannot pull multiplatform image locally, try Fetch") + } else if len(pullCtx.Platforms) == 0 { + pullCtx.PlatformMatcher = c.platform + } else { + p, err := platforms.Parse(pullCtx.Platforms[0]) + if err != nil { + return nil, errors.Wrapf(err, "invalid platform %s", pullCtx.Platforms[0]) + } + + pullCtx.PlatformMatcher = platforms.Only(p) + } + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + var unpacks int32 + var unpackEg *errgroup.Group + var unpackWrapper func(f images.Handler) images.Handler + + if pullCtx.Unpack { + // unpacker only supports schema 2 image, for schema 1 this is noop. + u, err := c.newUnpacker(ctx, pullCtx) + if err != nil { + return nil, errors.Wrap(err, "create unpacker") + } + unpackWrapper, unpackEg = u.handlerWrapper(ctx, pullCtx, &unpacks) + defer func() { + if err := unpackEg.Wait(); err != nil { + if retErr == nil { + retErr = errors.Wrap(err, "unpack") + } + } + }() + wrapper := pullCtx.HandlerWrapper + pullCtx.HandlerWrapper = func(h images.Handler) images.Handler { + if wrapper == nil { + return unpackWrapper(h) + } + return unpackWrapper(wrapper(h)) + } + } + + img, err := c.fetch(ctx, pullCtx, ref, 1) + if err != nil { + return nil, err + } + + // NOTE(fuweid): unpacker defers blobs download. before create image + // record in ImageService, should wait for unpacking(including blobs + // download). + if pullCtx.Unpack { + if unpackEg != nil { + if err := unpackEg.Wait(); err != nil { + return nil, err + } + } + } + + img, err = c.createNewImage(ctx, img) + if err != nil { + return nil, err + } + + i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher) + + if pullCtx.Unpack { + if unpacks == 0 { + // Try to unpack is none is done previously. + // This is at least required for schema 1 image. + if err := i.Unpack(ctx, pullCtx.Snapshotter, pullCtx.UnpackOpts...); err != nil { + return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter) + } + } + } + + return i, nil +} + +func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) { + store := c.ContentStore() + name, desc, err := rCtx.Resolver.Resolve(ctx, ref) + if err != nil { + return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref) + } + + fetcher, err := rCtx.Resolver.Fetcher(ctx, name) + if err != nil { + return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name) + } + + var ( + handler images.Handler + + isConvertible bool + converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error) + limiter *semaphore.Weighted + ) + + if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 { + schema1Converter := schema1.NewConverter(store, fetcher) + + handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...) + + isConvertible = true + + converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) { + return schema1Converter.Convert(ctx) + } + } else { + // Get all the children for a descriptor + childrenHandler := images.ChildrenHandler(store) + // Set any children labels for that content + childrenHandler = images.SetChildrenMappedLabels(store, childrenHandler, rCtx.ChildLabelMap) + if rCtx.AllMetadata { + // Filter manifests by platforms but allow to handle manifest + // and configuration for not-target platforms + childrenHandler = remotes.FilterManifestByPlatformHandler(childrenHandler, rCtx.PlatformMatcher) + } else { + // Filter children by platforms if specified. + childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher) + } + // Sort and limit manifests if a finite number is needed + if limit > 0 { + childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) + } + + // set isConvertible to true if there is application/octet-stream media type + convertibleHandler := images.HandlerFunc( + func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + if desc.MediaType == docker.LegacyConfigMediaType { + isConvertible = true + } + + return []ocispec.Descriptor{}, nil + }, + ) + + appendDistSrcLabelHandler, err := docker.AppendDistributionSourceLabel(store, ref) + if err != nil { + return images.Image{}, err + } + + handlers := append(rCtx.BaseHandlers, + remotes.FetchHandler(store, fetcher), + convertibleHandler, + childrenHandler, + appendDistSrcLabelHandler, + ) + + handler = images.Handlers(handlers...) + + converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) { + return docker.ConvertManifest(ctx, store, desc) + } + } + + if rCtx.HandlerWrapper != nil { + handler = rCtx.HandlerWrapper(handler) + } + + if rCtx.MaxConcurrentDownloads > 0 { + limiter = semaphore.NewWeighted(int64(rCtx.MaxConcurrentDownloads)) + } + + if err := images.Dispatch(ctx, handler, limiter, desc); err != nil { + return images.Image{}, err + } + + if isConvertible { + if desc, err = converterFunc(ctx, desc); err != nil { + return images.Image{}, err + } + } + + return images.Image{ + Name: name, + Target: desc, + Labels: rCtx.Labels, + }, nil +} + +func (c *Client) createNewImage(ctx context.Context, img images.Image) (images.Image, error) { + is := c.ImageService() + for { + if created, err := is.Create(ctx, img); err != nil { + if !errdefs.IsAlreadyExists(err) { + return images.Image{}, err + } + + updated, err := is.Update(ctx, img) + if err != nil { + // if image was removed, try create again + if errdefs.IsNotFound(err) { + continue + } + return images.Image{}, err + } + + img = updated + } else { + img = created + } + + return img, nil + } +} diff -Nru containerd-1.2.6/README.md containerd-1.5.9/README.md --- containerd-1.2.6/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,18 +1,32 @@ -![containerd banner](https://raw.githubusercontent.com/cncf/artwork/master/containerd/horizontal/color/containerd-horizontal-color.png) +![containerd banner](https://raw.githubusercontent.com/cncf/artwork/master/projects/containerd/horizontal/color/containerd-horizontal-color.png) -[![GoDoc](https://godoc.org/github.com/containerd/containerd?status.svg)](https://godoc.org/github.com/containerd/containerd) -[![Build Status](https://travis-ci.org/containerd/containerd.svg?branch=master)](https://travis-ci.org/containerd/containerd) -[![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/containerd/containerd?branch=master&svg=true)](https://ci.appveyor.com/project/mlaventure/containerd-3g73f?branch=master) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/containerd)](https://pkg.go.dev/github.com/containerd/containerd) +[![Build Status](https://github.com/containerd/containerd/workflows/CI/badge.svg)](https://github.com/containerd/containerd/actions?query=workflow%3ACI) +[![Nightlies](https://github.com/containerd/containerd/workflows/Nightly/badge.svg)](https://github.com/containerd/containerd/actions?query=workflow%3ANightly) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fcontainerd%2Fcontainerd.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fcontainerd%2Fcontainerd?ref=badge_shield) [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/containerd)](https://goreportcard.com/report/github.com/containerd/containerd) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1271/badge)](https://bestpractices.coreinfrastructure.org/projects/1271) containerd is an industry-standard container runtime with an emphasis on simplicity, robustness and portability. It is available as a daemon for Linux and Windows, which can manage the complete container lifecycle of its host system: image transfer and storage, container execution and supervision, low-level storage and network attachments, etc. +containerd is a member of CNCF with ['graduated'](https://landscape.cncf.io/selected=containerd) status. + containerd is designed to be embedded into a larger system, rather than being used directly by developers or end-users. ![architecture](design/architecture.png) +## Now Recruiting + +We are a large inclusive OSS project that is welcoming help of any kind shape or form: +* Documentation help is needed to make the product easier to consume and extend. +* We need OSS community outreach / organizing help to get the word out; manage +and create messaging and educational content; and to help with social media, community forums/groups, and google groups. +* We are actively inviting new [security advisors](https://github.com/containerd/project/blob/master/GOVERNANCE.md#security-advisors) to join the team. +* New sub-projects are being created, core and non-core that could use additional development help. +* Each of the [containerd projects](https://github.com/containerd) has a list of issues currently being worked on or that need help resolving. + - If the issue has not already been assigned to someone, or has not made recent progress and you are interested, please inquire. + - If you are interested in starting with a smaller / beginner level issue, look for issues with an `exp/beginner` tag, for example [containerd/containerd beginner issues.](https://github.com/containerd/containerd/issues?q=is%3Aissue+is%3Aopen+label%3Aexp%2Fbeginner) + ## Getting Started See our documentation on [containerd.io](https://containerd.io): @@ -24,12 +38,19 @@ If you are interested in trying out containerd see our example at [Getting Started](docs/getting-started.md). +## Nightly builds + +There are nightly builds available for download [here](https://github.com/containerd/containerd/actions?query=workflow%3ANightly). +Binaries are generated from `master` branch every night for `Linux` and `Windows`. + +Please be aware: nightly builds might have critical bugs, it's not recommended for use in production and no support provided. ## Runtime Requirements Runtime requirements for containerd are very minimal. Most interactions with the Linux and Windows container feature sets are handled via [runc](https://github.com/opencontainers/runc) and/or -OS-specific libraries (e.g. [hcsshim](https://github.com/Microsoft/hcsshim) for Microsoft). The current required version of `runc` is always listed in [RUNC.md](/RUNC.md). +OS-specific libraries (e.g. [hcsshim](https://github.com/Microsoft/hcsshim) for Microsoft). +The current required version of `runc` is described in [RUNC.md](docs/RUNC.md). There are specific features used by containerd core code and snapshotters that will require a minimum kernel @@ -119,7 +140,7 @@ ### Root Filesystems -containerd allows you to use overlay or snapshot filesystems with your containers. It comes with builtin support for overlayfs and btrfs. +containerd allows you to use overlay or snapshot filesystems with your containers. It comes with built in support for overlayfs and btrfs. ```go // pull an image and unpack it into the configured snapshotter @@ -147,10 +168,10 @@ ```go // create a new task -task, err := redis.NewTask(context, cio.Stdio) +task, err := redis.NewTask(context, cio.NewCreator(cio.WithStdio)) defer task.Delete(context) -// the task is now running and has a pid that can be use to setup networking +// the task is now running and has a pid that can be used to setup networking // or other runtime settings outside of containerd pid := task.Pid() @@ -163,7 +184,7 @@ ### Checkpoint and Restore -If you have [criu](https://criu.org/Main_Page) installed on your machine you can checkpoint and restore containers and their tasks. This allow you to clone and/or live migrate containers to other machines. +If you have [criu](https://criu.org/Main_Page) installed on your machine you can checkpoint and restore containers and their tasks. This allows you to clone and/or live migrate containers to other machines. ```go // checkpoint the task then push it to a registry @@ -172,14 +193,12 @@ err := client.Push(context, "myregistry/checkpoints/redis:master", checkpoint) // on a new machine pull the checkpoint and restore the redis container -image, err := client.Pull(context, "myregistry/checkpoints/redis:master") - -checkpoint := image.Target() +checkpoint, err := client.Pull(context, "myregistry/checkpoints/redis:master") -redis, err = client.NewContainer(context, "redis-master", containerd.WithCheckpoint(checkpoint, "redis-rootfs")) +redis, err = client.NewContainer(context, "redis-master", containerd.WithNewSnapshot("redis-rootfs", checkpoint)) defer container.Delete(context) -task, err = redis.NewTask(context, cio.Stdio, containerd.WithTaskCheckpoint(checkpoint)) +task, err = redis.NewTask(context, cio.NewCreator(cio.WithStdio), containerd.WithTaskCheckpoint(checkpoint)) defer task.Delete(context) err := task.Start(context) @@ -205,26 +224,83 @@ address = "/var/run/mysnapshotter.sock" ``` -See [PLUGINS.md](PLUGINS.md) for how to create plugins +See [PLUGINS.md](/docs/PLUGINS.md) for how to create plugins ### Releases and API Stability Please see [RELEASES.md](RELEASES.md) for details on versioning and stability of containerd components. -### Development reports. +Downloadable 64-bit Intel/AMD binaries of all official releases are available on +our [releases page](https://github.com/containerd/containerd/releases). + +For other architectures and distribution support, you will find that many +Linux distributions package their own containerd and provide it across several +architectures, such as [Canonical's Ubuntu packaging](https://launchpad.net/ubuntu/bionic/+package/containerd). + +#### Enabling command auto-completion + +Starting with containerd 1.4, the urfave client feature for auto-creation of bash and zsh +autocompletion data is enabled. To use the autocomplete feature in a bash shell for example, source +the autocomplete/ctr file in your `.bashrc`, or manually like: + +``` +$ source ./contrib/autocomplete/ctr +``` + +#### Distribution of `ctr` autocomplete for bash and zsh + +For bash, copy the `contrib/autocomplete/ctr` script into +`/etc/bash_completion.d/` and rename it to `ctr`. The `zsh_autocomplete` +file is also available and can be used similarly for zsh users. -Weekly summary on the progress and what is being worked on. -https://github.com/containerd/containerd/tree/master/reports +Provide documentation to users to `source` this file into their shell if +you don't place the autocomplete file in a location where it is automatically +loaded for the user's shell environment. + +### CRI + +`cri` is a [containerd](https://containerd.io/) plugin implementation of the Kubernetes [container runtime interface (CRI)](https://github.com/kubernetes/cri-api/blob/master/pkg/apis/runtime/v1alpha2/api.proto). With it, you are able to use containerd as the container runtime for a Kubernetes cluster. + +![cri](./docs/cri/cri.png) + +#### CRI Status + +`cri` is a native plugin of containerd. Since containerd 1.1, the cri plugin is built into the release binaries and enabled by default. + +> **Note:** As of containerd 1.5, the `cri` plugin is merged into the containerd/containerd repo. For example, the source code previously stored under [`containerd/cri/pkg`](https://github.com/containerd/cri/tree/release/1.4/pkg) +was moved to [`containerd/containerd/pkg/cri` package](https://github.com/containerd/containerd/tree/master/pkg/cri). + +The `cri` plugin has reached GA status, representing that it is: +* Feature complete +* Works with Kubernetes 1.10 and above +* Passes all [CRI validation tests](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-validation.md). +* Passes all [node e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md). +* Passes all [e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-testing/e2e-tests.md). + +See results on the containerd k8s [test dashboard](https://k8s-testgrid.appspot.com/sig-node-containerd) + +#### Validating Your `cri` Setup +A Kubernetes incubator project, [cri-tools](https://github.com/kubernetes-sigs/cri-tools), includes programs for exercising CRI implementations. More importantly, cri-tools includes the program `critest` which is used for running [CRI Validation Testing](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-validation.md). + +#### CRI Guides +* [Installing with Ansible and Kubeadm](contrib/ansible/README.md) +* [For Non-Ansible Users, Preforming a Custom Installation Using the Release Tarball and Kubeadm](docs/cri/installation.md) +* [CRI Plugin Testing Guide](./docs/cri/testing.md) +* [Debugging Pods, Containers, and Images with `crictl`](./docs/cri/crictl.md) +* [Configuring `cri` Plugins](./docs/cri/config.md) +* [Configuring containerd](https://github.com/containerd/containerd/blob/master/docs/man/containerd-config.8.md) ### Communication For async communication and long running discussions please use issues and pull requests on the github repo. This will be the best place to discuss design and implementation. -For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development. +For sync communication catch us in the `#containerd` and `#containerd-dev` slack channels on Cloud Native Computing Foundation's (CNCF) slack - `cloud-native.slack.com`. Everyone is welcome to join and chat. [Get Invite to CNCF slack.](https://slack.cncf.io) -**Slack:** https://join.slack.com/t/dockercommunity/shared_invite/enQtNDM4NjAwNDMyOTUwLWZlMDZmYWRjZjk4Zjc5ZGQ5NWZkOWI1Yjk2NGE3ZWVlYjYxM2VhYjczOWIyZDFhZTE3NTUwZWQzMjhmNGYyZTg +### Security audit + +A third party security audit was performed by Cure53 in 4Q2018; the [full report](docs/SECURITY_AUDIT.pdf) is available in our docs/ directory. ### Reporting security issues @@ -232,7 +308,7 @@ ## Licenses -The containerd codebase is released under the [Apache 2.0 license](LICENSE.code). +The containerd codebase is released under the [Apache 2.0 license](LICENSE). The README.md file, and files in the "docs" folder are licensed under the Creative Commons Attribution 4.0 International License. You may obtain a copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/. @@ -249,3 +325,8 @@ * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) information in our [`containerd/project`](https://github.com/containerd/project) repository. + +## Adoption + +Interested to see who is using containerd? Are you using containerd in a project? +Please add yourself via pull request to our [ADOPTERS.md](./ADOPTERS.md) file. diff -Nru containerd-1.2.6/reference/docker/reference.go containerd-1.5.9/reference/docker/reference.go --- containerd-1.2.6/reference/docker/reference.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/reference/docker/reference.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,797 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package docker provides a general type to represent any way of referencing images within the registry. +// Its main purpose is to abstract tags and digests (content-addressable hash). +// +// Grammar +// +// reference := name [ ":" tag ] [ "@" digest ] +// name := [domain '/'] path-component ['/' path-component]* +// domain := domain-component ['.' domain-component]* [':' port-number] +// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ +// port-number := /[0-9]+/ +// path-component := alpha-numeric [separator alpha-numeric]* +// alpha-numeric := /[a-z0-9]+/ +// separator := /[_.]|__|[-]*/ +// +// tag := /[\w][\w.-]{0,127}/ +// +// digest := digest-algorithm ":" digest-hex +// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* +// digest-algorithm-separator := /[+.-_]/ +// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ +// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value +// +// identifier := /[a-f0-9]{64}/ +// short-identifier := /[a-f0-9]{6,64}/ +package docker + +import ( + "errors" + "fmt" + "path" + "regexp" + "strings" + + "github.com/opencontainers/go-digest" +) + +const ( + // NameTotalLengthMax is the maximum total number of characters in a repository name. + NameTotalLengthMax = 255 +) + +var ( + // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. + ErrReferenceInvalidFormat = errors.New("invalid reference format") + + // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. + ErrTagInvalidFormat = errors.New("invalid tag format") + + // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. + ErrDigestInvalidFormat = errors.New("invalid digest format") + + // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. + ErrNameContainsUppercase = errors.New("repository name must be lowercase") + + // ErrNameEmpty is returned for empty, invalid repository names. + ErrNameEmpty = errors.New("repository name must have at least one component") + + // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + + // ErrNameNotCanonical is returned when a name is not canonical. + ErrNameNotCanonical = errors.New("repository name must be canonical") +) + +// Reference is an opaque object reference identifier that may include +// modifiers such as a hostname, name, tag, and digest. +type Reference interface { + // String returns the full reference + String() string +} + +// Field provides a wrapper type for resolving correct reference types when +// working with encoding. +type Field struct { + reference Reference +} + +// AsField wraps a reference in a Field for encoding. +func AsField(reference Reference) Field { + return Field{reference} +} + +// Reference unwraps the reference type from the field to +// return the Reference object. This object should be +// of the appropriate type to further check for different +// reference types. +func (f Field) Reference() Reference { + return f.reference +} + +// MarshalText serializes the field to byte text which +// is the string of the reference. +func (f Field) MarshalText() (p []byte, err error) { + return []byte(f.reference.String()), nil +} + +// UnmarshalText parses text bytes by invoking the +// reference parser to ensure the appropriately +// typed reference object is wrapped by field. +func (f *Field) UnmarshalText(p []byte) error { + r, err := Parse(string(p)) + if err != nil { + return err + } + + f.reference = r + return nil +} + +// Named is an object with a full name +type Named interface { + Reference + Name() string +} + +// Tagged is an object which has a tag +type Tagged interface { + Reference + Tag() string +} + +// NamedTagged is an object including a name and tag. +type NamedTagged interface { + Named + Tag() string +} + +// Digested is an object which has a digest +// in which it can be referenced by +type Digested interface { + Reference + Digest() digest.Digest +} + +// Canonical reference is an object with a fully unique +// name including a name with domain and digest +type Canonical interface { + Named + Digest() digest.Digest +} + +// namedRepository is a reference to a repository with a name. +// A namedRepository has both domain and path components. +type namedRepository interface { + Named + Domain() string + Path() string +} + +// Domain returns the domain part of the Named reference +func Domain(named Named) string { + if r, ok := named.(namedRepository); ok { + return r.Domain() + } + domain, _ := splitDomain(named.Name()) + return domain +} + +// Path returns the name without the domain part of the Named reference +func Path(named Named) (name string) { + if r, ok := named.(namedRepository); ok { + return r.Path() + } + _, path := splitDomain(named.Name()) + return path +} + +func splitDomain(name string) (string, string) { + match := anchoredNameRegexp.FindStringSubmatch(name) + if len(match) != 3 { + return "", name + } + return match[1], match[2] +} + +// SplitHostname splits a named reference into a +// hostname and name string. If no valid hostname is +// found, the hostname is empty and the full value +// is returned as name +// DEPRECATED: Use Domain or Path +func SplitHostname(named Named) (string, string) { + if r, ok := named.(namedRepository); ok { + return r.Domain(), r.Path() + } + return splitDomain(named.Name()) +} + +// Parse parses s and returns a syntactically valid Reference. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: Parse will not handle short digests. +func Parse(s string) (Reference, error) { + matches := ReferenceRegexp.FindStringSubmatch(s) + if matches == nil { + if s == "" { + return nil, ErrNameEmpty + } + if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { + return nil, ErrNameContainsUppercase + } + return nil, ErrReferenceInvalidFormat + } + + if len(matches[1]) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + var repo repository + + nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) + if len(nameMatch) == 3 { + repo.domain = nameMatch[1] + repo.path = nameMatch[2] + } else { + repo.domain = "" + repo.path = matches[1] + } + + ref := reference{ + namedRepository: repo, + tag: matches[2], + } + if matches[3] != "" { + var err error + ref.digest, err = digest.Parse(matches[3]) + if err != nil { + return nil, err + } + } + + r := getBestReferenceType(ref) + if r == nil { + return nil, ErrNameEmpty + } + + return r, nil +} + +// ParseNamed parses s and returns a syntactically valid reference implementing +// the Named interface. The reference must have a name and be in the canonical +// form, otherwise an error is returned. +// If an error was encountered it is returned, along with a nil Reference. +// NOTE: ParseNamed will not handle short digests. +func ParseNamed(s string) (Named, error) { + named, err := ParseNormalizedNamed(s) + if err != nil { + return nil, err + } + if named.String() != s { + return nil, ErrNameNotCanonical + } + return named, nil +} + +// WithName returns a named object representing the given string. If the input +// is invalid ErrReferenceInvalidFormat will be returned. +func WithName(name string) (Named, error) { + if len(name) > NameTotalLengthMax { + return nil, ErrNameTooLong + } + + match := anchoredNameRegexp.FindStringSubmatch(name) + if match == nil || len(match) != 3 { + return nil, ErrReferenceInvalidFormat + } + return repository{ + domain: match[1], + path: match[2], + }, nil +} + +// WithTag combines the name from "name" and the tag from "tag" to form a +// reference incorporating both the name and the tag. +func WithTag(name Named, tag string) (NamedTagged, error) { + if !anchoredTagRegexp.MatchString(tag) { + return nil, ErrTagInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if canonical, ok := name.(Canonical); ok { + return reference{ + namedRepository: repo, + tag: tag, + digest: canonical.Digest(), + }, nil + } + return taggedReference{ + namedRepository: repo, + tag: tag, + }, nil +} + +// WithDigest combines the name from "name" and the digest from "digest" to form +// a reference incorporating both the name and the digest. +func WithDigest(name Named, digest digest.Digest) (Canonical, error) { + if !anchoredDigestRegexp.MatchString(digest.String()) { + return nil, ErrDigestInvalidFormat + } + var repo repository + if r, ok := name.(namedRepository); ok { + repo.domain = r.Domain() + repo.path = r.Path() + } else { + repo.path = name.Name() + } + if tagged, ok := name.(Tagged); ok { + return reference{ + namedRepository: repo, + tag: tagged.Tag(), + digest: digest, + }, nil + } + return canonicalReference{ + namedRepository: repo, + digest: digest, + }, nil +} + +// TrimNamed removes any tag or digest from the named reference. +func TrimNamed(ref Named) Named { + domain, path := SplitHostname(ref) + return repository{ + domain: domain, + path: path, + } +} + +func getBestReferenceType(ref reference) Reference { + if ref.Name() == "" { + // Allow digest only references + if ref.digest != "" { + return digestReference(ref.digest) + } + return nil + } + if ref.tag == "" { + if ref.digest != "" { + return canonicalReference{ + namedRepository: ref.namedRepository, + digest: ref.digest, + } + } + return ref.namedRepository + } + if ref.digest == "" { + return taggedReference{ + namedRepository: ref.namedRepository, + tag: ref.tag, + } + } + + return ref +} + +type reference struct { + namedRepository + tag string + digest digest.Digest +} + +func (r reference) String() string { + return r.Name() + ":" + r.tag + "@" + r.digest.String() +} + +func (r reference) Tag() string { + return r.tag +} + +func (r reference) Digest() digest.Digest { + return r.digest +} + +type repository struct { + domain string + path string +} + +func (r repository) String() string { + return r.Name() +} + +func (r repository) Name() string { + if r.domain == "" { + return r.path + } + return r.domain + "/" + r.path +} + +func (r repository) Domain() string { + return r.domain +} + +func (r repository) Path() string { + return r.path +} + +type digestReference digest.Digest + +func (d digestReference) String() string { + return digest.Digest(d).String() +} + +func (d digestReference) Digest() digest.Digest { + return digest.Digest(d) +} + +type taggedReference struct { + namedRepository + tag string +} + +func (t taggedReference) String() string { + return t.Name() + ":" + t.tag +} + +func (t taggedReference) Tag() string { + return t.tag +} + +type canonicalReference struct { + namedRepository + digest digest.Digest +} + +func (c canonicalReference) String() string { + return c.Name() + "@" + c.digest.String() +} + +func (c canonicalReference) Digest() digest.Digest { + return c.digest +} + +var ( + // alphaNumericRegexp defines the alpha numeric atom, typically a + // component of names. This only allows lower case characters and digits. + alphaNumericRegexp = match(`[a-z0-9]+`) + + // separatorRegexp defines the separators allowed to be embedded in name + // components. This allow one period, one or two underscore and multiple + // dashes. + separatorRegexp = match(`(?:[._]|__|[-]*)`) + + // nameComponentRegexp restricts registry path component names to start + // with at least one letter or number, with following parts able to be + // separated by one period, one or two underscore and multiple dashes. + nameComponentRegexp = expression( + alphaNumericRegexp, + optional(repeated(separatorRegexp, alphaNumericRegexp))) + + // domainComponentRegexp restricts the registry domain component of a + // repository name to start with a component as defined by DomainRegexp + // and followed by an optional port. + domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) + + // DomainRegexp defines the structure of potential domain components + // that may be part of image names. This is purposely a subset of what is + // allowed by DNS to ensure backwards compatibility with Docker image + // names. + DomainRegexp = expression( + domainComponentRegexp, + optional(repeated(literal(`.`), domainComponentRegexp)), + optional(literal(`:`), match(`[0-9]+`))) + + // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. + TagRegexp = match(`[\w][\w.-]{0,127}`) + + // anchoredTagRegexp matches valid tag names, anchored at the start and + // end of the matched string. + anchoredTagRegexp = anchored(TagRegexp) + + // DigestRegexp matches valid digests. + DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) + + // anchoredDigestRegexp matches valid digests, anchored at the start and + // end of the matched string. + anchoredDigestRegexp = anchored(DigestRegexp) + + // NameRegexp is the format for the name component of references. The + // regexp has capturing groups for the domain and name part omitting + // the separating forward slash from either. + NameRegexp = expression( + optional(DomainRegexp, literal(`/`)), + nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp))) + + // anchoredNameRegexp is used to parse a name value, capturing the + // domain and trailing components. + anchoredNameRegexp = anchored( + optional(capture(DomainRegexp), literal(`/`)), + capture(nameComponentRegexp, + optional(repeated(literal(`/`), nameComponentRegexp)))) + + // ReferenceRegexp is the full supported format of a reference. The regexp + // is anchored and has capturing groups for name, tag, and digest + // components. + ReferenceRegexp = anchored(capture(NameRegexp), + optional(literal(":"), capture(TagRegexp)), + optional(literal("@"), capture(DigestRegexp))) + + // IdentifierRegexp is the format for string identifier used as a + // content addressable identifier using sha256. These identifiers + // are like digests without the algorithm, since sha256 is used. + IdentifierRegexp = match(`([a-f0-9]{64})`) + + // ShortIdentifierRegexp is the format used to represent a prefix + // of an identifier. A prefix may be used to match a sha256 identifier + // within a list of trusted identifiers. + ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) + + // anchoredIdentifierRegexp is used to check or match an + // identifier value, anchored at start and end of string. + anchoredIdentifierRegexp = anchored(IdentifierRegexp) +) + +// match compiles the string to a regular expression. +var match = regexp.MustCompile + +// literal compiles s into a literal regular expression, escaping any regexp +// reserved characters. +func literal(s string) *regexp.Regexp { + re := match(regexp.QuoteMeta(s)) + + if _, complete := re.LiteralPrefix(); !complete { + panic("must be a literal") + } + + return re +} + +// expression defines a full expression, where each regular expression must +// follow the previous. +func expression(res ...*regexp.Regexp) *regexp.Regexp { + var s string + for _, re := range res { + s += re.String() + } + + return match(s) +} + +// optional wraps the expression in a non-capturing group and makes the +// production optional. +func optional(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `?`) +} + +// repeated wraps the regexp in a non-capturing group to get one or more +// matches. +func repeated(res ...*regexp.Regexp) *regexp.Regexp { + return match(group(expression(res...)).String() + `+`) +} + +// group wraps the regexp in a non-capturing group. +func group(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(?:` + expression(res...).String() + `)`) +} + +// capture wraps the expression in a capturing group. +func capture(res ...*regexp.Regexp) *regexp.Regexp { + return match(`(` + expression(res...).String() + `)`) +} + +// anchored anchors the regular expression by adding start and end delimiters. +func anchored(res ...*regexp.Regexp) *regexp.Regexp { + return match(`^` + expression(res...).String() + `$`) +} + +var ( + legacyDefaultDomain = "index.docker.io" + defaultDomain = "docker.io" + officialRepoName = "library" + defaultTag = "latest" +) + +// normalizedNamed represents a name which has been +// normalized and has a familiar form. A familiar name +// is what is used in Docker UI. An example normalized +// name is "docker.io/library/ubuntu" and corresponding +// familiar name of "ubuntu". +type normalizedNamed interface { + Named + Familiar() Named +} + +// ParseNormalizedNamed parses a string into a named reference +// transforming a familiar name from Docker UI to a fully +// qualified reference. If the value may be an identifier +// use ParseAnyReference. +func ParseNormalizedNamed(s string) (Named, error) { + if ok := anchoredIdentifierRegexp.MatchString(s); ok { + return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) + } + domain, remainder := splitDockerDomain(s) + var remoteName string + if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { + remoteName = remainder[:tagSep] + } else { + remoteName = remainder + } + if strings.ToLower(remoteName) != remoteName { + return nil, errors.New("invalid reference format: repository name must be lowercase") + } + + ref, err := Parse(domain + "/" + remainder) + if err != nil { + return nil, err + } + named, isNamed := ref.(Named) + if !isNamed { + return nil, fmt.Errorf("reference %s has no name", ref.String()) + } + return named, nil +} + +// ParseDockerRef normalizes the image reference following the docker convention. This is added +// mainly for backward compatibility. +// The reference returned can only be either tagged or digested. For reference contains both tag +// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ +// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as +// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. +func ParseDockerRef(ref string) (Named, error) { + named, err := ParseNormalizedNamed(ref) + if err != nil { + return nil, err + } + if _, ok := named.(NamedTagged); ok { + if canonical, ok := named.(Canonical); ok { + // The reference is both tagged and digested, only + // return digested. + newNamed, err := WithName(canonical.Name()) + if err != nil { + return nil, err + } + newCanonical, err := WithDigest(newNamed, canonical.Digest()) + if err != nil { + return nil, err + } + return newCanonical, nil + } + } + return TagNameOnly(named), nil +} + +// splitDockerDomain splits a repository name to domain and remotename string. +// If no valid domain is found, the default domain is used. Repository name +// needs to be already validated before. +func splitDockerDomain(name string) (domain, remainder string) { + i := strings.IndexRune(name, '/') + if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { + domain, remainder = defaultDomain, name + } else { + domain, remainder = name[:i], name[i+1:] + } + if domain == legacyDefaultDomain { + domain = defaultDomain + } + if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { + remainder = officialRepoName + "/" + remainder + } + return +} + +// familiarizeName returns a shortened version of the name familiar +// to to the Docker UI. Familiar names have the default domain +// "docker.io" and "library/" repository prefix removed. +// For example, "docker.io/library/redis" will have the familiar +// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". +// Returns a familiarized named only reference. +func familiarizeName(named namedRepository) repository { + repo := repository{ + domain: named.Domain(), + path: named.Path(), + } + + if repo.domain == defaultDomain { + repo.domain = "" + // Handle official repositories which have the pattern "library/" + if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { + repo.path = split[1] + } + } + return repo +} + +func (r reference) Familiar() Named { + return reference{ + namedRepository: familiarizeName(r.namedRepository), + tag: r.tag, + digest: r.digest, + } +} + +func (r repository) Familiar() Named { + return familiarizeName(r) +} + +func (t taggedReference) Familiar() Named { + return taggedReference{ + namedRepository: familiarizeName(t.namedRepository), + tag: t.tag, + } +} + +func (c canonicalReference) Familiar() Named { + return canonicalReference{ + namedRepository: familiarizeName(c.namedRepository), + digest: c.digest, + } +} + +// TagNameOnly adds the default tag "latest" to a reference if it only has +// a repo name. +func TagNameOnly(ref Named) Named { + if IsNameOnly(ref) { + namedTagged, err := WithTag(ref, defaultTag) + if err != nil { + // Default tag must be valid, to create a NamedTagged + // type with non-validated input the WithTag function + // should be used instead + panic(err) + } + return namedTagged + } + return ref +} + +// ParseAnyReference parses a reference string as a possible identifier, +// full digest, or familiar name. +func ParseAnyReference(ref string) (Reference, error) { + if ok := anchoredIdentifierRegexp.MatchString(ref); ok { + return digestReference("sha256:" + ref), nil + } + if dgst, err := digest.Parse(ref); err == nil { + return digestReference(dgst), nil + } + + return ParseNormalizedNamed(ref) +} + +// IsNameOnly returns true if reference only contains a repo name. +func IsNameOnly(ref Named) bool { + if _, ok := ref.(NamedTagged); ok { + return false + } + if _, ok := ref.(Canonical); ok { + return false + } + return true +} + +// FamiliarName returns the familiar name string +// for the given named, familiarizing if needed. +func FamiliarName(ref Named) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().Name() + } + return ref.Name() +} + +// FamiliarString returns the familiar string representation +// for the given reference, familiarizing if needed. +func FamiliarString(ref Reference) string { + if nn, ok := ref.(normalizedNamed); ok { + return nn.Familiar().String() + } + return ref.String() +} + +// FamiliarMatch reports whether ref matches the specified pattern. +// See https://godoc.org/path#Match for supported patterns. +func FamiliarMatch(pattern string, ref Reference) (bool, error) { + matched, err := path.Match(pattern, FamiliarString(ref)) + if namedRef, isNamed := ref.(Named); isNamed && !matched { + matched, _ = path.Match(pattern, FamiliarName(namedRef)) + } + return matched, err +} diff -Nru containerd-1.2.6/reference/reference.go containerd-1.5.9/reference/reference.go --- containerd-1.2.6/reference/reference.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reference/reference.go 2022-01-05 17:30:58.000000000 +0000 @@ -85,6 +85,10 @@ // Parse parses the string into a structured ref. func Parse(s string) (Spec, error) { + if strings.Contains(s, "://") { + return Spec{}, ErrInvalid + } + u, err := url.Parse("dummy://" + s) if err != nil { return Spec{}, err @@ -124,7 +128,7 @@ i := strings.Index(r.Locator, "/") if i < 0 { - i = len(r.Locator) + 1 + return r.Locator } return r.Locator[:i] } diff -Nru containerd-1.2.6/reference/reference_test.go containerd-1.5.9/reference/reference_test.go --- containerd-1.2.6/reference/reference_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reference/reference_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -151,7 +151,6 @@ }, }, { - Skip: true, // TODO(stevvooe): Implement this case. Name: "SchemeDefined", Input: "http://xn--7o8h.com/myimage:xn--7o8h.com@sha512:fffffff", Hostname: "xn--7o8h.com", @@ -160,11 +159,6 @@ }, } { t.Run(testcase.Name, func(t *testing.T) { - if testcase.Skip { - t.Skip("testcase disabled") - return - } - ref, err := Parse(testcase.Input) if err != testcase.Err { if testcase.Err != nil { diff -Nru containerd-1.2.6/releases/README.md containerd-1.5.9/releases/README.md --- containerd-1.2.6/releases/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +## containerd release process + +1. Create release pull request with release notes and updated versions. + + 1. Compile release notes detailing features added since the last release and + add release template file to `releases/` directory. The template is defined + by containerd's release tool but refer to previous release files for style + and format help. Name the file using the version, for rc add an `-rc` suffix. + When moving from rc to final, the rc file may just be renamed and updated. + See [release-tool](https://github.com/containerd/release-tool) + + 2. Update the version file at `https://github.com/containerd/containerd/blob/master/version/version.go` + + 3. Update RELEASES.md to refer to the new release and dates. + + 4. Update the `.mailmap` files for commit authors which have multiple email addresses in the commit log. + If it is not clear which email or name the contributor might want used in the release notes, reach + out to the contributor for feedback. NOTE: real names should be used whenever possible. The file is + maintained by manually adding entries to the file. + - e.g. `Real Name Other Name ` + + 5. Before opening the pull request, run the release tool using the new release notes. + Ensure the output matches what is expected, including contributors, change log, + dependencies, and visual elements such as spacing. If a contributor is duplicated, + use the emails outputted by the release tool to update the mailmap then re-run. The + goal of the release tool is that is generates release notes that need no + alterations after it is generated. + +2. Create tag + + 1. Choose tag for the next release, containerd uses semantic versioning and + expects tags to be formatted as `vx.y.z[-rc.n]`. + + 2. Generate release notes (using a temp file may be helpful). + - e.g. `release-tool -l -d -n -t v1.0.0 ./releases/v1.0.0.toml > /tmp/v1.0.0-notes` + + 3. Create tag using the generated release notes. + - e.g. `git tag --cleanup=whitespace -s v1.0.0 -F /tmp/v1.0.0-notes` + + 4. Verify tag (e.g. `git show v1.0.0`), it may help to compare the new tag against previous. + +3. Push tag and Github release + + 1. Push the tag to `git@github.com:containerd/containerd.git`. + NOTE: this will kick off CI building of the release binaries. + + 2. Create the Github release using the `Tag version` which was just pushed. Use the first + line outputted from the release tool as the `Release title` and the remainder of the + output for the description. No alteration of the release output should be needed. + Ensure `pre-release` is checked if an `-rc`. + NOTE: This should be done immediately after pushing the tag, otherwise CI may create the release + when the binaries are pushed. + + 3. Check CI has completed and uploaded the binaries. Remove any binaries which get + uploaded but are not intended as part of the release (e.g. Darwin binaries). + +4. Update [`config.toml`](https://github.com/containerd/containerd.io/blob/f827d53826a426cb48f24cc08e43cc8722ad6d01/config.toml#L35) with latest release in the [containerd/containerd.io project](https://github.com/containerd/containerd.io); open PR to + force website downloads update. + +5. Promote on Slack, Twitter, mailing lists, etc diff -Nru containerd-1.2.6/releases/v1.0.0-beta.2.toml containerd-1.5.9/releases/v1.0.0-beta.2.toml --- containerd-1.2.6/releases/v1.0.0-beta.2.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.0.0-beta.2.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0-beta.1" - -pre_release = true - -preface = """\ -This release rounds out much of the remaining feature set for the 1.0 release -time frame. In addition to a large number of bugfixes and utility additions, -services and methods have been added to the GRPC API to meet production use -cases. The highlight is garbage collection, along with database migrations, -plugin introspection and rich PID listing.""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - [notes.gc] - title = "Garbage Collection" - description = """\ -Full garbage collection support for cleaning up content, snapshots and metadata -for containerd resources. The implementation is based on well-known concurrent -mark and sweep and the approach allows for extensibility in collection -policies. - -The GC is triggered `Container.Delete and Image.Delete. Note that images may -need to be re-pulled for proper support.""" - - [notes.migrations] - title = "Migrations" - description = """\ -A lightweight migration framework is now part of containerd. This allows us to -safely evolve the schema between releases with the groundwork laid early. - -As part of this release, a migration will be run to add back references in -support of garbage collection.""" - - [notes.introspection] - title = "Introspection API" - description = """\ -The new introspection API allows for querying the state of containerd. The -`Plugins` method lists the state and exports of all initialized plugins in use -in a containerd instance. - -```console -$ ctr plugins -TYPE ID PLATFORM STATUS -io.containerd.content.v1 content - ok -io.containerd.metadata.v1 bolt - ok -io.containerd.differ.v1 walking linux/amd64 ok -io.containerd.grpc.v1 containers - ok -io.containerd.grpc.v1 content - ok -io.containerd.grpc.v1 diff - ok -io.containerd.grpc.v1 events - ok -io.containerd.grpc.v1 healthcheck - ok -io.containerd.grpc.v1 images - ok -io.containerd.grpc.v1 namespaces - ok -io.containerd.snapshotter.v1 btrfs linux/amd64 error -io.containerd.snapshotter.v1 overlayfs linux/amd64 ok -io.containerd.grpc.v1 snapshots - ok -io.containerd.monitor.v1 cgroups linux/amd64 ok -io.containerd.runtime.v1 linux linux/amd64 ok -io.containerd.grpc.v1 tasks - ok -io.containerd.grpc.v1 version - ok -```""" - - [notes.listpids] - title = "Rich ListPIDs" - description = """\ -Listing PIDs through the task service can now provide runtime specific metadata -through the API. This is particularly interesting on the windows platform. The -following is an example of a Windows container `ps` output: - -```console -$ ctr tasks ps -PID INFO -3716 {ImageName:smss.exe CreatedAt:2017-10-10T17:51:45.1552607Z KernelTime_100Ns:156250 MemoryCommitBytes:348160 MemoryWorkingSetPrivateBytes:217088 MemoryWorkingSetSharedBytes:946176 ProcessID:3716 UserTime_100Ns:0} -5404 {ImageName:csrss.exe CreatedAt:2017-10-10T17:51:45.1848844Z KernelTime_100Ns:0 MemoryCommitBytes:606208 MemoryWorkingSetPrivateBytes:339968 MemoryWorkingSetSharedBytes:1560576 ProcessID:5404 UserTime_100Ns:0} -3628 {ImageName:wininit.exe CreatedAt:2017-10-10T17:51:45.1974386Z KernelTime_100Ns:156250 MemoryCommitBytes:983040 MemoryWorkingSetPrivateBytes:610304 MemoryWorkingSetSharedBytes:3448832 ProcessID:3628 UserTime_100Ns:0} -8576 {ImageName:services.exe CreatedAt:2017-10-10T17:51:45.2091635Z KernelTime_100Ns:468750 MemoryCommitBytes:2048000 MemoryWorkingSetPrivateBytes:1437696 MemoryWorkingSetSharedBytes:4182016 ProcessID:8576 UserTime_100Ns:0} -7892 {ImageName:lsass.exe CreatedAt:2017-10-10T17:51:45.2177712Z KernelTime_100Ns:937500 MemoryCommitBytes:2666496 MemoryWorkingSetPrivateBytes:1982464 MemoryWorkingSetSharedBytes:7561216 ProcessID:7892 UserTime_100Ns:312500} -6384 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:45.3676107Z KernelTime_100Ns:468750 MemoryCommitBytes:1896448 MemoryWorkingSetPrivateBytes:1277952 MemoryWorkingSetSharedBytes:4730880 ProcessID:6384 UserTime_100Ns:156250} -4904 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:45.5431743Z KernelTime_100Ns:312500 MemoryCommitBytes:1781760 MemoryWorkingSetPrivateBytes:1331200 MemoryWorkingSetSharedBytes:4952064 ProcessID:4904 UserTime_100Ns:0} -2092 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:45.5838844Z KernelTime_100Ns:156250 MemoryCommitBytes:2486272 MemoryWorkingSetPrivateBytes:2117632 MemoryWorkingSetSharedBytes:5668864 ProcessID:2092 UserTime_100Ns:312500} -6576 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:45.727607Z KernelTime_100Ns:156250 MemoryCommitBytes:1818624 MemoryWorkingSetPrivateBytes:1417216 MemoryWorkingSetSharedBytes:6684672 ProcessID:6576 UserTime_100Ns:156250} -2412 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:46.0427889Z KernelTime_100Ns:468750 MemoryCommitBytes:5570560 MemoryWorkingSetPrivateBytes:3915776 MemoryWorkingSetSharedBytes:5963776 ProcessID:2412 UserTime_100Ns:0} -5472 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:46.0827893Z KernelTime_100Ns:312500 MemoryCommitBytes:2625536 MemoryWorkingSetPrivateBytes:1908736 MemoryWorkingSetSharedBytes:7532544 ProcessID:5472 UserTime_100Ns:312500} -8756 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:46.1108672Z KernelTime_100Ns:312500 MemoryCommitBytes:1843200 MemoryWorkingSetPrivateBytes:1466368 MemoryWorkingSetSharedBytes:4612096 ProcessID:8756 UserTime_100Ns:0} -1508 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:46.1522136Z KernelTime_100Ns:2812500 MemoryCommitBytes:4816896 MemoryWorkingSetPrivateBytes:3600384 MemoryWorkingSetSharedBytes:9281536 ProcessID:1508 UserTime_100Ns:468750} -4612 {ImageName:svchost.exe CreatedAt:2017-10-10T17:51:46.2212148Z KernelTime_100Ns:937500 MemoryCommitBytes:3063808 MemoryWorkingSetPrivateBytes:2265088 MemoryWorkingSetSharedBytes:8667136 ProcessID:4612 UserTime_100Ns:156250} -5936 {ImageName:CExecSvc.exe CreatedAt:2017-10-10T17:51:46.2224031Z KernelTime_100Ns:0 MemoryCommitBytes:983040 MemoryWorkingSetPrivateBytes:737280 MemoryWorkingSetSharedBytes:3723264 ProcessID:5936 UserTime_100Ns:0} -4416 {ImageName:cmd.exe CreatedAt:2017-10-10T17:51:46.5943846Z KernelTime_100Ns:0 MemoryCommitBytes:1564672 MemoryWorkingSetPrivateBytes:356352 MemoryWorkingSetSharedBytes:2174976 ProcessID:4416 UserTime_100Ns:0} -8700 {ImageName:powershell.exe CreatedAt:2017-10-10T17:51:46.6120645Z KernelTime_100Ns:2343750 MemoryCommitBytes:24522752 MemoryWorkingSetPrivateBytes:19853312 MemoryWorkingSetSharedBytes:27156480 ProcessID:8700 UserTime_100Ns:10156250} -``` -""" - -[breaking] - [breaking.metrics] - pr = 1235 - description = """ """ diff -Nru containerd-1.2.6/releases/v1.0.0-beta.3.toml containerd-1.5.9/releases/v1.0.0-beta.3.toml --- containerd-1.2.6/releases/v1.0.0-beta.3.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.0.0-beta.3.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0-beta.2" - -pre_release = true - -preface = """\ -After rounding out the feature set in beta.2, we have taken a number of stability fixes. - -This release contains mostly bug fixes, code cleanup and improvements to useability of -the client and ctr tool.""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - - [notes.ctr] - title= "`ctr` makeover" - description = """\ -`ctr` is getting a ~makeover~! The end goal is for commands to be consistent and scoped. -Most notably: -- `push`, `pull` are now `images` subcommands: `ctr images push`, `ctr images pull` -- `fetch`, `fetch-object`, and `push-object` are `content` subcommands -- `rootfs unpack` is now `snapshot unpack` -- `apply` no longer exists. RIP""" - - [notes.gc] - title= "Garbage collector improvements" - description = """\ -The garbage collector continues to improve with this release, including bug -fixes on the client causing races and a new lease feature for making retention -from the client easier. - -The lease API was added to make it easier for clients to prevent content and -snapshots from being garbage collected while they are being actively worked on -(such as from pull, import, or checkpoint). The API includes functions for -creating, deleting, and listing leases. The lease gets attached to the context -and the backend metadata store sees it and associates newly created content -and snapshots with that lease. - -Leases are currently acquired and released automatically through the client. -From the user perspective, fewer `gc.root` labels should be seen on client -during pull/import operations or left over after a failed operation.""" - - - -[breaking] diff -Nru containerd-1.2.6/releases/v1.0.0-rc.0.toml containerd-1.5.9/releases/v1.0.0-rc.0.toml --- containerd-1.2.6/releases/v1.0.0-rc.0.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.0.0-rc.0.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0-beta.3" - -pre_release = true - -preface = """\ -The final 1.0 release stretch has been reached after 7 alphas and 4 betas full -of stability fixes, hardening, and API improvements. This release candidate -continues that pattern in including stability fixes, usability improvements and -performance optimizations. - -As part of the preparation for supporting the release of Containerd 1.0, the -governance model has been updated. The same as in previous versions, the day to -day management of the project is taken care of by the maintainers. The roles -of chief maintainer and BDFL have been removed and a technical steering -committee has been added as an escalation point when consensus cannot be reached -among maintainers. See https://github.com/moby/tsc.""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - - [notes.ctr] - title= "Shim Memory Improvements" - description = """\ -The shim memory usage has been identified as a key component to optimize. The -shim gets run for every container making memory usage multiplied by the -number of containers on a machine, requiring lower memory usage in order to -increase density. - -In profiling the memory usage of the shim, it was discovered that the HTTP2 -and GRPC stacks were accounting for a majority of the usage. Since the RPC -requests to the shim are fairly simple and there is no need for handling many -clients, a simpler protocol is now used with much less overhead. In order to -avoid changing the client or server code, ttrpc is used to generate code -similar to GRPC using the same protocol definitions, but using the lighter -weight protocol. This had the effect of drastically reducing the memory -usage of the shim. - -Memory improvements over beta 2... -``` - RSS CMD - 3644 containerd-shim -namespace default -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/default/test10 -address /run/containerd/containerd.sock -containerd-binary /usr/local/bin/containerd -debug -15320 docker-containerd-shim --namespace moby --workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/ffa219303c1419b179393a1123f176bb4268337432b0ca7945bc7ac66db73cad --address /var/run/docker/containerd/docker-containerd.sock --runtime-root /var/run/docker/ -``` - -See [ttrpc repository](https://github.com/stevvooe/ttrpc) for implementation.""" - - [notes.gc] - title= "Garbage Collector Improvements" - description = """\ -Garbage collection is now scheduled by a background process which watches -changes and tracks the amount of time garbage collection is taking. It is able -to use that information to schedule garbage collection based on configuration -options. The default configuration option aims to limit the amount of time the -metadata store is locked for garbage collection to 20ms of every second. - -Additionally image removal now has an option to synchronously cleanup all -referenced resources (such as snapshots). This option immediately schedules a -garbage collection and waits for it to complete before returning to the client. -Since the time to remove a snapshot depends on the size of the snapshot, the -time to synchronously remove an image cannot be consistent. For faster and -more consistent removals, images should be deleted asynchronously whenever -possible. Asynchronous remains the default.""" - - -[breaking] - [breaking.api] - pr = 1797 - description = "The snapshots GRPC service was renamed from snapshot." - - [breaking.shim] - pr = 1767 - description = """\ -The shim protocol has changed to use ttrpc. The new protocol does not use -http2 and is not compatible with previous shim versions using grpc.""" diff -Nru containerd-1.2.6/releases/v1.1.0-rc.0.toml containerd-1.5.9/releases/v1.1.0-rc.0.toml --- containerd-1.2.6/releases/v1.1.0-rc.0.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.1.0-rc.0.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0" - -pre_release = true - -preface = """\ -`containerd` provides a daemon for managing running containers. - -1.1 is the second major release for `containerd` with added support for CRI, the -Kubernetes [Container Runtime Interface](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md). -CRI is a new plugin which allows connecting the containerd daemon directly to a -Kubernetes kubelet to be used as the container runtime. The CRI GRPC interface -listens on the same socket as the containerd GRPC interface and runs in the same -process. - -In addition to all of the stability and bug fixes backported to 1.0, -1.1 includes... - -- CRI plugin -- ZFS and AUFS snapshotter -- Improvements to the `ctr` tool -- Better support for multiple platforms -- Cross namespace content sharing -- Better mount cleanup -- Support for disabling plugins -- TCP debug address for remote debugging -- Update to Go 1.10 -- Improvements to the garbage collector - -## CRI Plugin - -This release of `cri` is a native plugin of `containerd`. It is built into -`containerd` v1.1 and CRI services are enabled by default. - -You can now use Kubernetes, with `containerd` directly, without having to use -the intermediate `cri-containerd` daemon. The `cri-containerd` daemon is -end-of-life. - -*Note: Please [drain your node](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/) before -upgrading from older versions of `cri-containerd` to `containerd` v1.1.* - -You can [use a containerd config file to configure the `cri` plugin](https://github.com/containerd/cri/blob/v1.0/docs/config.md). - -### Untrusted Workload Runtime - -To run an untrusted pod on a runtime for untrusted workload, such as -[Kata Containers](https://katacontainers.io/) or -[Clear Containers](https://clearlinux.org/containers), you can: -1. Configure a runtime for untrusted workload [with the config option `plugins.cri.containerd.untrusted_workload_runtime`](https://github.com/containerd/cri/blob/v1.0/docs/config.md). -2. Create an untrusted pod by setting the annotation `io.kubernetes.cri.untrusted-workload` to `true`, for example: -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: nginx - annotations: - io.kubernetes.cri.untrusted-workload: true -spec: - containers: - - name: nginx - image: nginx -``` - -By default, `cri` will run pods with the default runtime. However, if a pod has -the `io.kubernetes.cri.untrusted-workload` annotation, the `cri` plugin will run -the pod with the runtime for untrusted workloads. - -Unless configured otherwise, the default runtime is set to -[runc](https://github.com/opencontainers/runc). - -### Container Runtime Interface v1alpha2 - -The supported CRI (Container Runtime Interface) version for Kubernetes v1.10 is -now `v1alpha2.` This release of `cri` has been updated to use CRI `v1alpha2`, so -**it only works with Kubernetes v1.10+.** - -New CRI features added in `v1alpha2` are all supported: -* Container log rotation: Kubelet rotates container logs. -* Shared pid namespace: Support sharing pid namespace inside a pod. - -### Registry Mirror - -You can now setup registry configurations with the config option -`plugins.cri.registry`. - -Currently only the `mirrors` option is supported. With it, you can specify -registry mirrors and secure/insecure connections. -([doc](https://github.com/containerd/cri/blob/v1.0/docs/registry.md)) - -### End-To-End Test - -In terms of testing, we've passed: -* ALL CRI validation tests -* ALL node e2e tests -* ALL e2e tests - -The containerd test coverage on GCE is equivalent with Docker now. - -All the test results are public: https://k8s-testgrid.appspot.com/sig-node-containerd. - -### Performance - -We significantly improved pod start latency and cpu/memory usage of `cri` plugin -this release. - -The continuous benchmark result is published on http://node-perf-dash.k8s.io/. -Job `ci-kubernetes-node-kubelet-benchmark` is for Docker 17.03, and -`ci-cri-containerd-node-e2e-benchmark` is for containerd with `cri` plugin. - -All metrics of containerd are either better or comparable with Docker 17.03. - -## Try It Out - -If you would like to try containerd, please download the binaries included on -this release. If you are using Docker, this version of containerd will be used -in the next major release of Docker. - -To set up containerd with Kubernetes... -* For a production quality cluster on GCE brought up with `kube-up.sh`, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/kube-up.md). -* For a multi-node cluster installer and bring up steps using ansible and kubeadm, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/contrib/ansible/README.md). -* For creating a cluster from scratch on Google Cloud, see [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way). -* For a custom installation from release tarball, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/installation.md). -* To install use LinuxKit on a local VM, see [here](https://github.com/linuxkit/linuxkit/tree/master/projects/kubernetes). - -## Support - -The [_support horizon_](https://github.com/containerd/containerd/blob/master/RELEASES.md#support-horizon) -for containerd has been updated to include the 1.1 release. With the addition of -the CRI plugin, we are expanding the support horizon for 1.1 to include the -entire lifespan of Kubernetes 1.10. The containerd 1.1 release train will be -considered an active branch with new patches until March 23, 2019 at the -earliest, when 1.2 is released, or until Kubernetes 1.10 reaches end of life. -The 1.1 containerd API is completely compatible with 1.0, any client using 1.0 -can safely upgrade to 1.1 without any incompatibilies. The CRI interface -included with the CRI plugin is only supported for Kubernetes 1.10. The CRI -interface is still considered alpha and will only be supported for Kubernetes -1.10. The CRI plugin in containerd 1.1 will also only be supported for -Kubernetes 1.10. -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.1.0-rc.1.toml containerd-1.5.9/releases/v1.1.0-rc.1.toml --- containerd-1.2.6/releases/v1.1.0-rc.1.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.1.0-rc.1.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0" - -pre_release = true - -preface = """\ -`containerd` provides a daemon for managing running containers. - -1.1 is the second major release for `containerd` with added support for CRI, the -Kubernetes [Container Runtime Interface](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md). -CRI is a new plugin which allows connecting the containerd daemon directly to a -Kubernetes kubelet to be used as the container runtime. The CRI GRPC interface -listens on the same socket as the containerd GRPC interface and runs in the same -process. - -In addition to all of the stability and bug fixes backported to 1.0, -1.1 includes... - -- CRI plugin -- ZFS and AUFS snapshotter -- Improvements to the `ctr` tool -- Better support for multiple platforms -- Cross namespace content sharing -- Better mount cleanup -- Support for disabling plugins -- TCP debug address for remote debugging -- Update to Go 1.10 -- Improvements to the garbage collector - -## CRI Plugin - -This release of `cri` is a native plugin of `containerd`. It is built into -`containerd` v1.1 and CRI services are enabled by default. - -You can now use Kubernetes, with `containerd` directly, without having to use -the intermediate `cri-containerd` daemon. The `cri-containerd` daemon is -end-of-life. - -*Note: Please [drain your node](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/) before -upgrading from older versions of `cri-containerd` to `containerd` v1.1.* - -You can [use a containerd config file to configure the `cri` plugin](https://github.com/containerd/cri/blob/v1.0/docs/config.md). - -### Untrusted Workload Runtime - -To run an untrusted pod on a runtime for untrusted workload, such as -[Kata Containers](https://katacontainers.io/) or -[Clear Containers](https://clearlinux.org/containers), you can: -1. Configure a runtime for untrusted workload [with the config option `plugins.cri.containerd.untrusted_workload_runtime`](https://github.com/containerd/cri/blob/v1.0/docs/config.md). -2. Create an untrusted pod by setting the annotation `io.kubernetes.cri.untrusted-workload` to `true`, for example: -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: nginx - annotations: - io.kubernetes.cri.untrusted-workload: true -spec: - containers: - - name: nginx - image: nginx -``` - -By default, `cri` will run pods with the default runtime. However, if a pod has -the `io.kubernetes.cri.untrusted-workload` annotation, the `cri` plugin will run -the pod with the runtime for untrusted workloads. - -Unless configured otherwise, the default runtime is set to -[runc](https://github.com/opencontainers/runc). - -### Container Runtime Interface v1alpha2 - -The supported CRI (Container Runtime Interface) version for Kubernetes v1.10 is -now `v1alpha2.` This release of `cri` has been updated to use CRI `v1alpha2`, so -**it only works with Kubernetes v1.10+.** - -New CRI features added in `v1alpha2` are all supported: -* Container log rotation: Kubelet rotates container logs. -* Shared pid namespace: Support sharing pid namespace inside a pod. - -### Registry Mirror - -You can now setup registry configurations with the config option -`plugins.cri.registry`. - -Currently only the `mirrors` option is supported. With it, you can specify -registry mirrors and secure/insecure connections. -([doc](https://github.com/containerd/cri/blob/v1.0/docs/registry.md)) - -### End-To-End Test - -In terms of testing, we've passed: -* ALL CRI validation tests -* ALL node e2e tests -* ALL e2e tests - -The containerd test coverage on GCE is equivalent with Docker now. - -All the test results are public: https://k8s-testgrid.appspot.com/sig-node-containerd. - -### Performance - -We significantly improved pod start latency and cpu/memory usage of `cri` plugin -this release. - -The continuous benchmark result is published on http://node-perf-dash.k8s.io/. -Job `ci-kubernetes-node-kubelet-benchmark` is for Docker 17.03, and -`ci-cri-containerd-node-e2e-benchmark` is for containerd with `cri` plugin. - -All metrics of containerd are either better or comparable with Docker 17.03. - -## Try It Out - -If you would like to try containerd, please download the binaries included on -this release. If you are using Docker, this version of containerd will be used -in the next major release of Docker. - -To set up containerd with Kubernetes... -* For a production quality cluster on GCE brought up with `kube-up.sh`, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/kube-up.md). -* For a multi-node cluster installer and bring up steps using ansible and kubeadm, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/contrib/ansible/README.md). -* For creating a cluster from scratch on Google Cloud, see [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way). -* For a custom installation from release tarball, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/installation.md). -* To install use LinuxKit on a local VM, see [here](https://github.com/linuxkit/linuxkit/tree/master/projects/kubernetes). - -## Support - -The [_support horizon_](https://github.com/containerd/containerd/blob/master/RELEASES.md#support-horizon) -for containerd has been updated to include the 1.1 release. With the addition of -the CRI plugin, we are expanding the support horizon for 1.1 to include the -entire lifespan of Kubernetes 1.10. The containerd 1.1 release train will be -considered an active branch with new patches until April 4, 2019 at the -earliest, when 1.2 is released, or until Kubernetes 1.10 reaches end of life. -The 1.1 containerd API is completely compatible with 1.0, any client using 1.0 -can safely upgrade to 1.1 without any incompatibilies. The CRI interface -included with the CRI plugin is only supported for Kubernetes 1.10. The CRI -interface is still considered alpha and will only be supported for Kubernetes -1.10. The CRI plugin in containerd 1.1 will also only be supported for -Kubernetes 1.10. -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.1.0-rc.2.toml containerd-1.5.9/releases/v1.1.0-rc.2.toml --- containerd-1.2.6/releases/v1.1.0-rc.2.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.1.0-rc.2.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" - -# previous release -previous = "v1.0.0" - -pre_release = true - -preface = """\ -`containerd` provides a daemon for managing running containers. - -1.1 is the second major release for `containerd` with added support for CRI, the -Kubernetes [Container Runtime Interface](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md). -CRI is a new plugin which allows connecting the containerd daemon directly to a -Kubernetes kubelet to be used as the container runtime. The CRI GRPC interface -listens on the same socket as the containerd GRPC interface and runs in the same -process. - -In addition to all of the stability and bug fixes backported to 1.0, -1.1 includes... - -- CRI plugin -- ZFS and AUFS snapshotter -- Improvements to the `ctr` tool -- Better support for multiple platforms -- Cross namespace content sharing -- Better mount cleanup -- Support for disabling plugins -- TCP debug address for remote debugging -- Update to Go 1.10 -- Improvements to the garbage collector - -## CRI Plugin - -This release of `cri` is a native plugin of `containerd`. It is built into -`containerd` v1.1 and CRI services are enabled by default. - -You can now use Kubernetes, with `containerd` directly, without having to use -the intermediate `cri-containerd` daemon. The `cri-containerd` daemon is -end-of-life. - -*Note: Please [drain your node](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/) before -upgrading from older versions of `cri-containerd` to `containerd` v1.1.* - -You can [use a containerd config file to configure the `cri` plugin](https://github.com/containerd/cri/blob/v1.0/docs/config.md). - -### Untrusted Workload Runtime - -To run an untrusted pod on a runtime for untrusted workload, such as -[Kata Containers](https://katacontainers.io/) or -[Clear Containers](https://clearlinux.org/containers), you can: -1. Configure a runtime for untrusted workload [with the config option `plugins.cri.containerd.untrusted_workload_runtime`](https://github.com/containerd/cri/blob/v1.0/docs/config.md). -2. Create an untrusted pod by setting the annotation `io.kubernetes.cri.untrusted-workload` to `"true"`, for example: -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: nginx - annotations: - io.kubernetes.cri.untrusted-workload: "true" -spec: - containers: - - name: nginx - image: nginx -``` - -By default, `cri` will run pods with the default runtime. However, if a pod has -the `io.kubernetes.cri.untrusted-workload` annotation, the `cri` plugin will run -the pod with the runtime for untrusted workloads. - -Unless configured otherwise, the default runtime is set to -[runc](https://github.com/opencontainers/runc). - -### Container Runtime Interface v1alpha2 - -The supported CRI (Container Runtime Interface) version for Kubernetes v1.10 is -now `v1alpha2.` This release of `cri` has been updated to use CRI `v1alpha2`, so -**it only works with Kubernetes v1.10+.** - -New CRI features added in `v1alpha2` are all supported: -* Container log rotation: Kubelet rotates container logs. -* Shared pid namespace: Support sharing pid namespace inside a pod. - -### Registry Mirror - -You can now setup registry configurations with the config option -`plugins.cri.registry`. - -Currently only the `mirrors` option is supported. With it, you can specify -registry mirrors and secure/insecure connections. -([doc](https://github.com/containerd/cri/blob/v1.0/docs/registry.md)) - -### End-To-End Test - -In terms of testing, we've passed: -* ALL CRI validation tests -* ALL node e2e tests -* ALL e2e tests - -The containerd test coverage on GCE is equivalent with Docker now. - -All the test results are public: https://k8s-testgrid.appspot.com/sig-node-containerd. - -### Performance - -We significantly improved pod start latency and cpu/memory usage of `cri` plugin -this release. - -The continuous benchmark result is published on http://node-perf-dash.k8s.io/. -Job `ci-kubernetes-node-kubelet-benchmark` is for Docker 17.03, and -`ci-cri-containerd-node-e2e-benchmark` is for containerd with `cri` plugin. - -All metrics of containerd are either better or comparable with Docker 17.03. - -## Try It Out - -If you would like to try containerd, please download the binaries included on -this release. If you are using Docker, this version of containerd will be used -in the next major release of Docker. - -To set up containerd with Kubernetes... -* For a production quality cluster on GCE brought up with `kube-up.sh`, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/kube-up.md). -* For a multi-node cluster installer and bring up steps using ansible and kubeadm, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/contrib/ansible/README.md). -* For creating a cluster from scratch on Google Cloud, see [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way). -* For a custom installation from release tarball, see [here](https://github.com/kubernetes-incubator/cri-containerd/blob/v1.0/docs/installation.md). -* To install use LinuxKit on a local VM, see [here](https://github.com/linuxkit/linuxkit/tree/master/projects/kubernetes). - -## Support - -The [_support horizon_](https://github.com/containerd/containerd/blob/master/RELEASES.md#support-horizon) -for containerd has been updated to include the 1.1 release. With the addition of -the CRI plugin, we are expanding the support horizon for 1.1 to include the -entire lifespan of Kubernetes 1.10. The containerd 1.1 release train will be -considered an active branch with new patches until April 13, 2019 at the -earliest, when 1.2 is released, or until Kubernetes 1.10 reaches end of life. -The 1.1 containerd API is completely compatible with 1.0, any client using 1.0 -can safely upgrade to 1.1 without any incompatibilies. The CRI interface -included with the CRI plugin is only supported for Kubernetes 1.10. The CRI -interface is still considered alpha and will only be supported for Kubernetes -1.10. The CRI plugin in containerd 1.1 will also only be supported for -Kubernetes 1.10. -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.2.0-beta.toml containerd-1.5.9/releases/v1.2.0-beta.toml --- containerd-1.2.6/releases/v1.2.0-beta.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.0-beta.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.1.0" - -pre_release = true - -preface = """\ -After two major releases of containerd, we have brought back the beta releases to -introduce a new runtime interface and new APIs. The 1.2 release will be fully -backwards compatible and has no API breakage. The API additions included in -this release are focused on making containerd more extensible and cover more -user cases. - -### New V2 Runtime - -A new v2 runtime has been added with a stable gRPC interface for managing -containers through external shims. - -This allows runtime authors to easily integrate with containerd over a stable -API. - -Various runtimes can be selected on a per container basis using the `WithRuntime` opt -or to test via ctr `ctr run --runtime io.containerd.runc.v1`. - -[Documentation](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md) - -### New Proxy Plugins - -A new proxy plugin configuration has been added to allow external snapshotters -be connected to containerd using gRPC. - -[Documentation](https://github.com/containerd/containerd/blob/master/PLUGINS.md) - -### Managed /opt directory - -A new `Install` method on the containerd client allows users to publish host level -binaries using standard container build tooling and container distribution tooling -to download containerd related binaries on their systems. - -This can be used for v2 runtime authors to get their runtime shims on an existing -containerd system. It can also be used to install `runc` and other related tools. - -```bash -> ctr content fetch docker.io/crosbymichael/runc:latest -> ctr install docker.io/crosbymichael/runc:latest -``` - -[Documentation](https://github.com/containerd/containerd/blob/master/docs/managed-opt.md) - -### Garbage Collection - -Add support for cleaning up leases and content ingests to garbage collections. - -Add expiration label to clean up temporary resources. - -### API Changes - -Minor API additions - -### Other Improvements - -Improved multi-arch image support using more precise matching and ranking""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] - -[rename_deps] - [rename_deps.ttrpc] - old = "github.com/stevvooe/ttrpc" - new = "github.com/containerd/ttrpc" diff -Nru containerd-1.2.6/releases/v1.2.1.toml containerd-1.5.9/releases/v1.2.1.toml --- containerd-1.2.6/releases/v1.2.1.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.1.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.0" - -pre_release = false - -preface = """\ -The first patch release for `containerd` 1.2 includes several -runtime and CRI fixes. - -## Runtime -* Fix race in process state when pausing containers -* Optimize runtime v1 shim locking -* Fix hang processing events -* Increase event buffer size -* Fix broken pipe causing shim hang -* Update runc - -## CRI -* Remove auth config logs -* Fix NetNS cache state -* Fix a bug that containers sharing pod pid namespace can't be stopped -* Remove host pid usage to work better with katacontainer - -## Service -* Ignore modprobe failures in systemd ExecStartPre""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] - -[rename_deps] diff -Nru containerd-1.2.6/releases/v1.2.2.toml containerd-1.5.9/releases/v1.2.2.toml --- containerd-1.2.6/releases/v1.2.2.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.2.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.1" - -pre_release = false - -preface = """\ -The second patch release for `containerd` 1.2 includes important -runtime and CRI fixes. - -## Runtime -* Fix rare deadlock on FIFO creation with timeout - -## CRI - -**ACTION REQUIRED:** -For Kubernetes support, when upgrading containerd from 1.2.0 (including rc releases) -to 1.2.1+, a node reboot is recommended to avoid a known deadlock in 1.2.0. -See [containerd/cri#1018](https://github.com/containerd/cri/issues/1018) - -* Fix a bug that a container can't be stopped or inspected when its corresponding image is deleted -* Fix a bug that the cri plugin handles containerd events outside of `k8s.io` namespace""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] - -[rename_deps] diff -Nru containerd-1.2.6/releases/v1.2.3.toml containerd-1.5.9/releases/v1.2.3.toml --- containerd-1.2.6/releases/v1.2.3.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.3.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.2" - -pre_release = false - -preface = """\ -The third patch release for `containerd` 1.2 contains important fixes -for container image backwards compatibility as well as some runtime and -CRI issues. - -### Notable Updates -* fix in Tar xattrs to restore compatibility with older container images [#2953](https://github.com/containerd/containerd/pull/2953) -* background `O_NONBLOCK` in OpenFifo to fix uncancelled context timeout issue -* updated `PlatformRuntime` interface to include Add/Delete methods -* runtime: exec race condition fixed [#2970](https://github.com/containerd/containerd/pull/2970) -* cri: fixed issues with extra newline character in log without an extra newline [#2984](https://github.com/containerd/containerd/pull/2984) -* cri: fixed an issue with pods being ignored after load failures [#2984](https://github.com/containerd/containerd/pull/2984) -* runc updated to 12f6a991201fdb8f82579582d5e00e28fba06d0a -* cri updated to c3cf754321fc38c6af5dfd2552fdde0ad192b31d - -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] - -[rename_deps] - [rename_deps.ttrpc] - old = "github.com/stevvooe/ttrpc" - new = "github.com/containerd/ttrpc" diff -Nru containerd-1.2.6/releases/v1.2.4.toml containerd-1.5.9/releases/v1.2.4.toml --- containerd-1.2.6/releases/v1.2.4.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.4.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.3" - -pre_release = false - -preface = """\ -The fourth patch release for `containerd` 1.2 re-vendors -`runc` which includes the patch for the critical CVE-2019-5736 escape -vulnerability. This release also includes a few fixes for the CRI plugin as -well as a change for Windows; all these changes are noted below. - -### Notable Updates -* cri: Set /etc/hostname [#1042](https://github.com/containerd/cri/pull/1042) -* cri: Fix env performance issue [#1045](https://github.com/containerd/cri/pull/1045) -* runc updated to 6635b4f0c6af3810594d2770f662f34ddc15b40d to solve CVE-2019-5736 -* cri updated to da0c016c830b2ea97fd1d737c49a568a816bf964 -* Windows: NewDirectIOFromFIFOSet [#2934](https://github.com/containerd/containerd/pull/2934) - -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.2.5.toml containerd-1.5.9/releases/v1.2.5.toml --- containerd-1.2.6/releases/v1.2.5.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.5.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.4" - -pre_release = false - -preface = """\ -The fifth patch release for `containerd` 1.2 contains fixes -for image management, cgroup management and the -CRI plugin. -It also updates runc to include an improved fix for CVE-2019-5736 -to reduce the increased memory-consumption introduced by the original -patch. -All these changes are noted below. -### Notable Updates -* Fix an issue that non-existent parent directory in image layers is created with permission -`0700`. [#3017](https://github.com/containerd/containerd/issues/3017) -* Fix an issue that snapshots of the base image can be deleted by mistake, when images -built on top of it are deleted. [#3087](https://github.com/containerd/containerd/pull/3087) -* Support for GC references to content from snapshot and container objects. [#3080](https://github.com/containerd/containerd/pull/3080) -* cri: Fix a bug that pod can't get started when the same volume is defined -differently in the image and the pod spec. [cri#1059](https://github.com/containerd/cri/issues/1059) -* cri: Fix a bug that causes container start failure after in-place upgrade containerd -to 1.2.4+ or 1.1.6+. [cri#1082](https://github.com/containerd/cri/issues/1082) -* cgroups updated to dbea6f2bd41658b84b00417ceefa416b97 to fix issues for systemd 420 and -non-existent cgroups. [#3079](https://github.com/containerd/containerd/pull/3079) -* runc updated to 2b18fe1d885ee5083ef9f0838fee39b62d653e30 to include the improved -fix for CVE-2019-5736. [#3082](https://github.com/containerd/containerd/pull/3082) -* cri updated to a92c40017473cbe0239ce180125f12669757e44f. [#3084](https://github.com/containerd/containerd/pull/3084) -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.2.6.toml containerd-1.5.9/releases/v1.2.6.toml --- containerd-1.2.6/releases/v1.2.6.toml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/releases/v1.2.6.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# commit to be tagged for new release -commit = "HEAD" - -project_name = "containerd" -github_repo = "containerd/containerd" -match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" - -# previous release -previous = "v1.2.5" - -pre_release = false - -preface = """\ -The sixth patch release for `containerd` 1.2 contains fixes -for the containerd client, the CRI plugin and containerd io -and mount handling. - -It whitelists 2 new syscalls in the default seccomp profile, -and also updates CNI to v0.7.5 to include the fix for [CVE-2019-9946](https://nvd.nist.gov/vuln/detail/CVE-2019-9946). - -All these changes are noted below. -### Notable Updates -* Allow overriding package name in `containerd --version` output. [#3098](https://github.com/containerd/containerd/pull/3098) -* Add 2 new syscalls `io_pgetevents` and `statx` in the default seccomp whitelist. [#3113](https://github.com/containerd/containerd/pull/3113) [#3115](https://github.com/containerd/containerd/pull/3115) -* Fix a bug that custom containerd cgroup path does not work in containerd 1.2.5. [#3143](https://github.com/containerd/containerd/pull/3143) -* Fix a bug in the containerd client that `WithAllCapabilities` applies incomplete capability list. [#3147](https://github.com/containerd/containerd/pull/3147) -* Fix a bug that container output can be incomplete when stdout and stderr are pointed to the same file. [#3118](https://github.com/containerd/containerd/issues/3118) -* Fix a bug that containerd can't properly handle space in mount point path. [3161](https://github.com/containerd/containerd/pull/3161) -* cri: fix a bug that containers being gracefully stopped are SIGKILLed when kubelet is restarted. [cri#1098](https://github.com/containerd/cri/issues/1098) -* cri: Fix a bug that pod UTS namespace is used for host network. [cri#1111](https://github.com/containerd/cri/pull/1111) -* cri: Update CNI plugins to v0.7.5 for [CVE-2019-9946](https://nvd.nist.gov/vuln/detail/CVE-2019-9946). -* Update cri to eb926cd79d3bac188dcc4ed7694fc9298f8831be. [#3174](https://github.com/containerd/containerd/pull/3174) -* Update runc to v1.0.0-rc7-6-g029124da [#3183](https://github.com/containerd/containerd/pull/3183) to fix potential container start failure on non-SELinux system. [runc#2030](https://github.com/opencontainers/runc/issues/2030) -""" - -# notable prs to include in the release notes, 1234 is the pr number -[notes] - -[breaking] diff -Nru containerd-1.2.6/releases/v1.3.0.toml containerd-1.5.9/releases/v1.3.0.toml --- containerd-1.2.6/releases/v1.3.0.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.3.0.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,99 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.2.0" + +pre_release = false + +preface = """\ +The fourth major release of containerd comes 11 months after the previous +major release and covers a period of both significant project growth and +further stabilization. Similar to previous releases, the number of API changes +are small and, as always, backwards compatible. The growing ecosystem of plugins +and users have driven improvements to make containerd more configurable, usable, +and pluggable. On Windows, this release brings a new runtime utilizing the shim +API. For clients, there are many new features and improvements completely +implemented in the client libraries without requiring daemon upgrade. + +### Runtime +* **New Windows V2 runtime using shim API.** Adds support for the Windows runtime shims in containerd. *NOTE: while containerd's runtime is stable in this release, running Windows containers are not yet fully supported until the [runhcs shim](https://github.com/microsoft/hcsshim/tree/master/cmd/containerd-shim-runhcs-v1) is fully supported.* +* **Improvements to ttrpc.** For better daemon to shim communication (https://github.com/containerd/containerd/pull/3341) +* **Removed experimental Windows V1 runtime** +* **Update runc dependency** Updated runc for CVE-2019-16884 + +### Snapshots +* **New Devmapper snapshotter** (https://github.com/containerd/containerd/pull/3022) +* **Improved label support for plugins.** Allows snapshot plugins to use labels from clients for advanced use cases + +### Plugins +* **Support for plugins registering as a TCP service** +* **Configurable plugin directory** +* **Add stream processor plugin.** Allow handling of custom media types during unpack (https://github.com/containerd/containerd/pull/3482) + +### Client +* **Default handling from namespace labels.** Allows defaults to be configured per containerd namespace (https://github.com/containerd/containerd/pull/3403) +* **Improved Docker resolver with mirroring support** +* **Support for cross repository push** (https://github.com/containerd/containerd/pull/3218) + +### API +* **Add support for direct resource management in leases** (https://github.com/containerd/containerd/pull/3304) +* **Add ttrpc service for shim event publishing** +* **Add annotations to descriptors in API** +* **Add id to TaskDelete event message to match exec id** +* **Add payload parameter to apply in diff service API** + +### CRI +This version of containerd is validated against v1.16, but it is also compatible with Kubernetes v1.12+. (See [more details](https://github.com/containerd/cri#support-metrics) about support metrics) + +#### Features +* **Supported per-pod containerd shim.** The `io.containerd.runc.v2` runtime is fully validated and ready to be used in production. This helps minimizing per-pod resource overhead. Note that `io.containerd.runtime.v1.linux` is still the default runtime. (https://github.com/containerd/cri/issues/1075) +* **Added file-based generic runtime config options.** This will be used by out-of-tree runtimes like gvisor and kata (https://github.com/containerd/cri/pull/1029), e.g. +``` +[plugins.cri.containerd.runtimes.kata] + runtime_type = "io.containerd.kata.v1" +[plugins.cri.containerd.runtimes.kata.options] + TypeUrl = "io.containerd.kata.v1.options" + ConfigPath = "/etc/kata/config.toml" +``` +* **Added the `pod_annotations` runtime option.** Pod annotations specified in the list will be passed to the runtime as OCI annotations. This enables runtimes to support annotation-based experimental features. (https://github.com/containerd/cri/pull/1084) +* **Added `stream_idle_time` option.** This makes idle connection timeout of the streaming server configurable. (https://github.com/containerd/cri/issues/1057) +* **Added [traffic shaping pod annotations](https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#support-traffic-shaping) support.** *NOTE: traffic shaping is still an experimental feature in Kubernetes.* (https://github.com/containerd/cri/issues/1150) +* **Added `max_conf_num` option to `plugins.cri.cni`**. This makes it possible to setup multiple CNI networks in a pod. *NOTE: multi-network is not an officially supported feature in Kubernetes.*(https://github.com/containerd/cri/issues/1154) +* **Added `plugins.cri.registry.configs` option to support TLS and auth configs of registries.** (https://github.com/containerd/cri/issues/1143) *NOTE: Non-mutual TLS is also supported. (https://github.com/containerd/containerd/issues/3521)* (see [registry.md](https://github.com/containerd/cri/blob/f1d492b0cdd14e76476ee4dd024696ce3634e501/docs/registry.md) for more details) +* **Added tcp endpoint for CRI service.** The tcp service can be disabled with the `disable_tcp_service` option, and it is disabled by default. (https://github.com/containerd/cri/issues/1181) +* **Added `max_concurrent_downloads` option to restrict the number of concurrent downloads for each image.** The default concurrency is `3`. (https://github.com/containerd/cri/pull/1211) +* **Added `privileged_without_host_devices` runtime option to disable host devices for privileged pods for the runtime.** This is especially useful for runtimes like kata. (https://github.com/containerd/cri/issues/1213) +* **Supported IPv4/IPv6 dualstack.** See Kubernetes [dual-stack doc](https://kubernetes.io/docs/concepts/services-networking/dual-stack) for more information. To enable dual-stack, your CNI plugin needs to support it. If you are using the CNI config template, see [how to configure it to support dual-stack](https://github.com/containerd/cri/blob/release/1.3/docs/config.md#cni-config-template). + +#### Enhancements +* Avoided `Status` lockup when CNI network setup/teardown is slow. (https://github.com/containerd/cri/issues/1078) +* Added CNI config in `Status` (`crictl info`) output. (https://github.com/containerd/cri/pull/1158) +* Supported URL path in `plugins.cri.registry.mirrors`, e.g. `https://my.custom.registry/anypath`. (https://github.com/containerd/cri/pull/1227) +* Added wildcard `*` support in `plugins.cri.registry.mirrors`. (https://github.com/containerd/cri/issues/1196) +* Removed an unnecessary round-trip to the image registry when pulling image. (https://github.com/containerd/cri/issues/1229) +* Updated cni library to v0.7.1 which has better context cancellation support. (https://github.com/containerd/cri/issues/1236) +* Updated cni plugins to v0.7.6 to fix a race condition in the `bridge` plugin. (https://github.com/containerd/containerd/issues/3507) + +#### Deprecation +* `ctr cri load` command is deprecated, use `ctr -n=k8s.io images import` instead.(https://github.com/containerd/cri/issues/909) +* The `plugins.cri.containerd.default_runtime` option is deprecated, use `plugins."io.containerd.grpc.v1.cri".containerd.default_runtime_name` instead. (https://github.com/containerd/cri/issues/1076) +* Runtime options including `systemd_cgroups`, `runtime_engine` and `runtime_root` are deprecated, use runtime `options` instead. (https://github.com/containerd/cri/pull/1217) +* `runtimeHandler` field is moved from the sandbox `info` into `status`. (https://github.com/containerd/cri/pull/1063) +* `plugins.cri.registry.auths` is deprecated, use `plugins.cri.registry.configs` instead. (https://github.com/containerd/cri/pull/1227) + +### Other +* **Support additional garbage collection labels.** Allows more advanced resource management use cases on the client +* **Fix garbage collection scheduling on reference removal.** Ensures removal of leases or containers triggers the next scheduled garbage collection + + +And many more improvements and bug fixes in the complete changelog""" + +# notable prs to include in the release notes, 1234 is the pr number +[notes] + +[breaking] diff -Nru containerd-1.2.6/releases/v1.4.0.toml containerd-1.5.9/releases/v1.4.0.toml --- containerd-1.2.6/releases/v1.4.0.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.4.0.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,96 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.3.0" + +pre_release = false + +preface = """\ +The fifth major release of containerd includes a mix of new features and +expanded support, such as support for CGroups v2, expanded SELinux support, +support for Windows on Kubernetes through CRI, and support for snapshotters +based on shared remote storage. All significant bug and stability fixes included +in this release are also available on supported prior releases. Like previous +major releases, what is not included in this release is also important. There +are only two small additions to the API with no backwards incompatible changes, +allowing client and daemon upgrades to be done independently without disruption. +The incredible increase in usage of containerd over the last year has shown the +value of our core principles to easily expand support for different use cases +while driving toward ever increasing stability. + +### Runtime +* **Support cgroups v2** [#3726](https://github.com/containerd/containerd/pull/3726) +* **Improved SELinux support** +* **Rework shim logger shutdown process** [#4162](https://github.com/containerd/containerd/pull/4162) +* **Deprecate `io.containerd.runtime.v1.*` and `io.containerd.runc.v1`** [#4384](https://github.com/containerd/containerd/pull/4384) + +### Snapshots +* **Support target snapshot option on prepare to allow skipping prepare when snapshot reports target already exists** [#3793](https://github.com/containerd/containerd/pull/3793) +* **Add filters to walk function** [#3709](https://github.com/containerd/containerd/pull/3709) +* **Support for FUSE mounts** [#3765](https://github.com/containerd/containerd/pull/3765) +* **Snapshotter options passed to backend** [#4080](https://github.com/containerd/containerd/pull/4080) +* **Support for lazy-pull snapshotters such as [stargz-snapshotter](https://github.com/containerd/stargz-snapshotter)** + +### Plugins +* **Proxy snapshotter support for cleanup** [#3925](https://github.com/containerd/containerd/pull/3925) + +### Client +* **Add spec options for host device and privileged handling** [#3718](https://github.com/containerd/containerd/pull/3718) +* **WithLease takes options for more flexibility** [#3719](https://github.com/containerd/containerd/pull/3719) +* **Add unpack options for pull** [#3826](https://github.com/containerd/containerd/pull/3826) +* **Improve host fallback behaviour in docker remote** [#3868](https://github.com/containerd/containerd/pull/3868) +* **Defer layer download until unpack to support skipping download when snapshotter reports already exists** [#3870](https://github.com/containerd/containerd/pull/3870) +* **Split UID and GID namespace mapping in spec generation** [#3881](https://github.com/containerd/containerd/pull/3881) +* **Propagate snapshotter layer annotations on unpack** [#3911](https://github.com/containerd/containerd/pull/3911) +* **Create image record after blob download to fix concurrent download issue** [#3972](https://github.com/containerd/containerd/pull/3972) +* **Use spec's mountLabel when mounting container rootfs** [#4051](https://github.com/containerd/containerd/pull/4051) +* **Add Linux resources to spec options** [#4083](https://github.com/containerd/containerd/pull/4083) +* **New registry configuration tooling for improved mirror and endpoint options** [#4138](https://github.com/containerd/containerd/pull/4138) +* **Add namespace query parameter when using a registry proxy** [#4413](https://github.com/containerd/containerd/pull/4413) + +### API +* **Add filters to snapshot list** [#3709](https://github.com/containerd/containerd/pull/3709) +* **Add snapshot cleanup** [#3925](https://github.com/containerd/containerd/pull/3925) + +### Daemon +* **Support NOTIFY_SOCKET for notifying the daemon's readiness to systemd** [#4088](https://github.com/containerd/containerd/pull/4088) +* **Remove libseccomp requirement, seccomp support is now always built-in** [#4439](https://github.com/containerd/containerd/pull/4439) + +### Windows +* **Disk usage support in snapshotter** [#3785](https://github.com/containerd/containerd/pull/3785) +* **Add support for custom wcow and lcow sandbox scratch sizes** [#3965](https://github.com/containerd/containerd/pull/3965) +* **Enable CRI plugin** [#4076](https://github.com/containerd/containerd/pull/4076) + +### CRI + +* **Support CNI DNS capabilities** [cri#1244](https://github.com/containerd/cri/pull/1244) +* **Build CRI Plugin on Windows and add presubmit** [cri#1258](https://github.com/containerd/cri/pull/1258) +* **Use container annotations when creating containers** [cri#1260](https://github.com/containerd/cri/pull/1260) +* **Add support for Windows containers process isolation** [cri#1264](https://github.com/containerd/cri/pull/1264) +* **Add windows port forward support** [cri#1284](https://github.com/containerd/cri/pull/1284) +* **Use `http` for localhost registry connections** [cri#1328](https://github.com/containerd/cri/pull/1328) +* **Add `resolv.conf` to sandbox container mounts** [cri#1344](https://github.com/containerd/cri/pull/1344) +* **Use host devices options from oci specs** [cri#1349](https://github.com/containerd/cri/pull/1349) +* **Fix privileged supported** [cri#1356](https://github.com/containerd/cri/pull/1356) +* **Update default runtime to `io.containerd.runc.v2`** [cri#1359](https://github.com/containerd/cri/pull/1359) +* **Add instrospection service** [cri#1364](https://github.com/containerd/cri/pull/1364) +* **Unshare cgroup namespace for container when using cgroupv2** [cri#1371](https://github.com/containerd/cri/pull/1371) +* **Add CPU and memory cgroupv2 metrics** [cri#1376](https://github.com/containerd/cri/pull/1376) +* **Reload CNI network config on fs change events** [cri#1405](https://github.com/containerd/cri/pull/1405) +* **Add support for stargz remote snapshots** [cri#1431](https://github.com/containerd/cri/pull/1431) +* **Add support for 'container-name' OCI annotation** [cri#1436](https://github.com/containerd/cri/pull/1436) +* **Remove socat for port forwarding** [cri#1470](https://github.com/containerd/cri/pull/1470) +* **Add config flag to default empty seccomp profile** [cri#1472](https://github.com/containerd/cri/pull/1472) +* **Add SELinux support** [cri#1487](https://github.com/containerd/cri/pull/1487) + +And many more improvements and bug fixes in the complete changelog""" + +# notable prs to include in the release notes, 1234 is the pr number +[notes] + +[breaking] diff -Nru containerd-1.2.6/releases/v1.5.0.toml containerd-1.5.9/releases/v1.5.0.toml --- containerd-1.2.6/releases/v1.5.0.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.0.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,163 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.4.0" + +pre_release = false + +preface = """\ +The sixth major release of containerd includes many stability improvements +and code organization changes to make contribution easier and make future +features cleaner to develop. This includes bringing CRI development into the +main containerd repository and switching to Go modules. This release also +brings support for the Node Resource Interface (NRI). + +### Highlights + +#### Project Organization +* **Merge containerd/cri codebase into containerd/containerd** [#4593](https://github.com/containerd/containerd/pull/4593) +* **Move to Go modules** [#4760](https://github.com/containerd/containerd/pull/4760) +* **Remove `selinux` build tag** [#4849](https://github.com/containerd/containerd/pull/4849) +* **Add json log format output option for daemon log** [#4803](https://github.com/containerd/containerd/pull/4803) + +#### Snapshots +* **Add configurable overlayfs path** [#4505](https://github.com/containerd/containerd/pull/4505) +* **Separate overlay implementation from plugin** [#4506](https://github.com/containerd/containerd/pull/4506) +* **Native snapshotter configuration and plugin separation** [#4517](https://github.com/containerd/containerd/pull/4517) +* **Devmapper snapshotter configuration and plugin separation** [#4573](https://github.com/containerd/containerd/pull/4573) +* **AUFS snapshotter configuration and plugin separation** [#4533](https://github.com/containerd/containerd/pull/4533) +* **ZFS snapshotter configuration and plugin separation** [#4534](https://github.com/containerd/containerd/pull/4534) +* **Pass custom snapshot labels when creating snapshot** [#4630](https://github.com/containerd/containerd/pull/4630) [#4635](https://github.com/containerd/containerd/pull/4635) +* **Add platform check for snapshotter support when unpacking** [#3927](https://github.com/containerd/containerd/pull/3927) +* **Handle loopback mounts** [#4902](https://github.com/containerd/containerd/pull/4902) +* **Support `userxattr` mount option for overlay in user namespace** [#5076](https://github.com/containerd/containerd/pull/5076) +* **ZFS snapshotter implementation of usage** [#5243](https://github.com/containerd/containerd/pull/5243) + +#### Distribution +* **Improve registry response errors** [#4523](https://github.com/containerd/containerd/pull/4523) +* **Improve image pull performance over HTTP 1.1** [#4653](https://github.com/containerd/containerd/pull/4653) +* **Registry configuration package** [#4138](https://github.com/containerd/containerd/pull/4138) +* **Add support for layers compressed with zstd** [#4809](https://github.com/containerd/containerd/pull/4809) +* **Allow arm64 to fallback to arm (v8, v7, v6, v5)** [4932](https://github.com/containerd/containerd/pull/4932) + +#### Runtime +* **Add annotations to containerd task update API** [#4647](https://github.com/containerd/containerd/pull/4647) +* **Add logging binary support when terminal is true** [#4502](https://github.com/containerd/containerd/pull/4502) +* **Runtime support on FreeBSD** [#5375](https://github.com/containerd/containerd/pull/5375) + +#### Windows +* **Implement windowsDiff.Compare to allow outputting OCI images** [#4399](https://github.com/containerd/containerd/pull/4399) +* **Optimize WCOW snapshotter to commit writable layers as read-only parent layers** [#4415](https://github.com/containerd/containerd/pull/4415) +* **Optimize LCOW snapshotter use of scratch layers** [#4643](https://github.com/containerd/containerd/pull/4643) + +#### CRI +* **Add NRI injection points** [cri#1552](https://github.com/containerd/cri/pull/1552) +* **Add support for registry host directory configuration** [#4978](https://github.com/containerd/containerd/pull/4978) +* **Update privileged containers to use current capabilities instead of known capabilities** [#5017](https://github.com/containerd/containerd/pull/5017) +* **Add pod annotations to CNI call** [#5026](https://github.com/containerd/containerd/pull/5026) +* **Enable ocicrypt by default** [#5135](https://github.com/containerd/containerd/pull/5135) +* **Support PID NamespaceMode_TARGET** [#5203](https://github.com/containerd/containerd/pull/5203) + +### Impactful Client Updates + +This release has changes which may affect projects which import containerd. + +#### Switch to Go modules + +containerd and all containerd sub-repositories are now using Go modules. This +should help make importing easier for handling transitive dependencies. As of +this release, containerd still does not guarantee client library compatibility +for 1.x versions, although best effort is made to minimize impact from changes +to exported Go packages. + +#### CRI plugin moved to main repository + +With the CRI plugin moving into the main repository, imports under `github.com/containerd/cri/` +can now be found `github.com/containerd/containerd/pkg/cri/`. +There are no changes required for end users of CRI. + +#### Library changes + +##### `oci` + +The `WithAllCapabilities` has been removed and replaced with `WithAllCurrentCapabilities` +and `WithAllKnownCapabilities`. `WithAllKnownCapabilities` has similar +functionality to the previous `WithAllCapabilities` with added support for newer +capabilities. `WithAllCurrentCapabilities` can be used to give privileged +containers the same set of permissions as the calling process, preventing errors +when privileged containers attempt to get more permissions than given to the +caller. + +#### Configuration changes + +##### *New* `registry.config_path` for CRI plugin + +`registry.config_path` specifies a directory to look for registry hosts +configuration. When resolving an image name during pull operations, the CRI +plugin will look in the `//` directory +for host configuration. An optional `hosts.toml` file in that directory may be +used to configure which hosts will be used for the pull operation as well +host-specific configurations. Updates under that directory do not require +restarting the containerd daemon. + +Enable `registry.config_path` in the containerd configuration file. + +```toml +[plugins."io.containerd.grpc.v1.cri".registry] + config_path = "/etc/containerd/certs.d" +``` + +Configure registry hosts, such as `/etc/containerd/certs.d/docker.io/hosts.toml` +for any image under the `docker.io` namespace (any image on Docker Hub). + +``` +server = "https://registry-1.docker.io" # Exclude this to not use upstream + +[host."https://public-mirror.example.com"] + capabilities = ["pull"] # Requires less trust, won't resolve tag to digest from this host +[host."https://docker-mirror.internal"] + capabilities = ["pull", "resolve"] + ca = "docker-mirror.crt" # Or absolute path /etc/containerd/certs.d/docker.io/docker-mirror.crt +``` + +If no `hosts.toml` configuration exists in the host directory, it will fallback +to check certificate files based on Docker's certificate file +pattern (".crt" files for CA certificates and ".cert"/".key" files for client +certificates). + +##### Deprecation of `registry.mirrors` and `registry.configs` in CRI plugin + +Mirroring and TLS can now be configured using the new `registry.config_path` +option. Existing configurations may be migrated to new host directory +configuration. These fields are only deprecated with no planned removal, +however, these configurations cannot be used while `registry.config_path` is +defined. + +##### Version 1 schema is deprecated + +Version 2 of the containerd configuration toml is recommended format and the +default. Starting this version, a deprecation warning will be logged when +version 1 is used. + +To check version, see the version value in the containerd toml configuration. + +```toml +version=2 +``` + +#### FreeBSD Runtime Support (Experimental) + +This release includes changes that allow containerd to run on FreeBSD with a +compatible runtime, such as [runj](https://github.com/samuelkarp/runj). This +support should be considered experimental and currently there are no official +binary releases for FreeBSD. The runtimes used by containerd are maintained +separately and have their own stability guarantees. The containerd project +strives to be compatible with any runtime which aims to implement containerd's +shim API and OCI runtime specification. + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.1.toml containerd-1.5.9/releases/v1.5.1.toml --- containerd-1.2.6/releases/v1.5.1.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.1.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.0" + +pre_release = false + +preface = """\ +The first patch release for containerd 1.5 includes an updated version +of runc and minor fix in the CRI service + +### Notable Updates + +* **Update runc to rc94** [#5473](https://github.com/containerd/containerd/pull/5473) +* **Fix registry mirror authorization logic in CRI plugin** [#5446](https://github.com/containerd/containerd/pull/5446) +* **Fix regression in cri-cni-release to include cri tools** [#5462](https://github.com/containerd/containerd/pull/5462) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.2.toml containerd-1.5.9/releases/v1.5.2.toml --- containerd-1.2.6/releases/v1.5.2.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.2.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,15 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.1" + +pre_release = false + +preface = """\ +The second patch release for containerd 1.5 is a security release to update +runc for [CVE-2021-30465](https://github.com/opencontainers/runc/security/advisories/GHSA-c3xm-pvg7-gh7r)""" diff -Nru containerd-1.2.6/releases/v1.5.3.toml containerd-1.5.9/releases/v1.5.3.toml --- containerd-1.2.6/releases/v1.5.3.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.3.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.2" + +pre_release = false + +preface = """\ +The third patch release for containerd 1.5 updates runc to 1.0.0 and contains +various other fixes. + +### Notable Updates + +* **Update runc binary to 1.0.0** [5552](https://github.com/containerd/containerd/pull/5552) +* **Send pod UID to CNI plugins as K8S_POD_UID** [#5640](https://github.com/containerd/containerd/pull/5640) +* **Fix invalid validation error checking** [#5565](https://github.com/containerd/containerd/pull/5565) +* **Fix error on image pull resume** [#5560](https://github.com/containerd/containerd/pull/5560) +* **Fix User Agent sent to registry authentication server** [#5533](https://github.com/containerd/containerd/pull/5533) +* **Fix symlink resolution for disk mounts on Windows** [#5411](https://github.com/containerd/containerd/pull/5411) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.4.toml containerd-1.5.9/releases/v1.5.4.toml --- containerd-1.2.6/releases/v1.5.4.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.4.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.3" + +pre_release = false + +preface = """\ +The fourth patch release for containerd 1.5 is a security release to address [CVE-2021-32760](https://github.com/containerd/containerd/security/advisories/GHSA-c72p-9xmj-rx3w).""" diff -Nru containerd-1.2.6/releases/v1.5.5.toml containerd-1.5.9/releases/v1.5.5.toml --- containerd-1.2.6/releases/v1.5.5.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.5.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.4" + +pre_release = false + +preface = """\ +The fifth patch release for containerd 1.5 updates runc to 1.0.1 and contains +other minor updates. + +### Notable Updates + +* **Update runc binary to 1.0.1** [#5751](https://github.com/containerd/containerd/pull/5751) +* **Update pull logic to try next mirror on non-404 response** [#5275](https://github.com/containerd/containerd/pull/5275) +* **Update pull authorization logic on redirect** [#5504](https://github.com/containerd/containerd/pull/5504) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.6.toml containerd-1.5.9/releases/v1.5.6.toml --- containerd-1.2.6/releases/v1.5.6.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.6.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.5" + +pre_release = false + +preface = """\ +The sixth patch release for containerd 1.5 contains minor fixes and updates +including an updated runc and hcsshim. + +### Notable Updates + +* **Install apparmor parser for arm64 and update seccomp to 2.5.1** [#5763](https://github.com/containerd/containerd/pull/5763) +* **Update runc binary to 1.0.2** [#5899](https://github.com/containerd/containerd/pull/5899) +* **Update hcsshim to v0.8.21 to fix layer issue on Windows Server 2019** [#5942](https://github.com/containerd/containerd/pull/5942) +* **Add support for 'clone3' syscall to fix issue with certain images when seccomp is enabled** [#5982](https://github.com/containerd/containerd/pull/5982) +* **Add image config labels in CRI container creation** [#6012](https://github.com/containerd/containerd/pull/6012) +* **Fix panic in metadata content writer on copy error** [#6043](https://github.com/containerd/containerd/pull/6043) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.7.toml containerd-1.5.9/releases/v1.5.7.toml --- containerd-1.2.6/releases/v1.5.7.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.7.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,19 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.6" + +pre_release = false + +preface = """\ +The seventh patch release for containerd 1.5 is a security release to fix CVE-2021-41103. + +### Notable Updates +* **Fix insufficiently restricted permissions on container root and plugin directories** [GHSA-c2h3-6mxw-7mvq](https://github.com/containerd/containerd/security/advisories/GHSA-c2h3-6mxw-7mvq) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.8.toml containerd-1.5.9/releases/v1.5.8.toml --- containerd-1.2.6/releases/v1.5.8.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.8.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.7" + +pre_release = false + +preface = """\ +The eighth patch release for containerd 1.5 contains a mitigation for [CVE-2021-41190](https://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m) +as well as several fixes and updates. + +### Notable Updates +* **Handle ambiguous OCI manifest parsing** ([GHSA-5j5w-g665-5m35](https://github.com/containerd/containerd/security/advisories/GHSA-5j5w-g665-5m35)) +* **Filter selinux xattr for image volumes in CRI plugin** ([#5104](https://github.com/containerd/containerd/pull/5104)) +* **Use DeactiveLayer to unlock layers that cannot be renamed in Windows snapshotter** ([#5422](https://github.com/containerd/containerd/pull/5422)) +* **Fix pull failure on unexpected EOF** ([#5921](https://github.com/containerd/containerd/pull/5921)) +* **Close task IO before waiting on delete** ([#5974](https://github.com/containerd/containerd/pull/5974)) +* **Log a warning for ignored invalid image labels rather than erroring** ([#6124](https://github.com/containerd/containerd/pull/6124)) +* **Update pull to handle of non-https urls in descriptors** ([#6221](https://github.com/containerd/containerd/pull/6221)) + + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/releases/v1.5.9.toml containerd-1.5.9/releases/v1.5.9.toml --- containerd-1.2.6/releases/v1.5.9.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/releases/v1.5.9.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,20 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +match_deps = "^github.com/(containerd/[a-zA-Z0-9-]+)$" + +# previous release +previous = "v1.5.8" + +pre_release = false + +preface = """\ +The ninth patch release for containerd 1.5 is a security release to fix CVE-2021-43816. + +### Notable Updates +* **Fix unprivileged pod using 'hostPath' bypassing SELinux labels** ([GHSA-mvff-h3cj-wj9c](https://github.com/containerd/containerd/security/advisories/GHSA-mvff-h3cj-wj9c)) +* **Fix setting the "container_kvm_t" SELinux label** ([#6381](https://github.com/containerd/containerd/pull/6381)) + +See the changelog for complete list of changes""" diff -Nru containerd-1.2.6/RELEASES.md containerd-1.5.9/RELEASES.md --- containerd-1.2.6/RELEASES.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/RELEASES.md 2022-01-05 17:30:58.000000000 +0000 @@ -77,26 +77,31 @@ by `.`. Releases branches will be in one of several states: - __*Next*__: The next planned release branch. -- __*Active*__: The release is currently supported and accepting patches. +- __*Active*__: The release branch is currently supported and accepting patches. +- __*Extended*__: The release branch is only accepting security patches. - __*End of Life*__: The release branch is no longer supported and no new patches will be accepted. Releases will be supported up to one year after a _minor_ release. This means that we will accept bug reports and backports to release branches until the end of life date. If no new _minor_ release has been made, that release will be -considered supported until the next _minor_ is released or one year, whichever -is longer. +considered supported until 6 months after the next _minor_ is released or one year, +whichever is longer. Additionally, releases may have an extended security support +period after the end of the active period to accept security backports. This +timeframe will be decided by maintainers before the end of the active status. The current state is available in the following table: | Release | Status | Start | End of Life | |---------|-------------|------------------|-------------------| -| [0.0](https://github.com/containerd/containerd/releases/tag/0.0.5) | End of Life | Dec 4, 2015 | - | -| [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - | -| [0.2](https://github.com/containerd/containerd/tree/v0.2.x) | End of Life | Apr 21, 2016 | December 5, 2017 | -| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.0) | Active | December 5, 2017 | December 5, 2018 | -| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.0) | Active | April 23, 2018 | max(April 23, 2019, release of 1.2.0, Kubernetes 1.10 EOL) | -| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.0) | Active | October 24, 2018 | max(October 24, 2019, release of 1.3.0) | -| [1.3](https://github.com/containerd/containerd/milestone/20) | Next | TBD | max(TBD+1 year, release of 1.4.0) | +| [0.0](https://github.com/containerd/containerd/releases/tag/0.0.5) | End of Life | Dec 4, 2015 | - | +| [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - | +| [0.2](https://github.com/containerd/containerd/tree/v0.2.x) | End of Life | Apr 21, 2016 | December 5, 2017 | +| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.3) | End of Life | December 5, 2017 | December 5, 2018 | +| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | End of Life | April 23, 2018 | October 23, 2019 | +| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.13) | End of Life | October 24, 2018 | October 15, 2020 | +| [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.10) | End of Life | September 26, 2019 | March 4, 2021 | +| [1.4](https://github.com/containerd/containerd/releases/tag/v1.4.4) | Active | August 17, 2020 | max(August 17, 2021, release of 1.5.0 + 6 months) | +| [1.5](https://github.com/containerd/containerd/milestone/30) | Next | TBD | max(TBD+1 year, release of 1.6.0 + 6 months) | Note that branches and release from before 1.0 may not follow these rules. @@ -129,7 +134,7 @@ process: 1. Pick the branch to which you want backported, usually in the format - `release/.`. The following will create a branch you can + `release/.`. The following will create a branch you can use to open a PR: ```console @@ -150,7 +155,12 @@ Make sure to replace `stevvooe` with whatever fork you are using to open the PR. When you open the PR, make sure to switch `master` with whatever - release branch you are targeting with the fix. + release branch you are targeting with the fix. Make sure the PR title has + `[]` prefixed. e.g.: + + ``` + [release/1.4] Fix foo in bar + ``` If there is no existing fix in master, you should first fix the bug in master, or ask us a maintainer or contributor to do it via an issue. Once that PR is @@ -170,8 +180,9 @@ | GRPC API | Stable | 1.0 | [api/](api) | | Metrics API | Stable | 1.0 | - | | Runtime Shim API | Stable | 1.2 | - | +| Daemon Config | Stable | 1.0 | - | | Go client API | Unstable | _future_ | [godoc](https://godoc.org/github.com/containerd/containerd) | -| CRI GRPC API | Unstable | v1alpha2 _current_ | [api/](https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet/apis/cri/runtime/v1alpha2) | +| CRI GRPC API | Unstable | v1alpha2 _current_ | [cri-api](https://github.com/kubernetes/cri-api/tree/master/pkg/apis/runtime/v1alpha2) | | `ctr` tool | Unstable | Out of scope | - | From the version stated in the above table, that component must adhere to the @@ -195,6 +206,10 @@ Note that new services may be added in _minor_ releases. New service methods and new fields on messages may be added if they are optional. +`*.pb.txt` files are generated at each API release. They prevent unintentional changes +to the API by having a diff that the CI can run. These files are not intended to be +consumed or used by clients. + ### Metrics API The metrics API that outputs prometheus style metrics will be versioned independently, @@ -263,10 +278,24 @@ ### `ctr` tool The `ctr` tool provides the ability to introspect and understand the containerd -API. At this time, it is not considered a primary offering of the project. It -may be completely refactored or have breaking changes in _minor_ releases. - -We will try not break the tool in _patch_ releases. +API. It is not considered a primary offering of the project and is unsupported in +that sense. While we understand it's value as a debug tool, it may be completely +refactored or have breaking changes in _minor_ releases. + +Targeting `ctr` for feature additions reflects a misunderstanding of the containerd +architecture. Feature addition should focus on the client Go API and additions to +`ctr` may or may not be accepted at the discretion of the maintainers. + +We will do our best to not break compatibility in the tool in _patch_ releases. + +### Daemon Configuration + +The daemon's configuration file, commonly located in `/etc/containerd/config.toml` +is versioned and backwards compatible. The `version` field in the config +file specifies the config's version. If no version number is specified inside +the config file then it is assumed to be a version 1 config and parsed as such. +Please use `version = 2` to enable version 2 config as version 1 has been +deprecated. ### Not Covered @@ -287,3 +316,14 @@ We may make exceptions in the interest of __security patches__. If a break is required, it will be communicated clearly and the solution will be considered against total impact. + +## Deprecated features + +The deprecated features are shown in the following table: + +| Component | Deprecation release | Target release for removal | Recommendation | +|----------------------------------------------------------------------|---------------------|----------------------------|-------------------------------| +| Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`) | containerd v1.4 | containerd v2.0 | Use `io.containerd.runc.v2` | +| Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`) | containerd v1.4 | containerd v2.0 | Use `io.containerd.runc.v2` | +| config.toml `version = 1` | containerd v1.5 | containerd v2.0 | Use config.toml `version = 2` | +| Built-in `aufs` snapshotter | containerd v1.5 | containerd v2.0 | Use `overlayfs` snapshotter | diff -Nru containerd-1.2.6/remotes/docker/auth/fetch.go containerd-1.5.9/remotes/docker/auth/fetch.go --- containerd-1.2.6/remotes/docker/auth/fetch.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/auth/fetch.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,209 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package auth + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "strings" + "time" + + "github.com/containerd/containerd/log" + remoteserrors "github.com/containerd/containerd/remotes/errors" + "github.com/containerd/containerd/version" + "github.com/pkg/errors" + "golang.org/x/net/context/ctxhttp" +) + +var ( + // ErrNoToken is returned if a request is successful but the body does not + // contain an authorization token. + ErrNoToken = errors.New("authorization server did not include a token in the response") +) + +// GenerateTokenOptions generates options for fetching a token based on a challenge +func GenerateTokenOptions(ctx context.Context, host, username, secret string, c Challenge) (TokenOptions, error) { + realm, ok := c.Parameters["realm"] + if !ok { + return TokenOptions{}, errors.New("no realm specified for token auth challenge") + } + + realmURL, err := url.Parse(realm) + if err != nil { + return TokenOptions{}, errors.Wrap(err, "invalid token auth challenge realm") + } + + to := TokenOptions{ + Realm: realmURL.String(), + Service: c.Parameters["service"], + Username: username, + Secret: secret, + } + + scope, ok := c.Parameters["scope"] + if ok { + to.Scopes = append(to.Scopes, scope) + } else { + log.G(ctx).WithField("host", host).Debug("no scope specified for token auth challenge") + } + + return to, nil +} + +// TokenOptions are options for requesting a token +type TokenOptions struct { + Realm string + Service string + Scopes []string + Username string + Secret string +} + +// OAuthTokenResponse is response from fetching token with a OAuth POST request +type OAuthTokenResponse struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIn int `json:"expires_in"` + IssuedAt time.Time `json:"issued_at"` + Scope string `json:"scope"` +} + +// FetchTokenWithOAuth fetches a token using a POST request +func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.Header, clientID string, to TokenOptions) (*OAuthTokenResponse, error) { + form := url.Values{} + if len(to.Scopes) > 0 { + form.Set("scope", strings.Join(to.Scopes, " ")) + } + form.Set("service", to.Service) + form.Set("client_id", clientID) + + if to.Username == "" { + form.Set("grant_type", "refresh_token") + form.Set("refresh_token", to.Secret) + } else { + form.Set("grant_type", "password") + form.Set("username", to.Username) + form.Set("password", to.Secret) + } + + req, err := http.NewRequest("POST", to.Realm, strings.NewReader(form.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") + for k, v := range headers { + req.Header[k] = append(req.Header[k], v...) + } + if len(req.Header.Get("User-Agent")) == 0 { + req.Header.Set("User-Agent", "containerd/"+version.Version) + } + + resp, err := ctxhttp.Do(ctx, client, req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return nil, errors.WithStack(remoteserrors.NewUnexpectedStatusErr(resp)) + } + + decoder := json.NewDecoder(resp.Body) + + var tr OAuthTokenResponse + if err = decoder.Decode(&tr); err != nil { + return nil, errors.Wrap(err, "unable to decode token response") + } + + if tr.AccessToken == "" { + return nil, errors.WithStack(ErrNoToken) + } + + return &tr, nil +} + +// FetchTokenResponse is response from fetching token with GET request +type FetchTokenResponse struct { + Token string `json:"token"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + IssuedAt time.Time `json:"issued_at"` + RefreshToken string `json:"refresh_token"` +} + +// FetchToken fetches a token using a GET request +func FetchToken(ctx context.Context, client *http.Client, headers http.Header, to TokenOptions) (*FetchTokenResponse, error) { + req, err := http.NewRequest("GET", to.Realm, nil) + if err != nil { + return nil, err + } + + for k, v := range headers { + req.Header[k] = append(req.Header[k], v...) + } + if len(req.Header.Get("User-Agent")) == 0 { + req.Header.Set("User-Agent", "containerd/"+version.Version) + } + + reqParams := req.URL.Query() + + if to.Service != "" { + reqParams.Add("service", to.Service) + } + + for _, scope := range to.Scopes { + reqParams.Add("scope", scope) + } + + if to.Secret != "" { + req.SetBasicAuth(to.Username, to.Secret) + } + + req.URL.RawQuery = reqParams.Encode() + + resp, err := ctxhttp.Do(ctx, client, req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return nil, errors.WithStack(remoteserrors.NewUnexpectedStatusErr(resp)) + } + + decoder := json.NewDecoder(resp.Body) + + var tr FetchTokenResponse + if err = decoder.Decode(&tr); err != nil { + return nil, errors.Wrap(err, "unable to decode token response") + } + + // `access_token` is equivalent to `token` and if both are specified + // the choice is undefined. Canonicalize `access_token` by sticking + // things in `token`. + if tr.AccessToken != "" { + tr.Token = tr.AccessToken + } + + if tr.Token == "" { + return nil, errors.WithStack(ErrNoToken) + } + + return &tr, nil +} diff -Nru containerd-1.2.6/remotes/docker/auth/parse.go containerd-1.5.9/remotes/docker/auth/parse.go --- containerd-1.2.6/remotes/docker/auth/parse.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/auth/parse.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,203 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package auth + +import ( + "net/http" + "sort" + "strings" +) + +// AuthenticationScheme defines scheme of the authentication method +type AuthenticationScheme byte + +const ( + // BasicAuth is scheme for Basic HTTP Authentication RFC 7617 + BasicAuth AuthenticationScheme = 1 << iota + // DigestAuth is scheme for HTTP Digest Access Authentication RFC 7616 + DigestAuth + // BearerAuth is scheme for OAuth 2.0 Bearer Tokens RFC 6750 + BearerAuth +) + +// Challenge carries information from a WWW-Authenticate response header. +// See RFC 2617. +type Challenge struct { + // scheme is the auth-scheme according to RFC 2617 + Scheme AuthenticationScheme + + // parameters are the auth-params according to RFC 2617 + Parameters map[string]string +} + +type byScheme []Challenge + +func (bs byScheme) Len() int { return len(bs) } +func (bs byScheme) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] } + +// Sort in priority order: token > digest > basic +func (bs byScheme) Less(i, j int) bool { return bs[i].Scheme > bs[j].Scheme } + +// Octet types from RFC 2616. +type octetType byte + +var octetTypes [256]octetType + +const ( + isToken octetType = 1 << iota + isSpace +) + +func init() { + // OCTET = + // CHAR = + // CTL = + // CR = + // LF = + // SP = + // HT = + // <"> = + // CRLF = CR LF + // LWS = [CRLF] 1*( SP | HT ) + // TEXT = + // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> + // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT + // token = 1* + // qdtext = > + + for c := 0; c < 256; c++ { + var t octetType + isCtl := c <= 31 || c == 127 + isChar := 0 <= c && c <= 127 + isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) + if strings.ContainsRune(" \t\r\n", rune(c)) { + t |= isSpace + } + if isChar && !isCtl && !isSeparator { + t |= isToken + } + octetTypes[c] = t + } +} + +// ParseAuthHeader parses challenges from WWW-Authenticate header +func ParseAuthHeader(header http.Header) []Challenge { + challenges := []Challenge{} + for _, h := range header[http.CanonicalHeaderKey("WWW-Authenticate")] { + v, p := parseValueAndParams(h) + var s AuthenticationScheme + switch v { + case "basic": + s = BasicAuth + case "digest": + s = DigestAuth + case "bearer": + s = BearerAuth + default: + continue + } + challenges = append(challenges, Challenge{Scheme: s, Parameters: p}) + } + sort.Stable(byScheme(challenges)) + return challenges +} + +func parseValueAndParams(header string) (value string, params map[string]string) { + params = make(map[string]string) + value, s := expectToken(header) + if value == "" { + return + } + value = strings.ToLower(value) + for { + var pkey string + pkey, s = expectToken(skipSpace(s)) + if pkey == "" { + return + } + if !strings.HasPrefix(s, "=") { + return + } + var pvalue string + pvalue, s = expectTokenOrQuoted(s[1:]) + if pvalue == "" { + return + } + pkey = strings.ToLower(pkey) + params[pkey] = pvalue + s = skipSpace(s) + if !strings.HasPrefix(s, ",") { + return + } + s = s[1:] + } +} + +func skipSpace(s string) (rest string) { + i := 0 + for ; i < len(s); i++ { + if octetTypes[s[i]]&isSpace == 0 { + break + } + } + return s[i:] +} + +func expectToken(s string) (token, rest string) { + i := 0 + for ; i < len(s); i++ { + if octetTypes[s[i]]&isToken == 0 { + break + } + } + return s[:i], s[i:] +} + +func expectTokenOrQuoted(s string) (value string, rest string) { + if !strings.HasPrefix(s, "\"") { + return expectToken(s) + } + s = s[1:] + for i := 0; i < len(s); i++ { + switch s[i] { + case '"': + return s[:i], s[i+1:] + case '\\': + p := make([]byte, len(s)-1) + j := copy(p, s[:i]) + escape := true + for i = i + 1; i < len(s); i++ { + b := s[i] + switch { + case escape: + escape = false + p[j] = b + j++ + case b == '\\': + escape = true + case b == '"': + return string(p[:j]), s[i+1:] + default: + p[j] = b + j++ + } + } + return "", "" + } + } + return "", "" +} diff -Nru containerd-1.2.6/remotes/docker/auth.go containerd-1.5.9/remotes/docker/auth.go --- containerd-1.2.6/remotes/docker/auth.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/auth.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,198 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package docker - -import ( - "net/http" - "sort" - "strings" -) - -type authenticationScheme byte - -const ( - basicAuth authenticationScheme = 1 << iota // Defined in RFC 7617 - digestAuth // Defined in RFC 7616 - bearerAuth // Defined in RFC 6750 -) - -// challenge carries information from a WWW-Authenticate response header. -// See RFC 2617. -type challenge struct { - // scheme is the auth-scheme according to RFC 2617 - scheme authenticationScheme - - // parameters are the auth-params according to RFC 2617 - parameters map[string]string -} - -type byScheme []challenge - -func (bs byScheme) Len() int { return len(bs) } -func (bs byScheme) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] } - -// Sort in priority order: token > digest > basic -func (bs byScheme) Less(i, j int) bool { return bs[i].scheme > bs[j].scheme } - -// Octet types from RFC 2616. -type octetType byte - -var octetTypes [256]octetType - -const ( - isToken octetType = 1 << iota - isSpace -) - -func init() { - // OCTET = - // CHAR = - // CTL = - // CR = - // LF = - // SP = - // HT = - // <"> = - // CRLF = CR LF - // LWS = [CRLF] 1*( SP | HT ) - // TEXT = - // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> - // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT - // token = 1* - // qdtext = > - - for c := 0; c < 256; c++ { - var t octetType - isCtl := c <= 31 || c == 127 - isChar := 0 <= c && c <= 127 - isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) - if strings.ContainsRune(" \t\r\n", rune(c)) { - t |= isSpace - } - if isChar && !isCtl && !isSeparator { - t |= isToken - } - octetTypes[c] = t - } -} - -func parseAuthHeader(header http.Header) []challenge { - challenges := []challenge{} - for _, h := range header[http.CanonicalHeaderKey("WWW-Authenticate")] { - v, p := parseValueAndParams(h) - var s authenticationScheme - switch v { - case "basic": - s = basicAuth - case "digest": - s = digestAuth - case "bearer": - s = bearerAuth - default: - continue - } - challenges = append(challenges, challenge{scheme: s, parameters: p}) - } - sort.Stable(byScheme(challenges)) - return challenges -} - -func parseValueAndParams(header string) (value string, params map[string]string) { - params = make(map[string]string) - value, s := expectToken(header) - if value == "" { - return - } - value = strings.ToLower(value) - for { - var pkey string - pkey, s = expectToken(skipSpace(s)) - if pkey == "" { - return - } - if !strings.HasPrefix(s, "=") { - return - } - var pvalue string - pvalue, s = expectTokenOrQuoted(s[1:]) - if pvalue == "" { - return - } - pkey = strings.ToLower(pkey) - params[pkey] = pvalue - s = skipSpace(s) - if !strings.HasPrefix(s, ",") { - return - } - s = s[1:] - } -} - -func skipSpace(s string) (rest string) { - i := 0 - for ; i < len(s); i++ { - if octetTypes[s[i]]&isSpace == 0 { - break - } - } - return s[i:] -} - -func expectToken(s string) (token, rest string) { - i := 0 - for ; i < len(s); i++ { - if octetTypes[s[i]]&isToken == 0 { - break - } - } - return s[:i], s[i:] -} - -func expectTokenOrQuoted(s string) (value string, rest string) { - if !strings.HasPrefix(s, "\"") { - return expectToken(s) - } - s = s[1:] - for i := 0; i < len(s); i++ { - switch s[i] { - case '"': - return s[:i], s[i+1:] - case '\\': - p := make([]byte, len(s)-1) - j := copy(p, s[:i]) - escape := true - for i = i + 1; i < len(s); i++ { - b := s[i] - switch { - case escape: - escape = false - p[j] = b - j++ - case b == '\\': - escape = true - case b == '"': - return string(p[:j]), s[i+1:] - default: - p[j] = b - j++ - } - } - return "", "" - } - } - return "", "" -} diff -Nru containerd-1.2.6/remotes/docker/authorizer.go containerd-1.5.9/remotes/docker/authorizer.go --- containerd-1.2.6/remotes/docker/authorizer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/authorizer.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,277 +19,297 @@ import ( "context" "encoding/base64" - "encoding/json" "fmt" - "io" - "io/ioutil" "net/http" - "net/url" "strings" "sync" - "time" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/remotes/docker/auth" + remoteerrors "github.com/containerd/containerd/remotes/errors" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/net/context/ctxhttp" ) type dockerAuthorizer struct { credentials func(string) (string, string, error) client *http.Client + header http.Header mu sync.Mutex - auth map[string]string + // indexed by host name + handlers map[string]*authHandler } // NewAuthorizer creates a Docker authorizer using the provided function to // get credentials for the token server or basic auth. +// Deprecated: Use NewDockerAuthorizer func NewAuthorizer(client *http.Client, f func(string) (string, string, error)) Authorizer { - if client == nil { - client = http.DefaultClient + return NewDockerAuthorizer(WithAuthClient(client), WithAuthCreds(f)) +} + +type authorizerConfig struct { + credentials func(string) (string, string, error) + client *http.Client + header http.Header +} + +// AuthorizerOpt configures an authorizer +type AuthorizerOpt func(*authorizerConfig) + +// WithAuthClient provides the HTTP client for the authorizer +func WithAuthClient(client *http.Client) AuthorizerOpt { + return func(opt *authorizerConfig) { + opt.client = client + } +} + +// WithAuthCreds provides a credential function to the authorizer +func WithAuthCreds(creds func(string) (string, string, error)) AuthorizerOpt { + return func(opt *authorizerConfig) { + opt.credentials = creds + } +} + +// WithAuthHeader provides HTTP headers for authorization +func WithAuthHeader(hdr http.Header) AuthorizerOpt { + return func(opt *authorizerConfig) { + opt.header = hdr } +} + +// NewDockerAuthorizer creates an authorizer using Docker's registry +// authentication spec. +// See https://docs.docker.com/registry/spec/auth/ +func NewDockerAuthorizer(opts ...AuthorizerOpt) Authorizer { + var ao authorizerConfig + for _, opt := range opts { + opt(&ao) + } + + if ao.client == nil { + ao.client = http.DefaultClient + } + return &dockerAuthorizer{ - credentials: f, - client: client, - auth: map[string]string{}, + credentials: ao.credentials, + client: ao.client, + header: ao.header, + handlers: make(map[string]*authHandler), } } +// Authorize handles auth request. func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Request) error { - // TODO: Lookup matching challenge and scope rather than just host - if auth := a.getAuth(req.URL.Host); auth != "" { - req.Header.Set("Authorization", auth) + // skip if there is no auth handler + ah := a.getAuthHandler(req.URL.Host) + if ah == nil { + return nil } + auth, err := ah.authorize(ctx) + if err != nil { + return err + } + + req.Header.Set("Authorization", auth) return nil } +func (a *dockerAuthorizer) getAuthHandler(host string) *authHandler { + a.mu.Lock() + defer a.mu.Unlock() + + return a.handlers[host] +} + func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.Response) error { last := responses[len(responses)-1] host := last.Request.URL.Host - for _, c := range parseAuthHeader(last.Header) { - if c.scheme == bearerAuth { + + a.mu.Lock() + defer a.mu.Unlock() + for _, c := range auth.ParseAuthHeader(last.Header) { + if c.Scheme == auth.BearerAuth { if err := invalidAuthorization(c, responses); err != nil { - // TODO: Clear token - a.setAuth(host, "") + delete(a.handlers, host) return err } - // TODO(dmcg): Store challenge, not token - // Move token fetching to authorize - return a.setTokenAuth(ctx, host, c.parameters) - } else if c.scheme == basicAuth { - // TODO: Resolve credentials on authorize + // reuse existing handler + // + // assume that one registry will return the common + // challenge information, including realm and service. + // and the resource scope is only different part + // which can be provided by each request. + if _, ok := a.handlers[host]; ok { + return nil + } + + var username, secret string + if a.credentials != nil { + var err error + username, secret, err = a.credentials(host) + if err != nil { + return err + } + } + + common, err := auth.GenerateTokenOptions(ctx, host, username, secret, c) + if err != nil { + return err + } + + a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, common) + return nil + } else if c.Scheme == auth.BasicAuth && a.credentials != nil { username, secret, err := a.credentials(host) if err != nil { return err } + if username != "" && secret != "" { - auth := username + ":" + secret - a.setAuth(host, fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth)))) + common := auth.TokenOptions{ + Username: username, + Secret: secret, + } + + a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, common) return nil } } } - return errors.Wrap(errdefs.ErrNotImplemented, "failed to find supported auth scheme") } -func (a *dockerAuthorizer) getAuth(host string) string { - a.mu.Lock() - defer a.mu.Unlock() - - return a.auth[host] -} - -func (a *dockerAuthorizer) setAuth(host string, auth string) bool { - a.mu.Lock() - defer a.mu.Unlock() - - changed := a.auth[host] != auth - a.auth[host] = auth - - return changed +// authResult is used to control limit rate. +type authResult struct { + sync.WaitGroup + token string + err error } -func (a *dockerAuthorizer) setTokenAuth(ctx context.Context, host string, params map[string]string) error { - realm, ok := params["realm"] - if !ok { - return errors.New("no realm specified for token auth challenge") - } +// authHandler is used to handle auth request per registry server. +type authHandler struct { + sync.Mutex - realmURL, err := url.Parse(realm) - if err != nil { - return errors.Wrap(err, "invalid token auth challenge realm") - } + header http.Header - to := tokenOptions{ - realm: realmURL.String(), - service: params["service"], - } + client *http.Client - to.scopes = getTokenScopes(ctx, params) - if len(to.scopes) == 0 { - return errors.Errorf("no scope specified for token auth challenge") - } + // only support basic and bearer schemes + scheme auth.AuthenticationScheme - if a.credentials != nil { - to.username, to.secret, err = a.credentials(host) - if err != nil { - return err - } - } + // common contains common challenge answer + common auth.TokenOptions - var token string - if to.secret != "" { - // Credential information is provided, use oauth POST endpoint - token, err = a.fetchTokenWithOAuth(ctx, to) - if err != nil { - return errors.Wrap(err, "failed to fetch oauth token") - } - } else { - // Do request anonymously - token, err = a.fetchToken(ctx, to) - if err != nil { - return errors.Wrap(err, "failed to fetch anonymous token") - } - } - a.setAuth(host, fmt.Sprintf("Bearer %s", token)) - - return nil + // scopedTokens caches token indexed by scopes, which used in + // bearer auth case + scopedTokens map[string]*authResult } -type tokenOptions struct { - realm string - service string - scopes []string - username string - secret string -} - -type postTokenResponse struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpiresIn int `json:"expires_in"` - IssuedAt time.Time `json:"issued_at"` - Scope string `json:"scope"` -} - -func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) (string, error) { - form := url.Values{} - form.Set("scope", strings.Join(to.scopes, " ")) - form.Set("service", to.service) - // TODO: Allow setting client_id - form.Set("client_id", "containerd-client") - - if to.username == "" { - form.Set("grant_type", "refresh_token") - form.Set("refresh_token", to.secret) - } else { - form.Set("grant_type", "password") - form.Set("username", to.username) - form.Set("password", to.secret) - } - - resp, err := ctxhttp.PostForm(ctx, a.client, to.realm, form) - if err != nil { - return "", err - } - defer resp.Body.Close() - - // Registries without support for POST may return 404 for POST /v2/token. - // As of September 2017, GCR is known to return 404. - // As of February 2018, JFrog Artifactory is known to return 401. - if (resp.StatusCode == 405 && to.username != "") || resp.StatusCode == 404 || resp.StatusCode == 401 { - return a.fetchToken(ctx, to) - } else if resp.StatusCode < 200 || resp.StatusCode >= 400 { - b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB - log.G(ctx).WithFields(logrus.Fields{ - "status": resp.Status, - "body": string(b), - }).Debugf("token request failed") - // TODO: handle error body and write debug output - return "", errors.Errorf("unexpected status: %s", resp.Status) - } - - decoder := json.NewDecoder(resp.Body) - - var tr postTokenResponse - if err = decoder.Decode(&tr); err != nil { - return "", fmt.Errorf("unable to decode token response: %s", err) +func newAuthHandler(client *http.Client, hdr http.Header, scheme auth.AuthenticationScheme, opts auth.TokenOptions) *authHandler { + return &authHandler{ + header: hdr, + client: client, + scheme: scheme, + common: opts, + scopedTokens: map[string]*authResult{}, } - - return tr.AccessToken, nil -} - -type getTokenResponse struct { - Token string `json:"token"` - AccessToken string `json:"access_token"` - ExpiresIn int `json:"expires_in"` - IssuedAt time.Time `json:"issued_at"` - RefreshToken string `json:"refresh_token"` } -// getToken fetches a token using a GET request -func (a *dockerAuthorizer) fetchToken(ctx context.Context, to tokenOptions) (string, error) { - req, err := http.NewRequest("GET", to.realm, nil) - if err != nil { - return "", err +func (ah *authHandler) authorize(ctx context.Context) (string, error) { + switch ah.scheme { + case auth.BasicAuth: + return ah.doBasicAuth(ctx) + case auth.BearerAuth: + return ah.doBearerAuth(ctx) + default: + return "", errors.Wrapf(errdefs.ErrNotImplemented, "failed to find supported auth scheme: %s", string(ah.scheme)) } +} - reqParams := req.URL.Query() +func (ah *authHandler) doBasicAuth(ctx context.Context) (string, error) { + username, secret := ah.common.Username, ah.common.Secret - if to.service != "" { - reqParams.Add("service", to.service) + if username == "" || secret == "" { + return "", fmt.Errorf("failed to handle basic auth because missing username or secret") } - for _, scope := range to.scopes { - reqParams.Add("scope", scope) - } + auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + secret)) + return fmt.Sprintf("Basic %s", auth), nil +} - if to.secret != "" { - req.SetBasicAuth(to.username, to.secret) - } +func (ah *authHandler) doBearerAuth(ctx context.Context) (token string, err error) { + // copy common tokenOptions + to := ah.common - req.URL.RawQuery = reqParams.Encode() + to.Scopes = GetTokenScopes(ctx, to.Scopes) - resp, err := ctxhttp.Do(ctx, a.client, req) - if err != nil { - return "", err - } - defer resp.Body.Close() + // Docs: https://docs.docker.com/registry/spec/auth/scope + scoped := strings.Join(to.Scopes, " ") - if resp.StatusCode < 200 || resp.StatusCode >= 400 { - // TODO: handle error body and write debug output - return "", errors.Errorf("unexpected status: %s", resp.Status) + ah.Lock() + if r, exist := ah.scopedTokens[scoped]; exist { + ah.Unlock() + r.Wait() + return r.token, r.err } - decoder := json.NewDecoder(resp.Body) + // only one fetch token job + r := new(authResult) + r.Add(1) + ah.scopedTokens[scoped] = r + ah.Unlock() - var tr getTokenResponse - if err = decoder.Decode(&tr); err != nil { - return "", fmt.Errorf("unable to decode token response: %s", err) - } + defer func() { + token = fmt.Sprintf("Bearer %s", token) + r.token, r.err = token, err + r.Done() + }() - // `access_token` is equivalent to `token` and if both are specified - // the choice is undefined. Canonicalize `access_token` by sticking - // things in `token`. - if tr.AccessToken != "" { - tr.Token = tr.AccessToken + // fetch token for the resource scope + if to.Secret != "" { + defer func() { + err = errors.Wrap(err, "failed to fetch oauth token") + }() + // credential information is provided, use oauth POST endpoint + // TODO: Allow setting client_id + resp, err := auth.FetchTokenWithOAuth(ctx, ah.client, ah.header, "containerd-client", to) + if err != nil { + var errStatus remoteerrors.ErrUnexpectedStatus + if errors.As(err, &errStatus) { + // Registries without support for POST may return 404 for POST /v2/token. + // As of September 2017, GCR is known to return 404. + // As of February 2018, JFrog Artifactory is known to return 401. + if (errStatus.StatusCode == 405 && to.Username != "") || errStatus.StatusCode == 404 || errStatus.StatusCode == 401 { + resp, err := auth.FetchToken(ctx, ah.client, ah.header, to) + if err != nil { + return "", err + } + return resp.Token, nil + } + log.G(ctx).WithFields(logrus.Fields{ + "status": errStatus.Status, + "body": string(errStatus.Body), + }).Debugf("token request failed") + } + return "", err + } + return resp.AccessToken, nil } - - if tr.Token == "" { - return "", ErrNoToken + // do request anonymously + resp, err := auth.FetchToken(ctx, ah.client, ah.header, to) + if err != nil { + return "", errors.Wrap(err, "failed to fetch anonymous token") } - - return tr.Token, nil + return resp.Token, nil } -func invalidAuthorization(c challenge, responses []*http.Response) error { - errStr := c.parameters["error"] +func invalidAuthorization(c auth.Challenge, responses []*http.Response) error { + errStr := c.Parameters["error"] if errStr == "" { return nil } diff -Nru containerd-1.2.6/remotes/docker/config/config_unix.go containerd-1.5.9/remotes/docker/config/config_unix.go --- containerd-1.2.6/remotes/docker/config/config_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/config/config_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "crypto/x509" + "path/filepath" +) + +func hostPaths(root, host string) []string { + ch := hostDirectory(host) + if ch == host { + return []string{filepath.Join(root, host)} + } + + return []string{ + filepath.Join(root, ch), + filepath.Join(root, host), + } +} + +func rootSystemPool() (*x509.CertPool, error) { + return x509.SystemCertPool() +} diff -Nru containerd-1.2.6/remotes/docker/config/config_windows.go containerd-1.5.9/remotes/docker/config/config_windows.go --- containerd-1.2.6/remotes/docker/config/config_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/config/config_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,41 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "crypto/x509" + "path/filepath" + "strings" +) + +func hostPaths(root, host string) []string { + ch := hostDirectory(host) + if ch == host { + return []string{filepath.Join(root, host)} + } + + return []string{ + filepath.Join(root, strings.Replace(ch, ":", "", -1)), + filepath.Join(root, strings.Replace(host, ":", "", -1)), + } +} + +func rootSystemPool() (*x509.CertPool, error) { + return x509.NewCertPool(), nil +} diff -Nru containerd-1.2.6/remotes/docker/config/hosts.go containerd-1.5.9/remotes/docker/config/hosts.go --- containerd-1.2.6/remotes/docker/config/hosts.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/config/hosts.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,557 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package config contains utilities for helping configure the Docker resolver +package config + +import ( + "context" + "crypto/tls" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/remotes/docker" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" +) + +// UpdateClientFunc is a function that lets you to amend http Client behavior used by registry clients. +type UpdateClientFunc func(client *http.Client) error + +type hostConfig struct { + scheme string + host string + path string + + capabilities docker.HostCapabilities + + caCerts []string + clientPairs [][2]string + skipVerify *bool + + header http.Header + + // TODO: API ("docker" or "oci") + // TODO: API Version ("v1", "v2") + // TODO: Add credential configuration (domain alias, username) +} + +// HostOptions is used to configure registry hosts +type HostOptions struct { + HostDir func(string) (string, error) + Credentials func(host string) (string, string, error) + DefaultTLS *tls.Config + DefaultScheme string + // UpdateClient will be called after creating http.Client object, so clients can provide extra configuration + UpdateClient UpdateClientFunc +} + +// ConfigureHosts creates a registry hosts function from the provided +// host creation options. The host directory can read hosts.toml or +// certificate files laid out in the Docker specific layout. +// If a `HostDir` function is not required, defaults are used. +func ConfigureHosts(ctx context.Context, options HostOptions) docker.RegistryHosts { + return func(host string) ([]docker.RegistryHost, error) { + var hosts []hostConfig + if options.HostDir != nil { + dir, err := options.HostDir(host) + if err != nil && !errdefs.IsNotFound(err) { + return nil, err + } + if dir != "" { + log.G(ctx).WithField("dir", dir).Debug("loading host directory") + hosts, err = loadHostDir(ctx, dir) + if err != nil { + return nil, err + } + } + } + + // If hosts was not set, add a default host + // NOTE: Check nil here and not empty, the host may be + // intentionally configured to not have any endpoints + if hosts == nil { + hosts = make([]hostConfig, 1) + } + if len(hosts) > 0 && hosts[len(hosts)-1].host == "" { + if host == "docker.io" { + hosts[len(hosts)-1].scheme = "https" + hosts[len(hosts)-1].host = "registry-1.docker.io" + } else { + hosts[len(hosts)-1].host = host + if options.DefaultScheme != "" { + hosts[len(hosts)-1].scheme = options.DefaultScheme + } else { + hosts[len(hosts)-1].scheme = "https" + } + } + hosts[len(hosts)-1].path = "/v2" + hosts[len(hosts)-1].capabilities = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush + } + + var defaultTLSConfig *tls.Config + if options.DefaultTLS != nil { + defaultTLSConfig = options.DefaultTLS + } else { + defaultTLSConfig = &tls.Config{} + } + + defaultTransport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + FallbackDelay: 300 * time.Millisecond, + }).DialContext, + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + TLSClientConfig: defaultTLSConfig, + ExpectContinueTimeout: 5 * time.Second, + } + + client := &http.Client{ + Transport: defaultTransport, + } + if options.UpdateClient != nil { + if err := options.UpdateClient(client); err != nil { + return nil, err + } + } + + authOpts := []docker.AuthorizerOpt{docker.WithAuthClient(client)} + if options.Credentials != nil { + authOpts = append(authOpts, docker.WithAuthCreds(options.Credentials)) + } + authorizer := docker.NewDockerAuthorizer(authOpts...) + + rhosts := make([]docker.RegistryHost, len(hosts)) + for i, host := range hosts { + + rhosts[i].Scheme = host.scheme + rhosts[i].Host = host.host + rhosts[i].Path = host.path + rhosts[i].Capabilities = host.capabilities + rhosts[i].Header = host.header + + if host.caCerts != nil || host.clientPairs != nil || host.skipVerify != nil { + tr := defaultTransport.Clone() + tlsConfig := tr.TLSClientConfig + if host.skipVerify != nil { + tlsConfig.InsecureSkipVerify = *host.skipVerify + } + if host.caCerts != nil { + if tlsConfig.RootCAs == nil { + rootPool, err := rootSystemPool() + if err != nil { + return nil, errors.Wrap(err, "unable to initialize cert pool") + } + tlsConfig.RootCAs = rootPool + } + for _, f := range host.caCerts { + data, err := ioutil.ReadFile(f) + if err != nil { + return nil, errors.Wrapf(err, "unable to read CA cert %q", f) + } + if !tlsConfig.RootCAs.AppendCertsFromPEM(data) { + return nil, errors.Errorf("unable to load CA cert %q", f) + } + } + } + + if host.clientPairs != nil { + for _, pair := range host.clientPairs { + certPEMBlock, err := ioutil.ReadFile(pair[0]) + if err != nil { + return nil, errors.Wrapf(err, "unable to read CERT file %q", pair[0]) + } + var keyPEMBlock []byte + if pair[1] != "" { + keyPEMBlock, err = ioutil.ReadFile(pair[1]) + if err != nil { + return nil, errors.Wrapf(err, "unable to read CERT file %q", pair[1]) + } + } else { + // Load key block from same PEM file + keyPEMBlock = certPEMBlock + } + cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) + if err != nil { + return nil, errors.Wrap(err, "failed to load X509 key pair") + } + + tlsConfig.Certificates = append(tlsConfig.Certificates, cert) + } + } + + c := *client + c.Transport = tr + if options.UpdateClient != nil { + if err := options.UpdateClient(&c); err != nil { + return nil, err + } + } + + rhosts[i].Client = &c + rhosts[i].Authorizer = docker.NewDockerAuthorizer(append(authOpts, docker.WithAuthClient(&c))...) + } else { + rhosts[i].Client = client + rhosts[i].Authorizer = authorizer + } + } + + return rhosts, nil + } + +} + +// HostDirFromRoot returns a function which finds a host directory +// based at the given root. +func HostDirFromRoot(root string) func(string) (string, error) { + return func(host string) (string, error) { + for _, p := range hostPaths(root, host) { + if _, err := os.Stat(p); err == nil { + return p, nil + } else if !os.IsNotExist(err) { + return "", err + } + } + return "", errdefs.ErrNotFound + } +} + +// hostDirectory converts ":port" to "_port_" in directory names +func hostDirectory(host string) string { + idx := strings.LastIndex(host, ":") + if idx > 0 { + return host[:idx] + "_" + host[idx+1:] + "_" + } + return host +} + +func loadHostDir(ctx context.Context, hostsDir string) ([]hostConfig, error) { + b, err := ioutil.ReadFile(filepath.Join(hostsDir, "hosts.toml")) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + + if len(b) == 0 { + // If hosts.toml does not exist, fallback to checking for + // certificate files based on Docker's certificate file + // pattern (".crt", ".cert", ".key" files) + return loadCertFiles(ctx, hostsDir) + } + + hosts, err := parseHostsFile(hostsDir, b) + if err != nil { + log.G(ctx).WithError(err).Error("failed to decode hosts.toml") + // Fallback to checking certificate files + return loadCertFiles(ctx, hostsDir) + } + + return hosts, nil +} + +type hostFileConfig struct { + // Capabilities determine what operations a host is + // capable of performing. Allowed values + // - pull + // - resolve + // - push + Capabilities []string `toml:"capabilities"` + + // CACert can be a string or an array of strings + CACert interface{} `toml:"ca"` + + // TODO: Make this an array (two key types, one for pairs (multiple files), one for single file?) + Client interface{} `toml:"client"` + + SkipVerify *bool `toml:"skip_verify"` + + Header map[string]interface{} `toml:"header"` + + // API (default: "docker") + // API Version (default: "v2") + // Credentials: helper? name? username? alternate domain? token? +} + +func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) { + tree, err := toml.LoadBytes(b) + if err != nil { + return nil, errors.Wrap(err, "failed to parse TOML") + } + + // HACK: we want to keep toml parsing structures private in this package, however go-toml ignores private embedded types. + // so we remap it to a public type within the func body, so technically it's public, but not possible to import elsewhere. + type HostFileConfig = hostFileConfig + + c := struct { + HostFileConfig + // Server specifies the default server. When `host` is + // also specified, those hosts are tried first. + Server string `toml:"server"` + // HostConfigs store the per-host configuration + HostConfigs map[string]hostFileConfig `toml:"host"` + }{} + + orderedHosts, err := getSortedHosts(tree) + if err != nil { + return nil, err + } + + var ( + hosts []hostConfig + ) + + if err := tree.Unmarshal(&c); err != nil { + return nil, err + } + + // Parse hosts array + for _, host := range orderedHosts { + config := c.HostConfigs[host] + + parsed, err := parseHostConfig(host, baseDir, config) + if err != nil { + return nil, err + } + hosts = append(hosts, parsed) + } + + // Parse root host config and append it as the last element + parsed, err := parseHostConfig(c.Server, baseDir, c.HostFileConfig) + if err != nil { + return nil, err + } + hosts = append(hosts, parsed) + + return hosts, nil +} + +func parseHostConfig(server string, baseDir string, config hostFileConfig) (hostConfig, error) { + var ( + result = hostConfig{} + err error + ) + + if server != "" { + if !strings.HasPrefix(server, "http") { + server = "https://" + server + } + u, err := url.Parse(server) + if err != nil { + return hostConfig{}, errors.Wrapf(err, "unable to parse server %v", server) + } + result.scheme = u.Scheme + result.host = u.Host + // TODO: Handle path based on registry protocol + // Define a registry protocol type + // OCI v1 - Always use given path as is + // Docker v2 - Always ensure ends with /v2/ + if len(u.Path) > 0 { + u.Path = path.Clean(u.Path) + if !strings.HasSuffix(u.Path, "/v2") { + u.Path = u.Path + "/v2" + } + } else { + u.Path = "/v2" + } + result.path = u.Path + } + + result.skipVerify = config.SkipVerify + + if len(config.Capabilities) > 0 { + for _, c := range config.Capabilities { + switch strings.ToLower(c) { + case "pull": + result.capabilities |= docker.HostCapabilityPull + case "resolve": + result.capabilities |= docker.HostCapabilityResolve + case "push": + result.capabilities |= docker.HostCapabilityPush + default: + return hostConfig{}, errors.Errorf("unknown capability %v", c) + } + } + } else { + result.capabilities = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush + } + + if config.CACert != nil { + switch cert := config.CACert.(type) { + case string: + result.caCerts = []string{makeAbsPath(cert, baseDir)} + case []interface{}: + result.caCerts, err = makeStringSlice(cert, func(p string) string { + return makeAbsPath(p, baseDir) + }) + if err != nil { + return hostConfig{}, err + } + default: + return hostConfig{}, errors.Errorf("invalid type %v for \"ca\"", cert) + } + } + + if config.Client != nil { + switch client := config.Client.(type) { + case string: + result.clientPairs = [][2]string{{makeAbsPath(client, baseDir), ""}} + case []interface{}: + // []string or [][2]string + for _, pairs := range client { + switch p := pairs.(type) { + case string: + result.clientPairs = append(result.clientPairs, [2]string{makeAbsPath(p, baseDir), ""}) + case []interface{}: + slice, err := makeStringSlice(p, func(s string) string { + return makeAbsPath(s, baseDir) + }) + if err != nil { + return hostConfig{}, err + } + if len(slice) != 2 { + return hostConfig{}, errors.Errorf("invalid pair %v for \"client\"", p) + } + + var pair [2]string + copy(pair[:], slice) + result.clientPairs = append(result.clientPairs, pair) + default: + return hostConfig{}, errors.Errorf("invalid type %T for \"client\"", p) + } + } + default: + return hostConfig{}, errors.Errorf("invalid type %v for \"client\"", client) + } + } + + if config.Header != nil { + header := http.Header{} + for key, ty := range config.Header { + switch value := ty.(type) { + case string: + header[key] = []string{value} + case []interface{}: + header[key], err = makeStringSlice(value, nil) + if err != nil { + return hostConfig{}, err + } + default: + return hostConfig{}, errors.Errorf("invalid type %v for header %q", ty, key) + } + } + result.header = header + } + + return result, nil +} + +// getSortedHosts returns the list of hosts as they defined in the file. +func getSortedHosts(root *toml.Tree) ([]string, error) { + iter, ok := root.Get("host").(*toml.Tree) + if !ok { + return nil, errors.Errorf("invalid `host` tree") + } + + list := append([]string{}, iter.Keys()...) + + // go-toml stores TOML sections in the map object, so no order guaranteed. + // We retrieve line number for each key and sort the keys by position. + sort.Slice(list, func(i, j int) bool { + h1 := iter.GetPath([]string{list[i]}).(*toml.Tree) + h2 := iter.GetPath([]string{list[j]}).(*toml.Tree) + return h1.Position().Line < h2.Position().Line + }) + + return list, nil +} + +// makeStringSlice is a helper func to convert from []interface{} to []string. +// Additionally an optional cb func may be passed to perform string mapping. +func makeStringSlice(slice []interface{}, cb func(string) string) ([]string, error) { + out := make([]string, len(slice)) + for i, value := range slice { + str, ok := value.(string) + if !ok { + return nil, errors.Errorf("unable to cast %v to string", value) + } + + if cb != nil { + out[i] = cb(str) + } else { + out[i] = str + } + } + return out, nil +} + +func makeAbsPath(p string, base string) string { + if filepath.IsAbs(p) { + return p + } + return filepath.Join(base, p) +} + +// loadCertsDir loads certs from certsDir like "/etc/docker/certs.d" . +// Compatible with Docker file layout +// - files ending with ".crt" are treated as CA certificate files +// - files ending with ".cert" are treated as client certificates, and +// files with the same name but ending with ".key" are treated as the +// corresponding private key. +// NOTE: If a ".key" file is missing, this function will just return +// the ".cert", which may contain the private key. If the ".cert" file +// does not contain the private key, the caller should detect and error. +func loadCertFiles(ctx context.Context, certsDir string) ([]hostConfig, error) { + fs, err := ioutil.ReadDir(certsDir) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + hosts := make([]hostConfig, 1) + for _, f := range fs { + if f.IsDir() { + continue + } + if strings.HasSuffix(f.Name(), ".crt") { + hosts[0].caCerts = append(hosts[0].caCerts, filepath.Join(certsDir, f.Name())) + } + if strings.HasSuffix(f.Name(), ".cert") { + var pair [2]string + certFile := f.Name() + pair[0] = filepath.Join(certsDir, certFile) + // Check if key also exists + keyFile := filepath.Join(certsDir, certFile[:len(certFile)-5]+".key") + if _, err := os.Stat(keyFile); err == nil { + pair[1] = keyFile + } else if !os.IsNotExist(err) { + return nil, err + } + hosts[0].clientPairs = append(hosts[0].clientPairs, pair) + } + } + return hosts, nil +} diff -Nru containerd-1.2.6/remotes/docker/config/hosts_test.go containerd-1.5.9/remotes/docker/config/hosts_test.go --- containerd-1.2.6/remotes/docker/config/hosts_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/config/hosts_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,398 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "testing" + + "github.com/containerd/containerd/log/logtest" + "github.com/containerd/containerd/remotes/docker" +) + +const allCaps = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush + +func TestDefaultHosts(t *testing.T) { + ctx := logtest.WithT(context.Background(), t) + resolve := ConfigureHosts(ctx, HostOptions{}) + + for _, tc := range []struct { + host string + expected []docker.RegistryHost + }{ + { + host: "docker.io", + expected: []docker.RegistryHost{ + { + Scheme: "https", + Host: "registry-1.docker.io", + Path: "/v2", + Capabilities: allCaps, + }, + }, + }, + } { + hosts, err := resolve(tc.host) + if err != nil { + t.Errorf("[%s] resolve failed: %v", tc.host, err) + continue + } + if len(hosts) != len(tc.expected) { + t.Errorf("[%s] unexpected number of hosts %d, expected %d", tc.host, len(hosts), len(tc.expected)) + continue + } + for j := range hosts { + if !compareRegistryHost(hosts[j], tc.expected[j]) { + + t.Errorf("[%s] [%d] unexpected host %v, expected %v", tc.host, j, hosts[j], tc.expected[j]) + break + } + + } + + } +} + +func TestParseHostFile(t *testing.T) { + const testtoml = ` +server = "https://test-default.registry" +ca = "/etc/path/default" +[header] + x-custom-1 = "custom header" + +[host."https://mirror.registry"] + capabilities = ["pull"] + ca = "/etc/certs/mirror.pem" + skip_verify = false + [host."https://mirror.registry".header] + x-custom-2 = ["value1", "value2"] + +[host."https://mirror-bak.registry/us"] + capabilities = ["pull"] + skip_verify = true + +[host."http://mirror.registry"] + capabilities = ["pull"] + +[host."https://test-1.registry"] + capabilities = ["pull", "resolve", "push"] + ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"] + client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]] + +[host."https://test-2.registry"] + client = "/etc/certs/client.pem" + +[host."https://test-3.registry"] + client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] +` + var tb, fb = true, false + expected := []hostConfig{ + { + scheme: "https", + host: "mirror.registry", + path: "/v2", + capabilities: docker.HostCapabilityPull, + caCerts: []string{filepath.FromSlash("/etc/certs/mirror.pem")}, + skipVerify: &fb, + header: http.Header{"x-custom-2": {"value1", "value2"}}, + }, + { + scheme: "https", + host: "mirror-bak.registry", + path: "/us/v2", + capabilities: docker.HostCapabilityPull, + skipVerify: &tb, + }, + { + scheme: "http", + host: "mirror.registry", + path: "/v2", + capabilities: docker.HostCapabilityPull, + }, + { + scheme: "https", + host: "test-1.registry", + path: "/v2", + capabilities: allCaps, + caCerts: []string{filepath.FromSlash("/etc/certs/test-1-ca.pem"), filepath.FromSlash("/etc/certs/special.pem")}, + clientPairs: [][2]string{ + {filepath.FromSlash("/etc/certs/client.cert"), filepath.FromSlash("/etc/certs/client.key")}, + {filepath.FromSlash("/etc/certs/client.pem"), ""}, + }, + }, + { + scheme: "https", + host: "test-2.registry", + path: "/v2", + capabilities: allCaps, + clientPairs: [][2]string{ + {filepath.FromSlash("/etc/certs/client.pem")}, + }, + }, + { + scheme: "https", + host: "test-3.registry", + path: "/v2", + capabilities: allCaps, + clientPairs: [][2]string{ + {filepath.FromSlash("/etc/certs/client-1.pem")}, + {filepath.FromSlash("/etc/certs/client-2.pem")}, + }, + }, + { + scheme: "https", + host: "test-default.registry", + path: "/v2", + capabilities: allCaps, + caCerts: []string{filepath.FromSlash("/etc/path/default")}, + header: http.Header{"x-custom-1": {"custom header"}}, + }, + } + hosts, err := parseHostsFile("", []byte(testtoml)) + if err != nil { + t.Fatal(err) + } + + defer func() { + if t.Failed() { + t.Log("HostConfigs...\nActual:\n" + printHostConfig(hosts) + "Expected:\n" + printHostConfig(expected)) + } + }() + + if len(hosts) != len(expected) { + t.Fatalf("Unexpected number of hosts %d, expected %d", len(hosts), len(expected)) + } + + for i := range hosts { + if !compareHostConfig(hosts[i], expected[i]) { + t.Fatalf("Mismatch at host %d", i) + } + } +} + +func TestLoadCertFiles(t *testing.T) { + dir, err := ioutil.TempDir("", t.Name()) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + type testCase struct { + input hostConfig + } + cases := map[string]testCase{ + "crt only": { + input: hostConfig{host: "testing.io", caCerts: []string{filepath.Join(dir, "testing.io", "ca.crt")}}, + }, + "crt and cert pair": { + input: hostConfig{ + host: "testing.io", + caCerts: []string{filepath.Join(dir, "testing.io", "ca.crt")}, + clientPairs: [][2]string{ + { + filepath.Join(dir, "testing.io", "client.cert"), + filepath.Join(dir, "testing.io", "client.key"), + }, + }, + }, + }, + "cert pair only": { + input: hostConfig{ + host: "testing.io", + clientPairs: [][2]string{ + { + filepath.Join(dir, "testing.io", "client.cert"), + filepath.Join(dir, "testing.io", "client.key"), + }, + }, + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + + hostDir := filepath.Join(dir, tc.input.host) + if err := os.MkdirAll(hostDir, 0700); err != nil { + t.Fatal(err) + } + defer os.RemoveAll(hostDir) + + for _, f := range tc.input.caCerts { + if err := ioutil.WriteFile(f, testKey, 0600); err != nil { + t.Fatal(err) + } + } + + for _, pair := range tc.input.clientPairs { + if err := ioutil.WriteFile(pair[0], testKey, 0600); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(pair[1], testKey, 0600); err != nil { + t.Fatal(err) + } + } + + configs, err := loadHostDir(context.Background(), hostDir) + if err != nil { + t.Fatal(err) + } + if len(configs) != 1 { + t.Fatalf("\nexpected:\n%+v\ngot:\n%+v", tc.input, configs) + } + + cfg := configs[0] + cfg.host = tc.input.host + + if !compareHostConfig(cfg, tc.input) { + t.Errorf("\nexpected:\n%+v:\n\ngot:\n%+v", tc.input, cfg) + } + }) + } +} + +func compareRegistryHost(j, k docker.RegistryHost) bool { + if j.Scheme != k.Scheme { + return false + } + if j.Host != k.Host { + return false + } + if j.Path != k.Path { + return false + } + if j.Capabilities != k.Capabilities { + return false + } + // Not comparing TLS configs or authorizations + return true +} + +func compareHostConfig(j, k hostConfig) bool { + if j.scheme != k.scheme { + return false + } + if j.host != k.host { + return false + } + if j.path != k.path { + return false + } + if j.capabilities != k.capabilities { + return false + } + + if len(j.caCerts) != len(k.caCerts) { + return false + } + for i := range j.caCerts { + if j.caCerts[i] != k.caCerts[i] { + return false + } + } + if len(j.clientPairs) != len(k.clientPairs) { + return false + } + for i := range j.clientPairs { + if j.clientPairs[i][0] != k.clientPairs[i][0] { + return false + } + if j.clientPairs[i][1] != k.clientPairs[i][1] { + return false + } + } + if j.skipVerify != nil && k.skipVerify != nil { + if *j.skipVerify != *k.skipVerify { + return false + } + } else if j.skipVerify != nil || k.skipVerify != nil { + return false + } + + if len(j.header) != len(k.header) { + return false + } + for key := range j.header { + if len(j.header[key]) != len(k.header[key]) { + return false + } + for i := range j.header[key] { + if j.header[key][i] != k.header[key][i] { + return false + } + } + } + + return true +} + +func printHostConfig(hc []hostConfig) string { + b := bytes.NewBuffer(nil) + for i := range hc { + fmt.Fprintf(b, "\t[%d]\tscheme: %q\n", i, hc[i].scheme) + fmt.Fprintf(b, "\t\thost: %q\n", hc[i].host) + fmt.Fprintf(b, "\t\tpath: %q\n", hc[i].path) + fmt.Fprintf(b, "\t\tcaps: %03b\n", hc[i].capabilities) + fmt.Fprintf(b, "\t\tca: %#v\n", hc[i].caCerts) + fmt.Fprintf(b, "\t\tclients: %#v\n", hc[i].clientPairs) + if hc[i].skipVerify == nil { + fmt.Fprintf(b, "\t\tskip-verify: %v\n", hc[i].skipVerify) + } else { + fmt.Fprintf(b, "\t\tskip-verify: %t\n", *hc[i].skipVerify) + } + fmt.Fprintf(b, "\t\theader: %#v\n", hc[i].header) + } + return b.String() +} + +var ( + testKey = []byte(`-----BEGIN PRIVATE KEY----- + MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDa+zvPgFXwra4S + 0DzEWRgZHxVTDG1sJsnN/jOaHCNpRyABGVW5kdei9WFWv3dpiELI+guQMjdUL++w + M68bs6cXKW+1nW6u5uWuGwklOwkoKoeHkkn/vHef7ybk+5qdk6AYY0DKQsrBBOvj + f0WAnG+1xi8VIOEBmce0/47MexOiuILVkjokgdmDCOc8ShkT6/EJTCsI1wDew/4G + 9IiRzw2xSM0ZATAtEC3HEBRLJGWZQtuKlLCuzJ+erOWUcg2cjnSgR3PmaAXE//5g + SoeqEbtTo1satf9AR4VvreIAI8m0eyo8ABMLTkZovEFcUUHetL63hdqItjCeRfrQ + zK4LMRFbAgMBAAECggEBAJtP6UHo0gtcA8SQMSlJz4+xvhwjClDUyfjyPIMnRe5b + ZdWhtG1jhT+tLhaqwfT1kfidcCobk6aAQU4FukK5jt8cooB7Yo9mcKylvDzNvFbi + ozGCjj113JpwsnNiCG2O0NO7Qa6y5L810GCQWik3yvtvzuD7atsJyN0VDKD3Ahw7 + 1X8z76grZFlhVMCTAA3vAJ2y2p3sd+TGC/PIhnsvChwxEorGCnMj93mBaUI7zZRY + EZhlk4ZvC9sUvlVUuYC+wAHjasgN9s3AzsOBSx+Xt3NaXQHzhL0mVo/vu/pjjFBs + WBLR1PBoIfveTJPOp+Hrr4cuCK0NuX9sWlWPYLl5A2ECgYEA5fq3n4PhbJ2BuTS5 + AVgOmjRpk1eogb6aSY+cx7Mr++ADF9EYXc5tgKoUsDeeiiyK2lv6IKavoTWT1kdd + shiclyEzp2CxG5GtbC/g2XHiBLepgo1fjfev3btCmIeGVBjglOx4F3gEsRygrAID + zcz94m2I+uqLT8hvWnccIqScglkCgYEA88H2ji4Nvx6TmqCLcER0vNDVoxxDfgGb + iohvenD2jmmdTnezTddsgECAI8L0BPNS/0vBCduTjs5BqhKbIfQvuK5CANMUcxuQ + twWH8kPvTYJVgsmWP6sSXSz3PohWC5EA9xACExGtyN6d7sLUCV0SBhjlcgMvGuDM + lP6NjyyWctMCgYBKdfGr+QQsqZaNw48+6ybXMK8aIKCTWYYU2SW21sEf7PizZmTQ + Qnzb0rWeFHQFYsSWTH9gwPdOZ8107GheuG9C02IpCDpvpawTwjC31pKKWnjMpz9P + 9OkBDpdSUVbhtahJL4L2fkpumck/x+s5X+y3uiVGsFfovgmnrbbzVH7ECQKBgQCC + MYs7DaYR+obkA/P2FtozL2esIyB5YOpu58iDIWrPTeHTU2PVo8Y0Cj9m2m3zZvNh + oFiOp1T85XV1HVL2o7IJdimSvyshAAwfdTjTUS2zvHVn0bwKbZj1Y1r7b15l9yEI + 1OgGv16O9zhrmmweRDOoRgvnBYRXWtJqkjuRyULiOQKBgQC/lSYigV32Eb8Eg1pv + 7OcPWv4qV4880lRE0MXuQ4VFa4+pqvdziYFYQD4jDYJ4IX9l//bsobL0j7z0P0Gk + wDFti9bRwRoO1ntqoA8n2pDLlLRGl0dyjB6fHzp27oqtyf1HRlHiow7Gqx5b5JOk + tycYKwA3DuaSyqPe6MthLneq8w== + -----END PRIVATE KEY----- + `) +) diff -Nru containerd-1.2.6/remotes/docker/errcode.go containerd-1.5.9/remotes/docker/errcode.go --- containerd-1.2.6/remotes/docker/errcode.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/errcode.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,283 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "encoding/json" + "fmt" + "strings" +) + +// ErrorCoder is the base interface for ErrorCode and Error allowing +// users of each to just call ErrorCode to get the real ID of each +type ErrorCoder interface { + ErrorCode() ErrorCode +} + +// ErrorCode represents the error type. The errors are serialized via strings +// and the integer format may change and should *never* be exported. +type ErrorCode int + +var _ error = ErrorCode(0) + +// ErrorCode just returns itself +func (ec ErrorCode) ErrorCode() ErrorCode { + return ec +} + +// Error returns the ID/Value +func (ec ErrorCode) Error() string { + // NOTE(stevvooe): Cannot use message here since it may have unpopulated args. + return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1)) +} + +// Descriptor returns the descriptor for the error code. +func (ec ErrorCode) Descriptor() ErrorDescriptor { + d, ok := errorCodeToDescriptors[ec] + + if !ok { + return ErrorCodeUnknown.Descriptor() + } + + return d +} + +// String returns the canonical identifier for this error code. +func (ec ErrorCode) String() string { + return ec.Descriptor().Value +} + +// Message returned the human-readable error message for this error code. +func (ec ErrorCode) Message() string { + return ec.Descriptor().Message +} + +// MarshalText encodes the receiver into UTF-8-encoded text and returns the +// result. +func (ec ErrorCode) MarshalText() (text []byte, err error) { + return []byte(ec.String()), nil +} + +// UnmarshalText decodes the form generated by MarshalText. +func (ec *ErrorCode) UnmarshalText(text []byte) error { + desc, ok := idToDescriptors[string(text)] + + if !ok { + desc = ErrorCodeUnknown.Descriptor() + } + + *ec = desc.Code + + return nil +} + +// WithMessage creates a new Error struct based on the passed-in info and +// overrides the Message property. +func (ec ErrorCode) WithMessage(message string) Error { + return Error{ + Code: ec, + Message: message, + } +} + +// WithDetail creates a new Error struct based on the passed-in info and +// set the Detail property appropriately +func (ec ErrorCode) WithDetail(detail interface{}) Error { + return Error{ + Code: ec, + Message: ec.Message(), + }.WithDetail(detail) +} + +// WithArgs creates a new Error struct and sets the Args slice +func (ec ErrorCode) WithArgs(args ...interface{}) Error { + return Error{ + Code: ec, + Message: ec.Message(), + }.WithArgs(args...) +} + +// Error provides a wrapper around ErrorCode with extra Details provided. +type Error struct { + Code ErrorCode `json:"code"` + Message string `json:"message"` + Detail interface{} `json:"detail,omitempty"` + + // TODO(duglin): See if we need an "args" property so we can do the + // variable substitution right before showing the message to the user +} + +var _ error = Error{} + +// ErrorCode returns the ID/Value of this Error +func (e Error) ErrorCode() ErrorCode { + return e.Code +} + +// Error returns a human readable representation of the error. +func (e Error) Error() string { + return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message) +} + +// WithDetail will return a new Error, based on the current one, but with +// some Detail info added +func (e Error) WithDetail(detail interface{}) Error { + return Error{ + Code: e.Code, + Message: e.Message, + Detail: detail, + } +} + +// WithArgs uses the passed-in list of interface{} as the substitution +// variables in the Error's Message string, but returns a new Error +func (e Error) WithArgs(args ...interface{}) Error { + return Error{ + Code: e.Code, + Message: fmt.Sprintf(e.Code.Message(), args...), + Detail: e.Detail, + } +} + +// ErrorDescriptor provides relevant information about a given error code. +type ErrorDescriptor struct { + // Code is the error code that this descriptor describes. + Code ErrorCode + + // Value provides a unique, string key, often captilized with + // underscores, to identify the error code. This value is used as the + // keyed value when serializing api errors. + Value string + + // Message is a short, human readable description of the error condition + // included in API responses. + Message string + + // Description provides a complete account of the errors purpose, suitable + // for use in documentation. + Description string + + // HTTPStatusCode provides the http status code that is associated with + // this error condition. + HTTPStatusCode int +} + +// ParseErrorCode returns the value by the string error code. +// `ErrorCodeUnknown` will be returned if the error is not known. +func ParseErrorCode(value string) ErrorCode { + ed, ok := idToDescriptors[value] + if ok { + return ed.Code + } + + return ErrorCodeUnknown +} + +// Errors provides the envelope for multiple errors and a few sugar methods +// for use within the application. +type Errors []error + +var _ error = Errors{} + +func (errs Errors) Error() string { + switch len(errs) { + case 0: + return "" + case 1: + return errs[0].Error() + default: + msg := "errors:\n" + for _, err := range errs { + msg += err.Error() + "\n" + } + return msg + } +} + +// Len returns the current number of errors. +func (errs Errors) Len() int { + return len(errs) +} + +// MarshalJSON converts slice of error, ErrorCode or Error into a +// slice of Error - then serializes +func (errs Errors) MarshalJSON() ([]byte, error) { + var tmpErrs struct { + Errors []Error `json:"errors,omitempty"` + } + + for _, daErr := range errs { + var err Error + + switch daErr := daErr.(type) { + case ErrorCode: + err = daErr.WithDetail(nil) + case Error: + err = daErr + default: + err = ErrorCodeUnknown.WithDetail(daErr) + + } + + // If the Error struct was setup and they forgot to set the + // Message field (meaning its "") then grab it from the ErrCode + msg := err.Message + if msg == "" { + msg = err.Code.Message() + } + + tmpErrs.Errors = append(tmpErrs.Errors, Error{ + Code: err.Code, + Message: msg, + Detail: err.Detail, + }) + } + + return json.Marshal(tmpErrs) +} + +// UnmarshalJSON deserializes []Error and then converts it into slice of +// Error or ErrorCode +func (errs *Errors) UnmarshalJSON(data []byte) error { + var tmpErrs struct { + Errors []Error + } + + if err := json.Unmarshal(data, &tmpErrs); err != nil { + return err + } + + var newErrs Errors + for _, daErr := range tmpErrs.Errors { + // If Message is empty or exactly matches the Code's message string + // then just use the Code, no need for a full Error struct + if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) { + // Error's w/o details get converted to ErrorCode + newErrs = append(newErrs, daErr.Code) + } else { + // Error's w/ details are untouched + newErrs = append(newErrs, Error{ + Code: daErr.Code, + Message: daErr.Message, + Detail: daErr.Detail, + }) + } + } + + *errs = newErrs + return nil +} diff -Nru containerd-1.2.6/remotes/docker/errdesc.go containerd-1.5.9/remotes/docker/errdesc.go --- containerd-1.2.6/remotes/docker/errdesc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/errdesc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,154 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "fmt" + "net/http" + "sort" + "sync" +) + +var ( + errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{} + idToDescriptors = map[string]ErrorDescriptor{} + groupToDescriptors = map[string][]ErrorDescriptor{} +) + +var ( + // ErrorCodeUnknown is a generic error that can be used as a last + // resort if there is no situation-specific error message that can be used + ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ + Value: "UNKNOWN", + Message: "unknown error", + Description: `Generic error returned when the error does not have an + API classification.`, + HTTPStatusCode: http.StatusInternalServerError, + }) + + // ErrorCodeUnsupported is returned when an operation is not supported. + ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{ + Value: "UNSUPPORTED", + Message: "The operation is unsupported.", + Description: `The operation was unsupported due to a missing + implementation or invalid set of parameters.`, + HTTPStatusCode: http.StatusMethodNotAllowed, + }) + + // ErrorCodeUnauthorized is returned if a request requires + // authentication. + ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ + Value: "UNAUTHORIZED", + Message: "authentication required", + Description: `The access controller was unable to authenticate + the client. Often this will be accompanied by a + Www-Authenticate HTTP response header indicating how to + authenticate.`, + HTTPStatusCode: http.StatusUnauthorized, + }) + + // ErrorCodeDenied is returned if a client does not have sufficient + // permission to perform an action. + ErrorCodeDenied = Register("errcode", ErrorDescriptor{ + Value: "DENIED", + Message: "requested access to the resource is denied", + Description: `The access controller denied access for the + operation on a resource.`, + HTTPStatusCode: http.StatusForbidden, + }) + + // ErrorCodeUnavailable provides a common error to report unavailability + // of a service or endpoint. + ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ + Value: "UNAVAILABLE", + Message: "service unavailable", + Description: "Returned when a service is not available", + HTTPStatusCode: http.StatusServiceUnavailable, + }) + + // ErrorCodeTooManyRequests is returned if a client attempts too many + // times to contact a service endpoint. + ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{ + Value: "TOOMANYREQUESTS", + Message: "too many requests", + Description: `Returned when a client attempts to contact a + service too many times`, + HTTPStatusCode: http.StatusTooManyRequests, + }) +) + +var nextCode = 1000 +var registerLock sync.Mutex + +// Register will make the passed-in error known to the environment and +// return a new ErrorCode +func Register(group string, descriptor ErrorDescriptor) ErrorCode { + registerLock.Lock() + defer registerLock.Unlock() + + descriptor.Code = ErrorCode(nextCode) + + if _, ok := idToDescriptors[descriptor.Value]; ok { + panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value)) + } + if _, ok := errorCodeToDescriptors[descriptor.Code]; ok { + panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code)) + } + + groupToDescriptors[group] = append(groupToDescriptors[group], descriptor) + errorCodeToDescriptors[descriptor.Code] = descriptor + idToDescriptors[descriptor.Value] = descriptor + + nextCode++ + return descriptor.Code +} + +type byValue []ErrorDescriptor + +func (a byValue) Len() int { return len(a) } +func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value } + +// GetGroupNames returns the list of Error group names that are registered +func GetGroupNames() []string { + keys := []string{} + + for k := range groupToDescriptors { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +// GetErrorCodeGroup returns the named group of error descriptors +func GetErrorCodeGroup(name string) []ErrorDescriptor { + desc := groupToDescriptors[name] + sort.Sort(byValue(desc)) + return desc +} + +// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are +// registered, irrespective of what group they're in +func GetErrorAllDescriptors() []ErrorDescriptor { + result := []ErrorDescriptor{} + + for _, group := range GetGroupNames() { + result = append(result, GetErrorCodeGroup(group)...) + } + sort.Sort(byValue(result)) + return result +} diff -Nru containerd-1.2.6/remotes/docker/fetcher.go containerd-1.5.9/remotes/docker/fetcher.go --- containerd-1.2.6/remotes/docker/fetcher.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/fetcher.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,11 +18,12 @@ import ( "context" + "encoding/json" "fmt" "io" "io/ioutil" "net/http" - "path" + "net/url" "strings" "github.com/containerd/containerd/errdefs" @@ -30,7 +31,6 @@ "github.com/containerd/containerd/log" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) type dockerFetcher struct { @@ -38,26 +38,50 @@ } func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { - ctx = log.WithLogger(ctx, log.G(ctx).WithFields( - logrus.Fields{ - "base": r.base.String(), - "digest": desc.Digest, - }, - )) + ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest)) - urls, err := r.getV2URLPaths(ctx, desc) - if err != nil { - return nil, err + hosts := r.filterHosts(HostCapabilityPull) + if len(hosts) == 0 { + return nil, errors.Wrap(errdefs.ErrNotFound, "no pull hosts") } - ctx, err = contextWithRepositoryScope(ctx, r.refspec, false) + ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false) if err != nil { return nil, err } return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) { - for _, u := range urls { - rc, err := r.open(ctx, u, desc.MediaType, offset) + // firstly try fetch via external urls + for _, us := range desc.URLs { + ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", us)) + + u, err := url.Parse(us) + if err != nil { + log.G(ctx).WithError(err).Debug("failed to parse") + continue + } + if u.Scheme != "http" && u.Scheme != "https" { + log.G(ctx).Debug("non-http(s) alternative url is unsupported") + continue + } + log.G(ctx).Debug("trying alternative url") + + // Try this first, parse it + host := RegistryHost{ + Client: http.DefaultClient, + Host: u.Host, + Scheme: u.Scheme, + Path: u.Path, + Capabilities: HostCapabilityPull, + } + req := r.request(host, http.MethodGet) + // Strip namespace from base + req.path = u.Path + if u.RawQuery != "" { + req.path = req.path + "?" + u.RawQuery + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) if err != nil { if errdefs.IsNotFound(err) { continue // try one of the other urls. @@ -69,32 +93,84 @@ return rc, nil } - return nil, errors.Wrapf(errdefs.ErrNotFound, - "could not fetch content descriptor %v (%v) from remote", - desc.Digest, desc.MediaType) + // Try manifests endpoints for manifests types + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, + images.MediaTypeDockerSchema1Manifest, + ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: + + var firstErr error + for _, host := range r.hosts { + req := r.request(host, http.MethodGet, "manifests", desc.Digest.String()) + if err := req.addNamespace(r.refspec.Hostname()); err != nil { + return nil, err + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) + if err != nil { + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + continue // try another host + } + + return rc, nil + } + + return nil, firstErr + } + + // Finally use blobs endpoints + var firstErr error + for _, host := range r.hosts { + req := r.request(host, http.MethodGet, "blobs", desc.Digest.String()) + if err := req.addNamespace(r.refspec.Hostname()); err != nil { + return nil, err + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) + if err != nil { + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + continue // try another host + } + + return rc, nil + } + + if errdefs.IsNotFound(firstErr) { + firstErr = errors.Wrapf(errdefs.ErrNotFound, + "could not fetch content descriptor %v (%v) from remote", + desc.Digest, desc.MediaType) + } + + return nil, firstErr }) } -func (r dockerFetcher) open(ctx context.Context, u, mediatype string, offset int64) (io.ReadCloser, error) { - req, err := http.NewRequest(http.MethodGet, u, nil) - if err != nil { - return nil, err - } - - req.Header.Set("Accept", strings.Join([]string{mediatype, `*`}, ", ")) +func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) { + req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", ")) if offset > 0 { // Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints // will return the header without supporting the range. The content // range must always be checked. - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) + req.header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) } - resp, err := r.doRequestWithRetries(ctx, req, nil) + resp, err := req.doWithRetries(ctx, nil) if err != nil { return nil, err } + defer func() { + if retErr != nil { + resp.Body.Close() + } + }() if resp.StatusCode > 299 { // TODO(stevvooe): When doing a offset specific request, we should @@ -102,11 +178,14 @@ // can discard the bytes, hiding the seek behavior from the // implementation. - resp.Body.Close() if resp.StatusCode == http.StatusNotFound { - return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", u) + return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String()) + } + var registryErr Errors + if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 { + return nil, errors.Errorf("unexpected status code %v: %v", req.String(), resp.Status) } - return nil, errors.Errorf("unexpected status code %v: %v", u, resp.Status) + return nil, errors.Errorf("unexpected status code %v: %s - Server message: %s", req.String(), resp.Status, registryErr.Error()) } if offset > 0 { cr := resp.Header.Get("content-range") @@ -135,30 +214,3 @@ return resp.Body, nil } - -// getV2URLPaths generates the candidate urls paths for the object based on the -// set of hints and the provided object id. URLs are returned in the order of -// most to least likely succeed. -func (r *dockerFetcher) getV2URLPaths(ctx context.Context, desc ocispec.Descriptor) ([]string, error) { - var urls []string - - if len(desc.URLs) > 0 { - // handle fetch via external urls. - for _, u := range desc.URLs { - log.G(ctx).WithField("url", u).Debug("adding alternative url") - urls = append(urls, u) - } - } - - switch desc.MediaType { - case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, - images.MediaTypeDockerSchema1Manifest, - ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: - urls = append(urls, r.url(path.Join("manifests", desc.Digest.String()))) - } - - // always fallback to attempting to get the object out of the blobs store. - urls = append(urls, r.url(path.Join("blobs", desc.Digest.String()))) - - return urls, nil -} diff -Nru containerd-1.2.6/remotes/docker/fetcher_test.go containerd-1.5.9/remotes/docker/fetcher_test.go --- containerd-1.2.6/remotes/docker/fetcher_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/fetcher_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,12 +18,18 @@ import ( "context" + "encoding/json" "fmt" + "io" "io/ioutil" "math/rand" "net/http" "net/http/httptest" + "net/url" "testing" + + "github.com/pkg/errors" + "gotest.tools/v3/assert" ) func TestFetcherOpen(t *testing.T) { @@ -40,14 +46,30 @@ })) defer s.Close() + u, err := url.Parse(s.URL) + if err != nil { + t.Fatal(err) + } + f := dockerFetcher{&dockerBase{ - client: s.Client(), + repository: "nonempty", }} + + host := RegistryHost{ + Client: s.Client(), + Host: u.Host, + Scheme: u.Scheme, + Path: u.Path, + } + ctx := context.Background() + req := f.request(host, http.MethodGet) + checkReader := func(o int64) { t.Helper() - rc, err := f.open(ctx, s.URL, "", o) + + rc, err := f.open(ctx, req, "", o) if err != nil { t.Fatalf("failed to open: %+v", err) } @@ -87,8 +109,106 @@ // Check that server returning a different content range // then requested errors start = 30 - _, err := f.open(ctx, s.URL, "", 20) + _, err = f.open(ctx, req, "", 20) if err == nil { t.Fatal("expected error opening with invalid server response") } } + +// New set of tests to test new error cases +func TestDockerFetcherOpen(t *testing.T) { + tests := []struct { + name string + mockedStatus int + mockedErr error + want io.ReadCloser + wantErr bool + wantServerMessageError bool + wantPlainError bool + retries int + }{ + { + name: "should return status and error.message if it exists if the registry request fails", + mockedStatus: 500, + mockedErr: Errors{Error{ + Code: ErrorCodeUnknown, + Message: "Test Error", + }}, + want: nil, + wantErr: true, + wantServerMessageError: true, + }, + { + name: "should return just status if the registry request fails and does not return a docker error", + mockedStatus: 500, + mockedErr: fmt.Errorf("Non-docker error"), + want: nil, + wantErr: true, + wantPlainError: true, + }, { + name: "should return StatusRequestTimeout after 5 retries", + mockedStatus: http.StatusRequestTimeout, + mockedErr: fmt.Errorf(http.StatusText(http.StatusRequestTimeout)), + want: nil, + wantErr: true, + wantPlainError: true, + retries: 5, + }, { + name: "should return StatusTooManyRequests after 5 retries", + mockedStatus: http.StatusTooManyRequests, + mockedErr: fmt.Errorf(http.StatusText(http.StatusTooManyRequests)), + want: nil, + wantErr: true, + wantPlainError: true, + retries: 5, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + if tt.retries > 0 { + tt.retries-- + } + rw.WriteHeader(tt.mockedStatus) + bytes, _ := json.Marshal(tt.mockedErr) + rw.Write(bytes) + })) + defer s.Close() + + u, err := url.Parse(s.URL) + if err != nil { + t.Fatal(err) + } + + f := dockerFetcher{&dockerBase{ + repository: "ns", + }} + + host := RegistryHost{ + Client: s.Client(), + Host: u.Host, + Scheme: u.Scheme, + Path: u.Path, + } + + req := f.request(host, http.MethodGet) + + got, err := f.open(context.TODO(), req, "", 0) + assert.Equal(t, tt.wantErr, (err != nil)) + assert.Equal(t, tt.want, got) + assert.Equal(t, tt.retries, 0) + if tt.wantErr { + var expectedError error + if tt.wantServerMessageError { + expectedError = errors.Errorf("unexpected status code %v/ns: %v %s - Server message: %s", s.URL, tt.mockedStatus, http.StatusText(tt.mockedStatus), tt.mockedErr.Error()) + } else if tt.wantPlainError { + expectedError = errors.Errorf("unexpected status code %v/ns: %v %s", s.URL, tt.mockedStatus, http.StatusText(tt.mockedStatus)) + } + assert.Equal(t, expectedError.Error(), err.Error()) + + } + + }) + } +} diff -Nru containerd-1.2.6/remotes/docker/handler.go containerd-1.5.9/remotes/docker/handler.go --- containerd-1.2.6/remotes/docker/handler.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/handler.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,154 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "context" + "fmt" + "net/url" + "strings" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/reference" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +var ( + // labelDistributionSource describes the source blob comes from. + labelDistributionSource = "containerd.io/distribution.source" +) + +// AppendDistributionSourceLabel updates the label of blob with distribution source. +func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) { + refspec, err := reference.Parse(ref) + if err != nil { + return nil, err + } + + u, err := url.Parse("dummy://" + refspec.Locator) + if err != nil { + return nil, err + } + + source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/") + return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + info, err := manager.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + + key := distributionSourceLabelKey(source) + + originLabel := "" + if info.Labels != nil { + originLabel = info.Labels[key] + } + value := appendDistributionSourceLabel(originLabel, repo) + + // The repo name has been limited under 256 and the distribution + // label might hit the limitation of label size, when blob data + // is used as the very, very common layer. + if err := labels.Validate(key, value); err != nil { + log.G(ctx).Warnf("skip to append distribution label: %s", err) + return nil, nil + } + + info = content.Info{ + Digest: desc.Digest, + Labels: map[string]string{ + key: value, + }, + } + _, err = manager.Update(ctx, info, fmt.Sprintf("labels.%s", key)) + return nil, err + }, nil +} + +func appendDistributionSourceLabel(originLabel, repo string) string { + repos := []string{} + if originLabel != "" { + repos = strings.Split(originLabel, ",") + } + repos = append(repos, repo) + + // use empty string to present duplicate items + for i := 1; i < len(repos); i++ { + tmp, j := repos[i], i-1 + for ; j >= 0 && repos[j] >= tmp; j-- { + if repos[j] == tmp { + tmp = "" + } + repos[j+1] = repos[j] + } + repos[j+1] = tmp + } + + i := 0 + for ; i < len(repos) && repos[i] == ""; i++ { + } + + return strings.Join(repos[i:], ",") +} + +func distributionSourceLabelKey(source string) string { + return fmt.Sprintf("%s.%s", labelDistributionSource, source) +} + +// selectRepositoryMountCandidate will select the repo which has longest +// common prefix components as the candidate. +func selectRepositoryMountCandidate(refspec reference.Spec, sources map[string]string) string { + u, err := url.Parse("dummy://" + refspec.Locator) + if err != nil { + // NOTE: basically, it won't be error here + return "" + } + + source, target := u.Hostname(), strings.TrimPrefix(u.Path, "/") + repoLabel, ok := sources[distributionSourceLabelKey(source)] + if !ok || repoLabel == "" { + return "" + } + + n, match := 0, "" + components := strings.Split(target, "/") + for _, repo := range strings.Split(repoLabel, ",") { + // the target repo is not a candidate + if repo == target { + continue + } + + if l := commonPrefixComponents(components, repo); l >= n { + n, match = l, repo + } + } + return match +} + +func commonPrefixComponents(components []string, target string) int { + targetComponents := strings.Split(target, "/") + + i := 0 + for ; i < len(components) && i < len(targetComponents); i++ { + if components[i] != targetComponents[i] { + break + } + } + return i +} diff -Nru containerd-1.2.6/remotes/docker/handler_test.go containerd-1.5.9/remotes/docker/handler_test.go --- containerd-1.2.6/remotes/docker/handler_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/handler_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,132 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "reflect" + "testing" + + "github.com/containerd/containerd/reference" +) + +func TestAppendDistributionLabel(t *testing.T) { + for _, tc := range []struct { + originLabel string + repo string + expected string + }{ + { + originLabel: "", + repo: "", + expected: "", + }, + { + originLabel: "", + repo: "library/busybox", + expected: "library/busybox", + }, + { + originLabel: "library/busybox", + repo: "library/busybox", + expected: "library/busybox", + }, + // remove the duplicate one in origin + { + originLabel: "library/busybox,library/redis,library/busybox", + repo: "library/alpine", + expected: "library/alpine,library/busybox,library/redis", + }, + // remove the empty repo + { + originLabel: "library/busybox,library/redis,library/busybox", + repo: "", + expected: "library/busybox,library/redis", + }, + { + originLabel: "library/busybox,library/redis,library/busybox", + repo: "library/redis", + expected: "library/busybox,library/redis", + }, + } { + if got := appendDistributionSourceLabel(tc.originLabel, tc.repo); !reflect.DeepEqual(got, tc.expected) { + t.Fatalf("expected %v, but got %v", tc.expected, got) + } + } +} + +func TestDistributionSourceLabelKey(t *testing.T) { + expected := "containerd.io/distribution.source.testsource" + if got := distributionSourceLabelKey("testsource"); !reflect.DeepEqual(got, expected) { + t.Fatalf("expected %v, but got %v", expected, got) + } +} + +func TestCommonPrefixComponents(t *testing.T) { + for _, tc := range []struct { + components []string + target string + expected int + }{ + { + components: []string{"foo"}, + target: "foo/bar", + expected: 1, + }, + { + components: []string{"bar"}, + target: "foo/bar", + expected: 0, + }, + { + components: []string{"foo", "bar"}, + target: "foo/bar", + expected: 2, + }, + } { + if got := commonPrefixComponents(tc.components, tc.target); !reflect.DeepEqual(got, tc.expected) { + t.Fatalf("expected %v, but got %v", tc.expected, got) + } + } +} + +func TestSelectRepositoryMountCandidate(t *testing.T) { + for _, tc := range []struct { + refspec reference.Spec + source map[string]string + expected string + }{ + { + refspec: reference.Spec{}, + source: map[string]string{"": ""}, + expected: "", + }, + { + refspec: reference.Spec{Locator: "user@host/path"}, + source: map[string]string{"containerd.io/distribution.source.host": "foo,path,bar"}, + expected: "bar", + }, + { + refspec: reference.Spec{Locator: "user@host/path"}, + source: map[string]string{"containerd.io/distribution.source.host": "foo,bar,path"}, + expected: "bar", + }, + } { + if got := selectRepositoryMountCandidate(tc.refspec, tc.source); !reflect.DeepEqual(got, tc.expected) { + t.Fatalf("expected %v, but got %v", tc.expected, got) + } + } +} diff -Nru containerd-1.2.6/remotes/docker/httpreadseeker.go containerd-1.5.9/remotes/docker/httpreadseeker.go --- containerd-1.2.6/remotes/docker/httpreadseeker.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/httpreadseeker.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,12 +26,16 @@ "github.com/pkg/errors" ) +const maxRetry = 3 + type httpReadSeeker struct { size int64 offset int64 rc io.ReadCloser open func(offset int64) (io.ReadCloser, error) closed bool + + errsWithNoProgress int } func newHTTPReadSeeker(size int64, open func(offset int64) (io.ReadCloser, error)) (io.ReadCloser, error) { @@ -53,6 +57,27 @@ n, err = rd.Read(p) hrs.offset += int64(n) + if n > 0 || err == nil { + hrs.errsWithNoProgress = 0 + } + if err == io.ErrUnexpectedEOF { + // connection closed unexpectedly. try reconnecting. + if n == 0 { + hrs.errsWithNoProgress++ + if hrs.errsWithNoProgress > maxRetry { + return // too many retries for this offset with no progress + } + } + if hrs.rc != nil { + if clsErr := hrs.rc.Close(); clsErr != nil { + log.L.WithError(clsErr).Errorf("httpReadSeeker: failed to close ReadCloser") + } + hrs.rc = nil + } + if _, err2 := hrs.reader(); err2 == nil { + return n, nil + } + } return } @@ -121,7 +146,7 @@ rc, err := hrs.open(hrs.offset) if err != nil { - return nil, errors.Wrapf(err, "httpReaderSeeker: failed open") + return nil, errors.Wrapf(err, "httpReadSeeker: failed open") } if hrs.rc != nil { diff -Nru containerd-1.2.6/remotes/docker/pusher.go containerd-1.5.9/remotes/docker/pusher.go --- containerd-1.2.6/remotes/docker/pusher.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/pusher.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,7 +21,7 @@ "io" "io/ioutil" "net/http" - "path" + "net/url" "strings" "time" @@ -30,6 +30,7 @@ "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/remotes" + remoteserrors "github.com/containerd/containerd/remotes/errors" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -37,62 +38,93 @@ type dockerPusher struct { *dockerBase - tag string + object string // TODO: namespace tracker tracker StatusTracker } +// Writer implements Ingester API of content store. This allows the client +// to receive ErrUnavailable when there is already an on-going upload. +// Note that the tracker MUST implement StatusTrackLocker interface to avoid +// race condition on StatusTracker. +func (p dockerPusher) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) { + var wOpts content.WriterOpts + for _, opt := range opts { + if err := opt(&wOpts); err != nil { + return nil, err + } + } + if wOpts.Ref == "" { + return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty") + } + return p.push(ctx, wOpts.Desc, wOpts.Ref, true) +} + func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) { - ctx, err := contextWithRepositoryScope(ctx, p.refspec, true) + return p.push(ctx, desc, remotes.MakeRefKey(ctx, desc), false) +} + +func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref string, unavailableOnFail bool) (content.Writer, error) { + if l, ok := p.tracker.(StatusTrackLocker); ok { + l.Lock(ref) + defer l.Unlock(ref) + } + ctx, err := ContextWithRepositoryScope(ctx, p.refspec, true) if err != nil { return nil, err } - ref := remotes.MakeRefKey(ctx, desc) status, err := p.tracker.GetStatus(ref) if err == nil { - if status.Offset == status.Total { + if status.Committed && status.Offset == status.Total { return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "ref %v", ref) } + if unavailableOnFail { + // Another push of this ref is happening elsewhere. The rest of function + // will continue only when `errdefs.IsNotFound(err) == true` (i.e. there + // is no actively-tracked ref already). + return nil, errors.Wrap(errdefs.ErrUnavailable, "push is on-going") + } // TODO: Handle incomplete status } else if !errdefs.IsNotFound(err) { return nil, errors.Wrap(err, "failed to get status") } + hosts := p.filterHosts(HostCapabilityPush) + if len(hosts) == 0 { + return nil, errors.Wrap(errdefs.ErrNotFound, "no push hosts") + } + var ( isManifest bool - existCheck string + existCheck []string + host = hosts[0] ) switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: isManifest = true - if p.tag == "" { - existCheck = path.Join("manifests", desc.Digest.String()) - } else { - existCheck = path.Join("manifests", p.tag) - } + existCheck = getManifestPath(p.object, desc.Digest) default: - existCheck = path.Join("blobs", desc.Digest.String()) + existCheck = []string{"blobs", desc.Digest.String()} } - req, err := http.NewRequest(http.MethodHead, p.url(existCheck), nil) - if err != nil { - return nil, err - } + req := p.request(host, http.MethodHead, existCheck...) + req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", ")) + + log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to") - req.Header.Set("Accept", strings.Join([]string{desc.MediaType, `*`}, ", ")) - resp, err := p.doRequestWithRetries(ctx, req, nil) + resp, err := req.doWithRetries(ctx, nil) if err != nil { - if errors.Cause(err) != ErrInvalidAuthorization { + if !errors.Is(err, ErrInvalidAuthorization) { return nil, err } log.G(ctx).WithError(err).Debugf("Unable to check existence, continuing with push") } else { if resp.StatusCode == http.StatusOK { var exists bool - if isManifest && p.tag != "" { + if isManifest && existCheck[1] != desc.Digest.String() { dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) if dgstHeader == desc.Digest { exists = true @@ -103,80 +135,120 @@ if exists { p.tracker.SetStatus(ref, Status{ + Committed: true, Status: content.Status{ - Ref: ref, + Ref: ref, + Total: desc.Size, + Offset: desc.Size, // TODO: Set updated time? }, }) + resp.Body.Close() return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) } } else if resp.StatusCode != http.StatusNotFound { - // TODO: log error - return nil, errors.Errorf("unexpected response: %s", resp.Status) + err := remoteserrors.NewUnexpectedStatusErr(resp) + log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + resp.Body.Close() + return nil, err } + resp.Body.Close() } - // TODO: Lookup related objects for cross repository push - if isManifest { - var putPath string - if p.tag != "" { - putPath = path.Join("manifests", p.tag) - } else { - putPath = path.Join("manifests", desc.Digest.String()) - } - - req, err = http.NewRequest(http.MethodPut, p.url(putPath), nil) - if err != nil { - return nil, err - } - req.Header.Add("Content-Type", desc.MediaType) + putPath := getManifestPath(p.object, desc.Digest) + req = p.request(host, http.MethodPut, putPath...) + req.header.Add("Content-Type", desc.MediaType) } else { - // TODO: Do monolithic upload if size is small - // Start upload request - req, err = http.NewRequest(http.MethodPost, p.url("blobs", "uploads")+"/", nil) - if err != nil { - return nil, err + req = p.request(host, http.MethodPost, "blobs", "uploads/") + + var resp *http.Response + if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" { + preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo) + pctx := ContextWithAppendPullRepositoryScope(ctx, fromRepo) + + // NOTE: the fromRepo might be private repo and + // auth service still can grant token without error. + // but the post request will fail because of 401. + // + // for the private repo, we should remove mount-from + // query and send the request again. + resp, err = preq.doWithRetries(pctx, nil) + if err != nil { + return nil, err + } + + if resp.StatusCode == http.StatusUnauthorized { + log.G(ctx).Debugf("failed to mount from repository %s", fromRepo) + + resp.Body.Close() + resp = nil + } } - resp, err := p.doRequestWithRetries(ctx, req, nil) - if err != nil { - return nil, err + if resp == nil { + resp, err = req.doWithRetries(ctx, nil) + if err != nil { + return nil, err + } } + defer resp.Body.Close() switch resp.StatusCode { case http.StatusOK, http.StatusAccepted, http.StatusNoContent: + case http.StatusCreated: + p.tracker.SetStatus(ref, Status{ + Committed: true, + Status: content.Status{ + Ref: ref, + Total: desc.Size, + Offset: desc.Size, + }, + }) + return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) default: - // TODO: log error - return nil, errors.Errorf("unexpected response: %s", resp.Status) + err := remoteserrors.NewUnexpectedStatusErr(resp) + log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + return nil, err } - location := resp.Header.Get("Location") + var ( + location = resp.Header.Get("Location") + lurl *url.URL + lhost = host + ) // Support paths without host in location if strings.HasPrefix(location, "/") { - // Support location string containing path and query - qmIndex := strings.Index(location, "?") - if qmIndex > 0 { - u := p.base - u.Path = location[:qmIndex] - u.RawQuery = location[qmIndex+1:] - location = u.String() - } else { - u := p.base - u.Path = location - location = u.String() + lurl, err = url.Parse(lhost.Scheme + "://" + lhost.Host + location) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse location %v", location) + } + } else { + if !strings.Contains(location, "://") { + location = lhost.Scheme + "://" + location + } + lurl, err = url.Parse(location) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse location %v", location) } - } - req, err = http.NewRequest(http.MethodPut, location, nil) - if err != nil { - return nil, err + if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme { + + lhost.Scheme = lurl.Scheme + lhost.Host = lurl.Host + log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination") + + // Strip authorizer if change to host or scheme + lhost.Authorizer = nil + } } - q := req.URL.Query() + q := lurl.Query() q.Add("digest", desc.Digest.String()) - req.URL.RawQuery = q.Encode() + req = p.request(lhost, http.MethodPut) + req.header.Set("Content-Type", "application/octet-stream") + req.path = lurl.Path + "?" + q.Encode() } p.tracker.SetStatus(ref, Status{ Status: content.Status{ @@ -190,15 +262,25 @@ // TODO: Support chunked upload pr, pw := io.Pipe() - respC := make(chan *http.Response, 1) + respC := make(chan response, 1) + body := ioutil.NopCloser(pr) - req.Body = ioutil.NopCloser(pr) - req.ContentLength = desc.Size + req.body = func() (io.ReadCloser, error) { + if body == nil { + return nil, errors.New("cannot reuse body, request must be retried") + } + // Only use the body once since pipe cannot be seeked + ob := body + body = nil + return ob, nil + } + req.size = desc.Size go func() { defer close(respC) - resp, err = p.doRequest(ctx, req) + resp, err := req.doWithRetries(ctx, nil) if err != nil { + respC <- response{err: err} pr.CloseWithError(err) return } @@ -206,10 +288,11 @@ switch resp.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent: default: - // TODO: log error - pr.CloseWithError(errors.Errorf("unexpected response: %s", resp.Status)) + err := remoteserrors.NewUnexpectedStatusErr(resp) + log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") + pr.CloseWithError(err) } - respC <- resp + respC <- response{Response: resp} }() return &pushWriter{ @@ -223,12 +306,36 @@ }, nil } +func getManifestPath(object string, dgst digest.Digest) []string { + if i := strings.IndexByte(object, '@'); i >= 0 { + if object[i+1:] != dgst.String() { + // use digest, not tag + object = "" + } else { + // strip @ for registry path to make tag + object = object[:i] + } + + } + + if object == "" { + return []string{"manifests", dgst.String()} + } + + return []string{"manifests", object} +} + +type response struct { + *http.Response + err error +} + type pushWriter struct { base *dockerBase ref string pipe *io.PipeWriter - responseC <-chan *http.Response + responseC <-chan response isManifest bool expected digest.Digest @@ -274,20 +381,19 @@ if err := pw.pipe.Close(); err != nil { return err } - // TODO: Update status to determine committing - // TODO: timeout waiting for response resp := <-pw.responseC - if resp == nil { - return errors.New("no response") + if resp.err != nil { + return resp.err } + defer resp.Response.Body.Close() // 201 is specified return status, some registries return - // 200 or 204. + // 200, 202 or 204. switch resp.StatusCode { - case http.StatusOK, http.StatusCreated, http.StatusNoContent: + case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: default: - return errors.Errorf("unexpected status: %s", resp.Status) + return remoteserrors.NewUnexpectedStatusErr(resp.Response) } status, err := pw.tracker.GetStatus(pw.ref) @@ -296,7 +402,7 @@ } if size > 0 && size != status.Offset { - return errors.Errorf("unxpected size %d, expected %d", status.Offset, size) + return errors.Errorf("unexpected size %d, expected %d", status.Offset, size) } if expected == "" { @@ -312,6 +418,10 @@ return errors.Errorf("got digest %s, expected %s", actual, expected) } + status.Committed = true + status.UpdatedAt = time.Now() + pw.tracker.SetStatus(pw.ref, status) + return nil } @@ -320,3 +430,16 @@ // TODO: always error on manifest return errors.New("cannot truncate remote upload") } + +func requestWithMountFrom(req *request, mount, from string) *request { + creq := *req + + sep := "?" + if strings.Contains(creq.path, sep) { + sep = "&" + } + + creq.path = creq.path + sep + "mount=" + mount + "&from=" + from + + return &creq +} diff -Nru containerd-1.2.6/remotes/docker/pusher_test.go containerd-1.5.9/remotes/docker/pusher_test.go --- containerd-1.2.6/remotes/docker/pusher_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/pusher_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "reflect" + "testing" + + digest "github.com/opencontainers/go-digest" +) + +func TestGetManifestPath(t *testing.T) { + for _, tc := range []struct { + object string + dgst digest.Digest + expected []string + }{ + { + object: "foo", + dgst: "bar", + expected: []string{"manifests", "foo"}, + }, + { + object: "foo@bar", + dgst: "bar", + expected: []string{"manifests", "foo"}, + }, + { + object: "foo@bar", + dgst: "foobar", + expected: []string{"manifests", "foobar"}, + }, + } { + if got := getManifestPath(tc.object, tc.dgst); !reflect.DeepEqual(got, tc.expected) { + t.Fatalf("expected %v, but got %v", tc.expected, got) + } + } +} diff -Nru containerd-1.2.6/remotes/docker/registry.go containerd-1.5.9/remotes/docker/registry.go --- containerd-1.2.6/remotes/docker/registry.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/registry.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,245 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import ( + "net" + "net/http" + + "github.com/pkg/errors" +) + +// HostCapabilities represent the capabilities of the registry +// host. This also represents the set of operations for which +// the registry host may be trusted to perform. +// +// For example pushing is a capability which should only be +// performed on an upstream source, not a mirror. +// Resolving (the process of converting a name into a digest) +// must be considered a trusted operation and only done by +// a host which is trusted (or more preferably by secure process +// which can prove the provenance of the mapping). A public +// mirror should never be trusted to do a resolve action. +// +// | Registry Type | Pull | Resolve | Push | +// |------------------|------|---------|------| +// | Public Registry | yes | yes | yes | +// | Private Registry | yes | yes | yes | +// | Public Mirror | yes | no | no | +// | Private Mirror | yes | yes | no | +type HostCapabilities uint8 + +const ( + // HostCapabilityPull represents the capability to fetch manifests + // and blobs by digest + HostCapabilityPull HostCapabilities = 1 << iota + + // HostCapabilityResolve represents the capability to fetch manifests + // by name + HostCapabilityResolve + + // HostCapabilityPush represents the capability to push blobs and + // manifests + HostCapabilityPush + + // Reserved for future capabilities (i.e. search, catalog, remove) +) + +// Has checks whether the capabilities list has the provide capability +func (c HostCapabilities) Has(t HostCapabilities) bool { + return c&t == t +} + +// RegistryHost represents a complete configuration for a registry +// host, representing the capabilities, authorizations, connection +// configuration, and location. +type RegistryHost struct { + Client *http.Client + Authorizer Authorizer + Host string + Scheme string + Path string + Capabilities HostCapabilities + Header http.Header +} + +func (h RegistryHost) isProxy(refhost string) bool { + if refhost != h.Host { + if refhost != "docker.io" || h.Host != "registry-1.docker.io" { + return true + } + } + return false +} + +// RegistryHosts fetches the registry hosts for a given namespace, +// provided by the host component of an distribution image reference. +type RegistryHosts func(string) ([]RegistryHost, error) + +// Registries joins multiple registry configuration functions, using the same +// order as provided within the arguments. When an empty registry configuration +// is returned with a nil error, the next function will be called. +// NOTE: This function will not join configurations, as soon as a non-empty +// configuration is returned from a configuration function, it will be returned +// to the caller. +func Registries(registries ...RegistryHosts) RegistryHosts { + return func(host string) ([]RegistryHost, error) { + for _, registry := range registries { + config, err := registry(host) + if err != nil { + return config, err + } + if len(config) > 0 { + return config, nil + } + } + return nil, nil + } +} + +type registryOpts struct { + authorizer Authorizer + plainHTTP func(string) (bool, error) + host func(string) (string, error) + client *http.Client +} + +// RegistryOpt defines a registry default option +type RegistryOpt func(*registryOpts) + +// WithPlainHTTP configures registries to use plaintext http scheme +// for the provided host match function. +func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { + return func(opts *registryOpts) { + opts.plainHTTP = f + } +} + +// WithAuthorizer configures the default authorizer for a registry +func WithAuthorizer(a Authorizer) RegistryOpt { + return func(opts *registryOpts) { + opts.authorizer = a + } +} + +// WithHostTranslator defines the default translator to use for registry hosts +func WithHostTranslator(h func(string) (string, error)) RegistryOpt { + return func(opts *registryOpts) { + opts.host = h + } +} + +// WithClient configures the default http client for a registry +func WithClient(c *http.Client) RegistryOpt { + return func(opts *registryOpts) { + opts.client = c + } +} + +// ConfigureDefaultRegistries is used to create a default configuration for +// registries. For more advanced configurations or per-domain setups, +// the RegistryHosts interface should be used directly. +// NOTE: This function will always return a non-empty value or error +func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { + var opts registryOpts + for _, opt := range ropts { + opt(&opts) + } + + return func(host string) ([]RegistryHost, error) { + config := RegistryHost{ + Client: opts.client, + Authorizer: opts.authorizer, + Host: host, + Scheme: "https", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, + } + + if config.Client == nil { + config.Client = http.DefaultClient + } + + if opts.plainHTTP != nil { + match, err := opts.plainHTTP(host) + if err != nil { + return nil, err + } + if match { + config.Scheme = "http" + } + } + + if opts.host != nil { + var err error + config.Host, err = opts.host(config.Host) + if err != nil { + return nil, err + } + } else if host == "docker.io" { + config.Host = "registry-1.docker.io" + } + + return []RegistryHost{config}, nil + } +} + +// MatchAllHosts is a host match function which is always true. +func MatchAllHosts(string) (bool, error) { + return true, nil +} + +// MatchLocalhost is a host match function which returns true for +// localhost. +// +// Note: this does not handle matching of ip addresses in octal, +// decimal or hex form. +func MatchLocalhost(host string) (bool, error) { + switch { + case host == "::1": + return true, nil + case host == "[::1]": + return true, nil + } + h, p, err := net.SplitHostPort(host) + + // addrError helps distinguish between errors of form + // "no colon in address" and "too many colons in address". + // The former is fine as the host string need not have a + // port. Latter needs to be handled. + addrError := &net.AddrError{ + Err: "missing port in address", + Addr: host, + } + if err != nil { + if err.Error() != addrError.Error() { + return false, err + } + // host string without any port specified + h = host + } else if len(p) == 0 { + return false, errors.New("invalid host name format") + } + + // use ipv4 dotted decimal for further checking + if h == "localhost" { + h = "127.0.0.1" + } + ip := net.ParseIP(h) + + return ip.IsLoopback(), nil +} diff -Nru containerd-1.2.6/remotes/docker/registry_test.go containerd-1.5.9/remotes/docker/registry_test.go --- containerd-1.2.6/remotes/docker/registry_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/docker/registry_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package docker + +import "testing" + +func TestHasCapability(t *testing.T) { + var ( + pull = HostCapabilityPull + rslv = HostCapabilityResolve + push = HostCapabilityPush + all = pull | rslv | push + ) + for i, tc := range []struct { + c HostCapabilities + t HostCapabilities + e bool + }{ + {all, pull, true}, + {all, pull | rslv, true}, + {all, pull | push, true}, + {all, all, true}, + {pull, all, false}, + {pull, push, false}, + {rslv, pull, false}, + {pull | rslv, push, false}, + {pull | rslv, rslv, true}, + } { + if a := tc.c.Has(tc.t); a != tc.e { + t.Fatalf("%d: failed, expected %t, got %t", i, tc.e, a) + } + } +} + +func TestMatchLocalhost(t *testing.T) { + for _, tc := range []struct { + host string + match bool + }{ + {"", false}, + {"127.1.1.1", true}, + {"127.0.0.1", true}, + {"127.256.0.1", false}, // test MatchLocalhost does not panic on invalid ip + {"127.23.34.52", true}, + {"127.0.0.1:5000", true}, + {"registry.org", false}, + {"126.example.com", false}, + {"localhost", true}, + {"localhost:5000", true}, + {"[127:0:0:1]", false}, + {"[::1]", true}, + {"[::1]:", false}, // invalid ip + {"127.0.1.1:", false}, // invalid ip + {"[::1]:5000", true}, + {"::1", true}, + } { + actual, _ := MatchLocalhost(tc.host) + if actual != tc.match { + if tc.match { + t.Logf("Expected match for %s", tc.host) + } else { + t.Logf("Unexpected match for %s", tc.host) + } + t.Fail() + } + } +} diff -Nru containerd-1.2.6/remotes/docker/resolver.go containerd-1.5.9/remotes/docker/resolver.go --- containerd-1.2.6/remotes/docker/resolver.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/resolver.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,10 +18,12 @@ import ( "context" + "fmt" + "io" + "io/ioutil" "net/http" "net/url" "path" - "strconv" "strings" "github.com/containerd/containerd/errdefs" @@ -29,6 +31,8 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/remotes/docker/schema1" + "github.com/containerd/containerd/version" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -37,13 +41,22 @@ ) var ( - // ErrNoToken is returned if a request is successful but the body does not - // contain an authorization token. - ErrNoToken = errors.New("authorization server did not include a token in the response") - // ErrInvalidAuthorization is used when credentials are passed to a server but // those credentials are rejected. ErrInvalidAuthorization = errors.New("authorization failed") + + // MaxManifestSize represents the largest size accepted from a registry + // during resolution. Larger manifests may be accepted using a + // resolution method other than the registry. + // + // NOTE: The max supported layers by some runtimes is 128 and individual + // layers will not contribute more than 256 bytes, making a + // reasonable limit for a large image manifests of 32K bytes. + // 4M bytes represents a much larger upper bound for images which may + // contain large annotations or be non-images. A proper manifest + // design puts large metadata in subobjects, as is consistent the + // intent of the manifest design. + MaxManifestSize int64 = 4 * 1048 * 1048 ) // Authorizer is used to authorize HTTP requests based on 401 HTTP responses. @@ -70,28 +83,38 @@ // ResolverOptions are used to configured a new Docker register resolver type ResolverOptions struct { + // Hosts returns registry host configurations for a namespace. + Hosts RegistryHosts + + // Headers are the HTTP request header fields sent by the resolver + Headers http.Header + + // Tracker is used to track uploads to the registry. This is used + // since the registry does not have upload tracking and the existing + // mechanism for getting blob upload status is expensive. + Tracker StatusTracker + // Authorizer is used to authorize registry requests + // Deprecated: use Hosts Authorizer Authorizer // Credentials provides username and secret given a host. // If username is empty but a secret is given, that secret - // is interpretted as a long lived token. - // Deprecated: use Authorizer + // is interpreted as a long lived token. + // Deprecated: use Hosts Credentials func(string) (string, string, error) // Host provides the hostname given a namespace. + // Deprecated: use Hosts Host func(string) (string, error) // PlainHTTP specifies to use plain http and not https + // Deprecated: use Hosts PlainHTTP bool // Client is the http client to used when making registry requests + // Deprecated: use Hosts Client *http.Client - - // Tracker is used to track uploads to the registry. This is used - // since the registry does not have upload tracking and the existing - // mechanism for getting blob upload status is expensive. - Tracker StatusTracker } // DefaultHost is the default host function. @@ -103,11 +126,10 @@ } type dockerResolver struct { - auth Authorizer - host func(string) (string, error) - plainHTTP bool - client *http.Client - tracker StatusTracker + hosts RegistryHosts + header http.Header + resolveHeader http.Header + tracker StatusTracker } // NewResolver returns a new resolver to a Docker registry @@ -115,45 +137,102 @@ if options.Tracker == nil { options.Tracker = NewInMemoryTracker() } - if options.Host == nil { - options.Host = DefaultHost + + if options.Headers == nil { + options.Headers = make(http.Header) } - if options.Authorizer == nil { - options.Authorizer = NewAuthorizer(options.Client, options.Credentials) + if _, ok := options.Headers["User-Agent"]; !ok { + options.Headers.Set("User-Agent", "containerd/"+version.Version) + } + + resolveHeader := http.Header{} + if _, ok := options.Headers["Accept"]; !ok { + // set headers for all the types we support for resolution. + resolveHeader.Set("Accept", strings.Join([]string{ + images.MediaTypeDockerSchema2Manifest, + images.MediaTypeDockerSchema2ManifestList, + ocispec.MediaTypeImageManifest, + ocispec.MediaTypeImageIndex, "*/*"}, ", ")) + } else { + resolveHeader["Accept"] = options.Headers["Accept"] + delete(options.Headers, "Accept") + } + + if options.Hosts == nil { + opts := []RegistryOpt{} + if options.Host != nil { + opts = append(opts, WithHostTranslator(options.Host)) + } + + if options.Authorizer == nil { + options.Authorizer = NewDockerAuthorizer( + WithAuthClient(options.Client), + WithAuthHeader(options.Headers), + WithAuthCreds(options.Credentials)) + } + opts = append(opts, WithAuthorizer(options.Authorizer)) + + if options.Client != nil { + opts = append(opts, WithClient(options.Client)) + } + if options.PlainHTTP { + opts = append(opts, WithPlainHTTP(MatchAllHosts)) + } else { + opts = append(opts, WithPlainHTTP(MatchLocalhost)) + } + options.Hosts = ConfigureDefaultRegistries(opts...) } return &dockerResolver{ - auth: options.Authorizer, - host: options.Host, - plainHTTP: options.PlainHTTP, - client: options.Client, - tracker: options.Tracker, + hosts: options.Hosts, + header: options.Headers, + resolveHeader: resolveHeader, + tracker: options.Tracker, } } +func getManifestMediaType(resp *http.Response) string { + // Strip encoding data (manifests should always be ascii JSON) + contentType := resp.Header.Get("Content-Type") + if sp := strings.IndexByte(contentType, ';'); sp != -1 { + contentType = contentType[0:sp] + } + + // As of Apr 30 2019 the registry.access.redhat.com registry does not specify + // the content type of any data but uses schema1 manifests. + if contentType == "text/plain" { + contentType = images.MediaTypeDockerSchema1Manifest + } + return contentType +} + +type countingReader struct { + reader io.Reader + bytesRead int64 +} + +func (r *countingReader) Read(p []byte) (int, error) { + n, err := r.reader.Read(p) + r.bytesRead += int64(n) + return n, err +} + var _ remotes.Resolver = &dockerResolver{} func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocispec.Descriptor, error) { - refspec, err := reference.Parse(ref) + base, err := r.resolveDockerBase(ref) if err != nil { return "", ocispec.Descriptor{}, err } - + refspec := base.refspec if refspec.Object == "" { return "", ocispec.Descriptor{}, reference.ErrObjectRequired } - base, err := r.base(refspec) - if err != nil { - return "", ocispec.Descriptor{}, err - } - - fetcher := dockerFetcher{ - dockerBase: base, - } - var ( - urls []string - dgst = refspec.Digest() + firstErr error + paths [][]string + dgst = refspec.Digest() + caps = HostCapabilityPull ) if dgst != "" { @@ -164,98 +243,159 @@ } // turns out, we have a valid digest, make a url. - urls = append(urls, fetcher.url("manifests", dgst.String())) + paths = append(paths, []string{"manifests", dgst.String()}) // fallback to blobs on not found. - urls = append(urls, fetcher.url("blobs", dgst.String())) + paths = append(paths, []string{"blobs", dgst.String()}) } else { - urls = append(urls, fetcher.url("manifests", refspec.Object)) + // Add + paths = append(paths, []string{"manifests", refspec.Object}) + caps |= HostCapabilityResolve } - ctx, err = contextWithRepositoryScope(ctx, refspec, false) + hosts := base.filterHosts(caps) + if len(hosts) == 0 { + return "", ocispec.Descriptor{}, errors.Wrap(errdefs.ErrNotFound, "no resolve hosts") + } + + ctx, err = ContextWithRepositoryScope(ctx, refspec, false) if err != nil { return "", ocispec.Descriptor{}, err } - for _, u := range urls { - req, err := http.NewRequest(http.MethodHead, u, nil) - if err != nil { - return "", ocispec.Descriptor{}, err - } - - // set headers for all the types we support for resolution. - req.Header.Set("Accept", strings.Join([]string{ - images.MediaTypeDockerSchema2Manifest, - images.MediaTypeDockerSchema2ManifestList, - ocispec.MediaTypeImageManifest, - ocispec.MediaTypeImageIndex, "*"}, ", ")) - log.G(ctx).Debug("resolving") - resp, err := fetcher.doRequestWithRetries(ctx, req, nil) - if err != nil { - if errors.Cause(err) == ErrInvalidAuthorization { - err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") + for _, u := range paths { + for _, host := range hosts { + ctx := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host)) + + req := base.request(host, http.MethodHead, u...) + if err := req.addNamespace(base.refspec.Hostname()); err != nil { + return "", ocispec.Descriptor{}, err } - return "", ocispec.Descriptor{}, err - } - resp.Body.Close() // don't care about body contents. - if resp.StatusCode > 299 { - if resp.StatusCode == http.StatusNotFound { - continue + for key, value := range r.resolveHeader { + req.header[key] = append(req.header[key], value...) } - return "", ocispec.Descriptor{}, errors.Errorf("unexpected status code %v: %v", u, resp.Status) - } - // this is the only point at which we trust the registry. we use the - // content headers to assemble a descriptor for the name. when this becomes - // more robust, we mostly get this information from a secure trust store. - dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) + log.G(ctx).Debug("resolving") + resp, err := req.doWithRetries(ctx, nil) + if err != nil { + if errors.Is(err, ErrInvalidAuthorization) { + err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") + } + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + log.G(ctx).WithError(err).Info("trying next host") + continue // try another host + } + resp.Body.Close() // don't care about body contents. - if dgstHeader != "" { - if err := dgstHeader.Validate(); err != nil { - return "", ocispec.Descriptor{}, errors.Wrapf(err, "%q in header not a valid digest", dgstHeader) + if resp.StatusCode > 299 { + if resp.StatusCode == http.StatusNotFound { + log.G(ctx).Info("trying next host - response was http.StatusNotFound") + continue + } + if resp.StatusCode > 399 { + // Set firstErr when encountering the first non-404 status code. + if firstErr == nil { + firstErr = errors.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status) + } + continue // try another host + } + return "", ocispec.Descriptor{}, errors.Errorf("pulling from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status) } - dgst = dgstHeader - } + size := resp.ContentLength + contentType := getManifestMediaType(resp) - if dgst == "" { - return "", ocispec.Descriptor{}, errors.Errorf("could not resolve digest for %v", ref) - } + // if no digest was provided, then only a resolve + // trusted registry was contacted, in this case use + // the digest header (or content from GET) + if dgst == "" { + // this is the only point at which we trust the registry. we use the + // content headers to assemble a descriptor for the name. when this becomes + // more robust, we mostly get this information from a secure trust store. + dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) + + if dgstHeader != "" && size != -1 { + if err := dgstHeader.Validate(); err != nil { + return "", ocispec.Descriptor{}, errors.Wrapf(err, "%q in header not a valid digest", dgstHeader) + } + dgst = dgstHeader + } + } + if dgst == "" || size == -1 { + log.G(ctx).Debug("no Docker-Content-Digest header, fetching manifest instead") - var ( - size int64 - sizeHeader = resp.Header.Get("Content-Length") - ) + req = base.request(host, http.MethodGet, u...) + if err := req.addNamespace(base.refspec.Hostname()); err != nil { + return "", ocispec.Descriptor{}, err + } + + for key, value := range r.resolveHeader { + req.header[key] = append(req.header[key], value...) + } + + resp, err := req.doWithRetries(ctx, nil) + if err != nil { + return "", ocispec.Descriptor{}, err + } + defer resp.Body.Close() + + bodyReader := countingReader{reader: resp.Body} + + contentType = getManifestMediaType(resp) + if dgst == "" { + if contentType == images.MediaTypeDockerSchema1Manifest { + b, err := schema1.ReadStripSignature(&bodyReader) + if err != nil { + return "", ocispec.Descriptor{}, err + } + + dgst = digest.FromBytes(b) + } else { + dgst, err = digest.FromReader(&bodyReader) + if err != nil { + return "", ocispec.Descriptor{}, err + } + } + } else if _, err := io.Copy(ioutil.Discard, &bodyReader); err != nil { + return "", ocispec.Descriptor{}, err + } + size = bodyReader.bytesRead + } + // Prevent resolving to excessively large manifests + if size > MaxManifestSize { + if firstErr == nil { + firstErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref) + } + continue + } - size, err = strconv.ParseInt(sizeHeader, 10, 64) - if err != nil { + desc := ocispec.Descriptor{ + Digest: dgst, + MediaType: contentType, + Size: size, + } - return "", ocispec.Descriptor{}, errors.Wrapf(err, "invalid size header: %q", sizeHeader) - } - if size < 0 { - return "", ocispec.Descriptor{}, errors.Errorf("%q in header not a valid size", sizeHeader) + log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved") + return ref, desc, nil } + } - desc := ocispec.Descriptor{ - Digest: dgst, - MediaType: resp.Header.Get("Content-Type"), // need to strip disposition? - Size: size, - } + // If above loop terminates without return, then there was an error. + // "firstErr" contains the first non-404 error. That is, "firstErr == nil" + // means that either no registries were given or each registry returned 404. - log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved") - return ref, desc, nil + if firstErr == nil { + firstErr = errors.Wrap(errdefs.ErrNotFound, ref) } - return "", ocispec.Descriptor{}, errors.Errorf("%v not found", ref) + return "", ocispec.Descriptor{}, firstErr } func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { - refspec, err := reference.Parse(ref) - if err != nil { - return nil, err - } - - base, err := r.base(refspec) + base, err := r.resolveDockerBase(ref) if err != nil { return nil, err } @@ -266,79 +406,84 @@ } func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) { - refspec, err := reference.Parse(ref) + base, err := r.resolveDockerBase(ref) if err != nil { return nil, err } - // Manifests can be pushed by digest like any other object, but the passed in - // reference cannot take a digest without the associated content. A tag is allowed - // and will be used to tag pushed manifests. - if refspec.Object != "" && strings.Contains(refspec.Object, "@") { - return nil, errors.New("cannot use digest reference for push locator") - } + return dockerPusher{ + dockerBase: base, + object: base.refspec.Object, + tracker: r.tracker, + }, nil +} - base, err := r.base(refspec) +func (r *dockerResolver) resolveDockerBase(ref string) (*dockerBase, error) { + refspec, err := reference.Parse(ref) if err != nil { return nil, err } - return dockerPusher{ - dockerBase: base, - tag: refspec.Object, - tracker: r.tracker, - }, nil + return r.base(refspec) } type dockerBase struct { - refspec reference.Spec - base url.URL - - client *http.Client - auth Authorizer + refspec reference.Spec + repository string + hosts []RegistryHost + header http.Header } func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) { - var ( - err error - base url.URL - ) - host := refspec.Hostname() - base.Host = host - if r.host != nil { - base.Host, err = r.host(host) - if err != nil { - return nil, err - } - } - - base.Scheme = "https" - if r.plainHTTP || strings.HasPrefix(base.Host, "localhost:") { - base.Scheme = "http" + hosts, err := r.hosts(host) + if err != nil { + return nil, err } - - prefix := strings.TrimPrefix(refspec.Locator, host+"/") - base.Path = path.Join("/v2", prefix) - return &dockerBase{ - refspec: refspec, - base: base, - client: r.client, - auth: r.auth, + refspec: refspec, + repository: strings.TrimPrefix(refspec.Locator, host+"/"), + hosts: hosts, + header: r.header, }, nil } -func (r *dockerBase) url(ps ...string) string { - url := r.base - url.Path = path.Join(url.Path, path.Join(ps...)) - return url.String() +func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) { + for _, host := range r.hosts { + if host.Capabilities.Has(caps) { + hosts = append(hosts, host) + } + } + return } -func (r *dockerBase) authorize(ctx context.Context, req *http.Request) error { +func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request { + header := r.header.Clone() + if header == nil { + header = http.Header{} + } + + for key, value := range host.Header { + header[key] = append(header[key], value...) + } + parts := append([]string{"/", host.Path, r.repository}, ps...) + p := path.Join(parts...) + // Join strips trailing slash, re-add ending "/" if included + if len(parts) > 0 && strings.HasSuffix(parts[len(parts)-1], "/") { + p = p + "/" + } + return &request{ + method: method, + path: p, + header: header, + host: host, + } +} + +func (r *request) authorize(ctx context.Context, req *http.Request) error { // Check if has header for host - if r.auth != nil { - if err := r.auth.Authorize(ctx, req); err != nil { + if r.host.Authorizer != nil { + if err := r.host.Authorizer.Authorize(ctx, req); err != nil { return err } } @@ -346,80 +491,177 @@ return nil } -func (r *dockerBase) doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { - ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", req.URL.String())) - log.G(ctx).WithField("request.headers", req.Header).WithField("request.method", req.Method).Debug("do request") +func (r *request) addNamespace(ns string) (err error) { + if !r.host.isProxy(ns) { + return nil + } + var q url.Values + // Parse query + if i := strings.IndexByte(r.path, '?'); i > 0 { + r.path = r.path[:i+1] + q, err = url.ParseQuery(r.path[i+1:]) + if err != nil { + return + } + } else { + r.path = r.path + "?" + q = url.Values{} + } + q.Add("ns", ns) + + r.path = r.path + q.Encode() + + return +} + +type request struct { + method string + path string + header http.Header + host RegistryHost + body func() (io.ReadCloser, error) + size int64 +} + +func (r *request) do(ctx context.Context) (*http.Response, error) { + u := r.host.Scheme + "://" + r.host.Host + r.path + req, err := http.NewRequest(r.method, u, nil) + if err != nil { + return nil, err + } + req.Header = http.Header{} // headers need to be copied to avoid concurrent map access + for k, v := range r.header { + req.Header[k] = v + } + if r.body != nil { + body, err := r.body() + if err != nil { + return nil, err + } + req.Body = body + req.GetBody = r.body + if r.size > 0 { + req.ContentLength = r.size + } + } + + ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u)) + log.G(ctx).WithFields(requestFields(req)).Debug("do request") if err := r.authorize(ctx, req); err != nil { return nil, errors.Wrap(err, "failed to authorize") } - resp, err := ctxhttp.Do(ctx, r.client, req) + + var client = &http.Client{} + if r.host.Client != nil { + *client = *r.host.Client + } + if client.CheckRedirect == nil { + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return errors.Wrap(r.authorize(ctx, req), "failed to authorize redirect") + } + } + + resp, err := ctxhttp.Do(ctx, client, req) if err != nil { return nil, errors.Wrap(err, "failed to do request") } - log.G(ctx).WithFields(logrus.Fields{ - "status": resp.Status, - "response.headers": resp.Header, - }).Debug("fetch response received") + log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received") return resp, nil } -func (r *dockerBase) doRequestWithRetries(ctx context.Context, req *http.Request, responses []*http.Response) (*http.Response, error) { - resp, err := r.doRequest(ctx, req) +func (r *request) doWithRetries(ctx context.Context, responses []*http.Response) (*http.Response, error) { + resp, err := r.do(ctx) if err != nil { return nil, err } responses = append(responses, resp) - req, err = r.retryRequest(ctx, req, responses) + retry, err := r.retryRequest(ctx, responses) if err != nil { resp.Body.Close() return nil, err } - if req != nil { + if retry { resp.Body.Close() - return r.doRequestWithRetries(ctx, req, responses) + return r.doWithRetries(ctx, responses) } return resp, err } -func (r *dockerBase) retryRequest(ctx context.Context, req *http.Request, responses []*http.Response) (*http.Request, error) { +func (r *request) retryRequest(ctx context.Context, responses []*http.Response) (bool, error) { if len(responses) > 5 { - return nil, nil + return false, nil } last := responses[len(responses)-1] - if last.StatusCode == http.StatusUnauthorized { + switch last.StatusCode { + case http.StatusUnauthorized: log.G(ctx).WithField("header", last.Header.Get("WWW-Authenticate")).Debug("Unauthorized") - if r.auth != nil { - if err := r.auth.AddResponses(ctx, responses); err == nil { - return copyRequest(req) + if r.host.Authorizer != nil { + if err := r.host.Authorizer.AddResponses(ctx, responses); err == nil { + return true, nil } else if !errdefs.IsNotImplemented(err) { - return nil, err + return false, err } } - return nil, nil - } else if last.StatusCode == http.StatusMethodNotAllowed && req.Method == http.MethodHead { + return false, nil + case http.StatusMethodNotAllowed: // Support registries which have not properly implemented the HEAD method for // manifests endpoint - if strings.Contains(req.URL.Path, "/manifests/") { - // TODO: copy request? - req.Method = http.MethodGet - return copyRequest(req) + if r.method == http.MethodHead && strings.Contains(r.path, "/manifests/") { + r.method = http.MethodGet + return true, nil } + case http.StatusRequestTimeout, http.StatusTooManyRequests: + return true, nil } // TODO: Handle 50x errors accounting for attempt history - return nil, nil + return false, nil } -func copyRequest(req *http.Request) (*http.Request, error) { - ireq := *req - if ireq.GetBody != nil { - var err error - ireq.Body, err = ireq.GetBody() - if err != nil { - return nil, err +func (r *request) String() string { + return r.host.Scheme + "://" + r.host.Host + r.path +} + +func requestFields(req *http.Request) logrus.Fields { + fields := map[string]interface{}{ + "request.method": req.Method, + } + for k, vals := range req.Header { + k = strings.ToLower(k) + if k == "authorization" { + continue } + for i, v := range vals { + field := "request.header." + k + if i > 0 { + field = fmt.Sprintf("%s.%d", field, i) + } + fields[field] = v + } + } + + return logrus.Fields(fields) +} + +func responseFields(resp *http.Response) logrus.Fields { + fields := map[string]interface{}{ + "response.status": resp.Status, } - return &ireq, nil + for k, vals := range resp.Header { + k = strings.ToLower(k) + for i, v := range vals { + field := "response.header." + k + if i > 0 { + field = fmt.Sprintf("%s.%d", field, i) + } + fields[field] = v + } + } + + return logrus.Fields(fields) } diff -Nru containerd-1.2.6/remotes/docker/resolver_test.go containerd-1.5.9/remotes/docker/resolver_test.go --- containerd-1.2.6/remotes/docker/resolver_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/resolver_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,6 +29,7 @@ "strconv" "strings" "testing" + "time" "github.com/containerd/containerd/remotes" digest "github.com/opencontainers/go-digest" @@ -41,9 +42,7 @@ s := func(h http.Handler) (string, ResolverOptions, func()) { s := httptest.NewServer(h) - options := ResolverOptions{ - PlainHTTP: true, - } + options := ResolverOptions{} base := s.URL[7:] // strip "http://" return base, options, s.Close } @@ -69,9 +68,12 @@ }) base, options, close := tlsServer(wrapped) - options.Authorizer = NewAuthorizer(options.Client, func(string) (string, string, error) { - return "user1", "password1", nil - }) + options.Hosts = ConfigureDefaultRegistries( + WithClient(options.Client), + WithAuthorizer(NewAuthorizer(options.Client, func(string) (string, string, error) { + return "user1", "password1", nil + })), + ) return base, options, close } runBasicTest(t, "testname", basicAuth) @@ -186,9 +188,241 @@ if err == nil { t.Fatal("Expected error getting token with inssufficient scope") } - if errors.Cause(err) != ErrInvalidAuthorization { + if !errors.Is(err, ErrInvalidAuthorization) { + t.Fatal(err) + } +} + +func TestHostFailureFallbackResolver(t *testing.T) { + sf := func(h http.Handler) (string, ResolverOptions, func()) { + s := httptest.NewServer(h) + base := s.URL[7:] // strip "http://" + + options := ResolverOptions{} + createHost := func(host string) RegistryHost { + return RegistryHost{ + Client: &http.Client{ + // Set the timeout so we timeout waiting for the non-responsive HTTP server + Timeout: 500 * time.Millisecond, + }, + Host: host, + Scheme: "http", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, + } + } + + // Create an unstarted HTTP server. We use this to generate a random port. + notRunning := httptest.NewUnstartedServer(nil) + notRunningBase := notRunning.Listener.Addr().String() + + // Override hosts with two hosts + options.Hosts = func(host string) ([]RegistryHost, error) { + return []RegistryHost{ + createHost(notRunningBase), // This host IS running, but with a non-responsive HTTP server + createHost(base), // This host IS running + }, nil + } + + return base, options, s.Close + } + + runBasicTest(t, "testname", sf) +} + +func TestHostTLSFailureFallbackResolver(t *testing.T) { + sf := func(h http.Handler) (string, ResolverOptions, func()) { + // Start up two servers + server := httptest.NewServer(h) + httpBase := server.URL[7:] // strip "http://" + + tlsServer := httptest.NewUnstartedServer(h) + tlsServer.StartTLS() + httpsBase := tlsServer.URL[8:] // strip "https://" + + capool := x509.NewCertPool() + cert, _ := x509.ParseCertificate(tlsServer.TLS.Certificates[0].Certificate[0]) + capool.AddCert(cert) + + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: capool, + }, + }, + } + + options := ResolverOptions{} + createHost := func(host string) RegistryHost { + return RegistryHost{ + Client: client, + Host: host, + Scheme: "https", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, + } + } + + // Override hosts with two hosts + options.Hosts = func(host string) ([]RegistryHost, error) { + return []RegistryHost{ + createHost(httpBase), // This host is serving plain HTTP + createHost(httpsBase), // This host is serving TLS + }, nil + } + + return httpBase, options, func() { + server.Close() + tlsServer.Close() + } + } + + runBasicTest(t, "testname", sf) +} + +func TestResolveProxy(t *testing.T) { + var ( + ctx = context.Background() + tag = "latest" + r = http.NewServeMux() + name = "testname" + ns = "upstream.example.com" + ) + + m := newManifest( + newContent(ocispec.MediaTypeImageConfig, []byte("1")), + newContent(ocispec.MediaTypeImageLayerGzip, []byte("2")), + ) + mc := newContent(ocispec.MediaTypeImageManifest, m.OCIManifest()) + m.RegisterHandler(r, name) + r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, tag), mc) + r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, mc.Digest()), mc) + + nr := namespaceRouter{ + "upstream.example.com": r, + } + + base, ro, close := tlsServer(logHandler{t, nr}) + defer close() + + ro.Hosts = func(host string) ([]RegistryHost, error) { + return []RegistryHost{{ + Client: ro.Client, + Host: base, + Scheme: "https", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve, + }}, nil + } + + resolver := NewResolver(ro) + image := fmt.Sprintf("%s/%s:%s", ns, name, tag) + + _, d, err := resolver.Resolve(ctx, image) + if err != nil { + t.Fatal(err) + } + f, err := resolver.Fetcher(ctx, image) + if err != nil { + t.Fatal(err) + } + + refs, err := testocimanifest(ctx, f, d) + if err != nil { + t.Fatal(err) + } + + if len(refs) != 2 { + t.Fatalf("Unexpected number of references: %d, expected 2", len(refs)) + } + + for _, ref := range refs { + if err := testFetch(ctx, f, ref); err != nil { + t.Fatal(err) + } + } +} + +func TestResolveProxyFallback(t *testing.T) { + var ( + ctx = context.Background() + tag = "latest" + r = http.NewServeMux() + name = "testname" + ) + + m := newManifest( + newContent(ocispec.MediaTypeImageConfig, []byte("1")), + newContent(ocispec.MediaTypeImageLayerGzip, []byte("2")), + ) + mc := newContent(ocispec.MediaTypeImageManifest, m.OCIManifest()) + m.RegisterHandler(r, name) + r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, tag), mc) + r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, mc.Digest()), mc) + + nr := namespaceRouter{ + "": r, + } + s := httptest.NewServer(logHandler{t, nr}) + defer s.Close() + + base := s.URL[7:] // strip "http://" + + ro := ResolverOptions{ + Hosts: func(host string) ([]RegistryHost, error) { + return []RegistryHost{ + { + Host: flipLocalhost(host), + Scheme: "http", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve, + }, + { + Host: host, + Scheme: "http", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, + }, + }, nil + }, + } + + resolver := NewResolver(ro) + image := fmt.Sprintf("%s/%s:%s", base, name, tag) + + _, d, err := resolver.Resolve(ctx, image) + if err != nil { + t.Fatal(err) + } + f, err := resolver.Fetcher(ctx, image) + if err != nil { + t.Fatal(err) + } + + refs, err := testocimanifest(ctx, f, d) + if err != nil { t.Fatal(err) } + + if len(refs) != 2 { + t.Fatalf("Unexpected number of references: %d, expected 2", len(refs)) + } + + for _, ref := range refs { + if err := testFetch(ctx, f, ref); err != nil { + t.Fatal(err) + } + } +} + +func flipLocalhost(host string) string { + if strings.HasPrefix(host, "127.0.0.1") { + return "localhost" + host[9:] + + } else if strings.HasPrefix(host, "localhost") { + return "127.0.0.1" + host[9:] + } + return host } func withTokenServer(th http.Handler, creds func(string) (string, string, error)) func(h http.Handler) (string, ResolverOptions, func()) { @@ -215,7 +449,13 @@ }) base, options, close := tlsServer(wrapped) - options.Authorizer = NewAuthorizer(options.Client, creds) + options.Hosts = ConfigureDefaultRegistries( + WithClient(options.Client), + WithAuthorizer(NewDockerAuthorizer( + WithAuthClient(options.Client), + WithAuthCreds(creds), + )), + ) options.Client.Transport.(*http.Transport).TLSClientConfig.RootCAs.AddCert(cert) return base, options, func() { s.Close() @@ -232,15 +472,18 @@ cert, _ := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) capool.AddCert(cert) - options := ResolverOptions{ - Client: &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: capool, - }, + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: capool, }, }, } + options := ResolverOptions{ + Hosts: ConfigureDefaultRegistries(WithClient(client)), + // Set deprecated field for tests to use for configuration + Client: client, + } base := s.URL[8:] // strip "https://" return base, options, s.Close } @@ -254,6 +497,17 @@ h.handler.ServeHTTP(rw, r) } +type namespaceRouter map[string]http.Handler + +func (nr namespaceRouter) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + h, ok := nr[r.URL.Query().Get("ns")] + if !ok { + rw.WriteHeader(http.StatusNotFound) + return + } + h.ServeHTTP(rw, r) +} + func runBasicTest(t *testing.T, name string, sf func(h http.Handler) (string, ResolverOptions, func())) { var ( ctx = context.Background() @@ -393,7 +647,7 @@ Config: m.config.Descriptor(), Layers: make([]ocispec.Descriptor, len(m.references)), } - for i, c := range append(m.references) { + for i, c := range m.references { manifest.Layers[i] = c.Descriptor() } b, _ := json.Marshal(manifest) diff -Nru containerd-1.2.6/remotes/docker/schema1/converter.go containerd-1.5.9/remotes/docker/schema1/converter.go --- containerd-1.2.6/remotes/docker/schema1/converter.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/schema1/converter.go 2022-01-05 17:30:58.000000000 +0000 @@ -216,17 +216,28 @@ ref := remotes.MakeRefKey(ctx, desc) if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc, content.WithLabels(labels)); err != nil { - return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config") + return ocispec.Descriptor{}, errors.Wrap(err, "failed to write image manifest") } ref = remotes.MakeRefKey(ctx, config) if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config); err != nil { - return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config") + return ocispec.Descriptor{}, errors.Wrap(err, "failed to write image config") } return desc, nil } +// ReadStripSignature reads in a schema1 manifest and returns a byte array +// with the "signatures" field stripped +func ReadStripSignature(schema1Blob io.Reader) ([]byte, error) { + b, err := ioutil.ReadAll(io.LimitReader(schema1Blob, manifestSizeLimit)) // limit to 8MB + if err != nil { + return nil, err + } + + return stripSignature(b) +} + func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.Descriptor) error { log.G(ctx).Debug("fetch schema 1") @@ -235,21 +246,19 @@ return err } - b, err := ioutil.ReadAll(io.LimitReader(rc, manifestSizeLimit)) // limit to 8MB + b, err := ReadStripSignature(rc) rc.Close() if err != nil { return err } - b, err = stripSignature(b) - if err != nil { - return err - } - var m manifest if err := json.Unmarshal(b, &m); err != nil { return err } + if len(m.Manifests) != 0 || len(m.Layers) != 0 { + return errors.New("converter: expected schema1 document but found extra keys") + } c.pulledManifest = &m return nil @@ -466,8 +475,10 @@ } type manifest struct { - FSLayers []fsLayer `json:"fsLayers"` - History []history `json:"history"` + FSLayers []fsLayer `json:"fsLayers"` + History []history `json:"history"` + Layers json.RawMessage `json:"layers,omitempty"` // OCI manifest + Manifests json.RawMessage `json:"manifests,omitempty"` // OCI index } type v1History struct { diff -Nru containerd-1.2.6/remotes/docker/scope.go containerd-1.5.9/remotes/docker/scope.go --- containerd-1.2.6/remotes/docker/scope.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/scope.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "context" + "fmt" "net/url" "sort" "strings" @@ -25,10 +26,10 @@ "github.com/containerd/containerd/reference" ) -// repositoryScope returns a repository scope string such as "repository:foo/bar:pull" +// RepositoryScope returns a repository scope string such as "repository:foo/bar:pull" // for "host/foo/bar:baz". // When push is true, both pull and push are added to the scope. -func repositoryScope(refspec reference.Spec, push bool) (string, error) { +func RepositoryScope(refspec reference.Spec, push bool) (string, error) { u, err := url.Parse("dummy://" + refspec.Locator) if err != nil { return "", err @@ -44,33 +45,53 @@ // value: []string (e.g. {"registry:foo/bar:pull"}) type tokenScopesKey struct{} -// contextWithRepositoryScope returns a context with tokenScopesKey{} and the repository scope value. -func contextWithRepositoryScope(ctx context.Context, refspec reference.Spec, push bool) (context.Context, error) { - s, err := repositoryScope(refspec, push) +// ContextWithRepositoryScope returns a context with tokenScopesKey{} and the repository scope value. +func ContextWithRepositoryScope(ctx context.Context, refspec reference.Spec, push bool) (context.Context, error) { + s, err := RepositoryScope(refspec, push) if err != nil { return nil, err } - return context.WithValue(ctx, tokenScopesKey{}, []string{s}), nil + return WithScope(ctx, s), nil } -// getTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and params["scope"]. -func getTokenScopes(ctx context.Context, params map[string]string) []string { +// WithScope appends a custom registry auth scope to the context. +func WithScope(ctx context.Context, scope string) context.Context { + var scopes []string + if v := ctx.Value(tokenScopesKey{}); v != nil { + scopes = v.([]string) + scopes = append(scopes, scope) + } else { + scopes = []string{scope} + } + return context.WithValue(ctx, tokenScopesKey{}, scopes) +} + +// ContextWithAppendPullRepositoryScope is used to append repository pull +// scope into existing scopes indexed by the tokenScopesKey{}. +func ContextWithAppendPullRepositoryScope(ctx context.Context, repo string) context.Context { + return WithScope(ctx, fmt.Sprintf("repository:%s:pull", repo)) +} + +// GetTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and common scopes. +func GetTokenScopes(ctx context.Context, common []string) []string { var scopes []string if x := ctx.Value(tokenScopesKey{}); x != nil { scopes = append(scopes, x.([]string)...) } - if scope, ok := params["scope"]; ok { - for _, s := range scopes { - // Note: this comparison is unaware of the scope grammar (https://docs.docker.com/registry/spec/auth/scope/) - // So, "repository:foo/bar:pull,push" != "repository:foo/bar:push,pull", although semantically they are equal. - if s == scope { - // already appended - goto Sort - } + + scopes = append(scopes, common...) + sort.Strings(scopes) + + l := 0 + for idx := 1; idx < len(scopes); idx++ { + // Note: this comparison is unaware of the scope grammar (https://docs.docker.com/registry/spec/auth/scope/) + // So, "repository:foo/bar:pull,push" != "repository:foo/bar:push,pull", although semantically they are equal. + if scopes[l] == scopes[idx] { + continue } - scopes = append(scopes, scope) + + l++ + scopes[l] = scopes[idx] } -Sort: - sort.Strings(scopes) - return scopes + return scopes[:l+1] } diff -Nru containerd-1.2.6/remotes/docker/scope_test.go containerd-1.5.9/remotes/docker/scope_test.go --- containerd-1.2.6/remotes/docker/scope_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/scope_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,10 +17,12 @@ package docker import ( + "context" "testing" "github.com/containerd/containerd/reference" - "gotest.tools/assert" + "gotest.tools/v3/assert" + "gotest.tools/v3/assert/cmp" ) func TestRepositoryScope(t *testing.T) { @@ -48,9 +50,59 @@ } for _, x := range testCases { t.Run(x.refspec.String(), func(t *testing.T) { - actual, err := repositoryScope(x.refspec, x.push) + actual, err := RepositoryScope(x.refspec, x.push) assert.NilError(t, err) assert.Equal(t, x.expected, actual) }) } } + +func TestGetTokenScopes(t *testing.T) { + testCases := []struct { + scopesInCtx []string + commonScopes []string + expected []string + }{ + { + scopesInCtx: []string{}, + commonScopes: []string{"repository:foo/bar:pull"}, + expected: []string{"repository:foo/bar:pull"}, + }, + { + scopesInCtx: []string{"repository:foo/bar:pull,push"}, + commonScopes: []string{}, + expected: []string{"repository:foo/bar:pull,push"}, + }, + { + scopesInCtx: []string{"repository:foo/bar:pull"}, + commonScopes: []string{"repository:foo/bar:pull"}, + expected: []string{"repository:foo/bar:pull"}, + }, + { + scopesInCtx: []string{"repository:foo/bar:pull"}, + commonScopes: []string{"repository:foo/bar:pull,push"}, + expected: []string{"repository:foo/bar:pull", "repository:foo/bar:pull,push"}, + }, + { + scopesInCtx: []string{"repository:foo/bar:pull"}, + commonScopes: []string{"repository:foo/bar:pull,push", "repository:foo/bar:pull"}, + expected: []string{"repository:foo/bar:pull", "repository:foo/bar:pull,push"}, + }, + } + for _, tc := range testCases { + ctx := context.WithValue(context.TODO(), tokenScopesKey{}, tc.scopesInCtx) + actual := GetTokenScopes(ctx, tc.commonScopes) + assert.DeepEqual(t, tc.expected, actual) + } +} + +func TestCustomScope(t *testing.T) { + scope := "whatever:foo/bar:pull" + ctx := WithScope(context.Background(), scope) + ctx = ContextWithAppendPullRepositoryScope(ctx, "foo/bar") + + scopes := GetTokenScopes(ctx, []string{}) + assert.Assert(t, cmp.Len(scopes, 2)) + assert.Check(t, cmp.Equal(scopes[0], "repository:foo/bar:pull")) + assert.Check(t, cmp.Equal(scopes[1], scope)) +} diff -Nru containerd-1.2.6/remotes/docker/status.go containerd-1.5.9/remotes/docker/status.go --- containerd-1.2.6/remotes/docker/status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/docker/status.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" + "github.com/moby/locker" "github.com/pkg/errors" ) @@ -28,6 +29,8 @@ type Status struct { content.Status + Committed bool + // UploadUUID is used by the Docker registry to reference blob uploads UploadUUID string } @@ -38,15 +41,24 @@ SetStatus(string, Status) } +// StatusTrackLocker to track status of operations with lock +type StatusTrackLocker interface { + StatusTracker + Lock(string) + Unlock(string) +} + type memoryStatusTracker struct { statuses map[string]Status m sync.Mutex + locker *locker.Locker } // NewInMemoryTracker returns a StatusTracker that tracks content status in-memory -func NewInMemoryTracker() StatusTracker { +func NewInMemoryTracker() StatusTrackLocker { return &memoryStatusTracker{ statuses: map[string]Status{}, + locker: locker.New(), } } @@ -65,3 +77,11 @@ t.statuses[ref] = status t.m.Unlock() } + +func (t *memoryStatusTracker) Lock(ref string) { + t.locker.Lock(ref) +} + +func (t *memoryStatusTracker) Unlock(ref string) { + t.locker.Unlock(ref) +} diff -Nru containerd-1.2.6/remotes/errors/errors.go containerd-1.5.9/remotes/errors/errors.go --- containerd-1.2.6/remotes/errors/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/errors/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package errors + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" +) + +var _ error = ErrUnexpectedStatus{} + +// ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status +type ErrUnexpectedStatus struct { + Status string + StatusCode int + Body []byte + RequestURL, RequestMethod string +} + +func (e ErrUnexpectedStatus) Error() string { + return fmt.Sprintf("unexpected status: %s", e.Status) +} + +// NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response +func NewUnexpectedStatusErr(resp *http.Response) error { + var b []byte + if resp.Body != nil { + b, _ = ioutil.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB + } + err := ErrUnexpectedStatus{ + Body: b, + Status: resp.Status, + StatusCode: resp.StatusCode, + RequestMethod: resp.Request.Method, + } + if resp.Request.URL != nil { + err.RequestURL = resp.Request.URL.String() + } + return err +} diff -Nru containerd-1.2.6/remotes/handlers.go containerd-1.5.9/remotes/handlers.go --- containerd-1.2.6/remotes/handlers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/handlers.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,30 +31,57 @@ ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/sync/semaphore" ) +type refKeyPrefix struct{} + +// WithMediaTypeKeyPrefix adds a custom key prefix for a media type which is used when storing +// data in the content store from the FetchHandler. +// +// Used in `MakeRefKey` to determine what the key prefix should be. +func WithMediaTypeKeyPrefix(ctx context.Context, mediaType, prefix string) context.Context { + var values map[string]string + if v := ctx.Value(refKeyPrefix{}); v != nil { + values = v.(map[string]string) + } else { + values = make(map[string]string) + } + + values[mediaType] = prefix + return context.WithValue(ctx, refKeyPrefix{}, values) +} + // MakeRefKey returns a unique reference for the descriptor. This reference can be // used to lookup ongoing processes related to the descriptor. This function // may look to the context to namespace the reference appropriately. func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string { - // TODO(stevvooe): Need better remote key selection here. Should be a - // product of the context, which may include information about the ongoing - // fetch process. - switch desc.MediaType { - case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: - return "manifest-" + desc.Digest.String() - case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: - return "index-" + desc.Digest.String() - case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip, - images.MediaTypeDockerSchema2LayerForeign, images.MediaTypeDockerSchema2LayerForeignGzip, - ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip, - ocispec.MediaTypeImageLayerNonDistributable, ocispec.MediaTypeImageLayerNonDistributableGzip: - return "layer-" + desc.Digest.String() - case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: - return "config-" + desc.Digest.String() + key := desc.Digest.String() + if desc.Annotations != nil { + if name, ok := desc.Annotations[ocispec.AnnotationRefName]; ok { + key = fmt.Sprintf("%s@%s", name, desc.Digest.String()) + } + } + + if v := ctx.Value(refKeyPrefix{}); v != nil { + values := v.(map[string]string) + if prefix := values[desc.MediaType]; prefix != "" { + return prefix + "-" + key + } + } + + switch mt := desc.MediaType; { + case mt == images.MediaTypeDockerSchema2Manifest || mt == ocispec.MediaTypeImageManifest: + return "manifest-" + key + case mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex: + return "index-" + key + case images.IsLayerType(mt): + return "layer-" + key + case images.IsKnownConfig(mt): + return "config-" + key default: - log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType) - return "unknown-" + desc.Digest.String() + log.G(ctx).Warnf("reference for unknown type: %s", mt) + return "unknown-" + key } } @@ -96,6 +123,12 @@ return err } + if desc.Size == 0 { + // most likely a poorly configured registry/web front end which responded with no + // Content-Length header; unable (not to mention useless) to commit a 0-length entry + // into the content store. Error out here otherwise the error sent back is confusing + return errors.Wrapf(errdefs.ErrInvalidArgument, "unable to fetch descriptor (%s) which reports content size of zero", desc.Digest) + } if ws.Offset == desc.Size { // If writer is already complete, commit and return err := cw.Commit(ctx, desc.Size, desc.Digest) @@ -132,7 +165,15 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc ocispec.Descriptor) error { log.G(ctx).Debug("push") - cw, err := pusher.Push(ctx, desc) + var ( + cw content.Writer + err error + ) + if cs, ok := pusher.(content.Ingester); ok { + cw, err = content.OpenWriter(ctx, cs, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc)) + } else { + cw, err = pusher.Push(ctx, desc) + } if err != nil { if !errdefs.IsAlreadyExists(err) { return err @@ -156,7 +197,8 @@ // // Base handlers can be provided which will be called before any push specific // handlers. -func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, provider content.Provider, platform platforms.MatchComparer, baseHandlers ...images.Handler) error { +func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Store, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error { + var m sync.Mutex manifestStack := []ocispec.Descriptor{} @@ -173,15 +215,22 @@ } }) - pushHandler := PushHandler(pusher, provider) + pushHandler := PushHandler(pusher, store) + + platformFilterhandler := images.FilterPlatforms(images.ChildrenHandler(store), platform) + + annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, store) - handlers := append(baseHandlers, - images.FilterPlatforms(images.ChildrenHandler(provider), platform), + var handler images.Handler = images.Handlers( + annotateHandler, filterHandler, pushHandler, ) + if wrapper != nil { + handler = wrapper(handler) + } - if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil { + if err := images.Dispatch(ctx, handler, limiter, desc); err != nil { return err } @@ -203,3 +252,80 @@ return nil } + +// FilterManifestByPlatformHandler allows Handler to handle non-target +// platform's manifest and configuration data. +func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher) images.HandlerFunc { + return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + children, err := f(ctx, desc) + if err != nil { + return nil, err + } + + // no platform information + if desc.Platform == nil || m == nil { + return children, nil + } + + var descs []ocispec.Descriptor + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + if m.Match(*desc.Platform) { + descs = children + } else { + for _, child := range children { + if child.MediaType == images.MediaTypeDockerSchema2Config || + child.MediaType == ocispec.MediaTypeImageConfig { + + descs = append(descs, child) + } + } + } + default: + descs = children + } + return descs, nil + } +} + +// annotateDistributionSourceHandler add distribution source label into +// annotation of config or blob descriptor. +func annotateDistributionSourceHandler(f images.HandlerFunc, manager content.Manager) images.HandlerFunc { + return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + children, err := f(ctx, desc) + if err != nil { + return nil, err + } + + // only add distribution source for the config or blob data descriptor + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest, + images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + default: + return children, nil + } + + for i := range children { + child := children[i] + + info, err := manager.Info(ctx, child.Digest) + if err != nil { + return nil, err + } + + for k, v := range info.Labels { + if !strings.HasPrefix(k, "containerd.io/distribution.source.") { + continue + } + + if child.Annotations == nil { + child.Annotations = map[string]string{} + } + child.Annotations[k] = v + } + + children[i] = child + } + return children, nil + } +} diff -Nru containerd-1.2.6/remotes/handlers_test.go containerd-1.5.9/remotes/handlers_test.go --- containerd-1.2.6/remotes/handlers_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/remotes/handlers_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package remotes + +import ( + "context" + "testing" + + "github.com/containerd/containerd/images" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +func TestContextCustomKeyPrefix(t *testing.T) { + ctx := context.Background() + cmt := "testing/custom.media.type" + ctx = WithMediaTypeKeyPrefix(ctx, images.MediaTypeDockerSchema2Layer, "bananas") + ctx = WithMediaTypeKeyPrefix(ctx, cmt, "apples") + + // makes sure that even though we've supplied some custom handling, the built-in still works + t.Run("normal supported case", func(t *testing.T) { + desc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageLayer} + expected := "layer-" + + actual := MakeRefKey(ctx, desc) + if actual != expected { + t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) + } + }) + + t.Run("unknown media type", func(t *testing.T) { + desc := ocispec.Descriptor{MediaType: "we.dont.know.what.this.is"} + expected := "unknown-" + + actual := MakeRefKey(ctx, desc) + if actual != expected { + t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) + } + }) + + t.Run("overwrite supported media type", func(t *testing.T) { + desc := ocispec.Descriptor{MediaType: images.MediaTypeDockerSchema2Layer} + expected := "bananas-" + + actual := MakeRefKey(ctx, desc) + if actual != expected { + t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) + } + }) + + t.Run("custom media type", func(t *testing.T) { + desc := ocispec.Descriptor{MediaType: cmt} + expected := "apples-" + + actual := MakeRefKey(ctx, desc) + if actual != expected { + t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) + } + }) +} diff -Nru containerd-1.2.6/remotes/resolver.go containerd-1.5.9/remotes/resolver.go --- containerd-1.2.6/remotes/resolver.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/remotes/resolver.go 2022-01-05 17:30:58.000000000 +0000 @@ -45,6 +45,8 @@ Fetcher(ctx context.Context, ref string) (Fetcher, error) // Pusher returns a new pusher for the provided reference + // The returned Pusher should satisfy content.Ingester and concurrent attempts + // to push the same blob using the Ingester API should result in ErrUnavailable. Pusher(ctx context.Context, ref string) (Pusher, error) } @@ -72,9 +74,9 @@ // PusherFunc allows package users to implement a Pusher with just a // function. -type PusherFunc func(ctx context.Context, desc ocispec.Descriptor, r io.Reader) error +type PusherFunc func(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) // Push content -func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor, r io.Reader) error { - return fn(ctx, desc, r) +func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) { + return fn(ctx, desc) } diff -Nru containerd-1.2.6/reports/2017-01-13.md containerd-1.5.9/reports/2017-01-13.md --- containerd-1.2.6/reports/2017-01-13.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-01-13.md 2022-01-05 17:30:58.000000000 +0000 @@ -37,7 +37,7 @@ * https://github.com/containerd/containerd/pull/417 -## Whats Next? +## What's Next? Next week we will be working towards a full PoC with the runtime, storage, and fetching of images. Getting the core functionality up and running quickly is important to us to ensure that integration between the different subsystems in the core flow well together. We want to make sure the responsibilities of pulling an image from a remote source do not spill into the storage layer and vice-versa. diff -Nru containerd-1.2.6/reports/2017-02-10.md containerd-1.5.9/reports/2017-02-10.md --- containerd-1.2.6/reports/2017-02-10.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-02-10.md 2022-01-05 17:30:58.000000000 +0000 @@ -38,7 +38,7 @@ ## Bundles Bundles Bundles We spend time talking with people implementing Windows support as well as a few other users. -One the the major issues with our current approach was that bundles were a central part of our architecture. +One the major issues with our current approach was that bundles were a central part of our architecture. The content and storage subsystems would produce bundles and the execution subsystem would consume them. However, with a bundle being on the filesystem, having this concept does not work as smoothly on Windows as it would for Unix platforms. diff -Nru containerd-1.2.6/reports/2017-04-28.md containerd-1.5.9/reports/2017-04-28.md --- containerd-1.2.6/reports/2017-04-28.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-04-28.md 2022-01-05 17:30:58.000000000 +0000 @@ -26,7 +26,7 @@ ## Task List for week of May 1 -So, now that we are all back from Dockercon and not rested at all, whats on the agenda for next week? +So, now that we are all back from Dockercon and not rested at all, what's on the agenda for next week? * Docker Integration Pass - Replace the current v0.2.x branch of containerd in Docker for execution with the 1.0 execution service @@ -43,7 +43,7 @@ ## containerd Summit Notes -Here are the notes from the containerd summit that was held after Dockercon. If there are important to you and you would like to start working on a feature, fix, request, please go ahead and open an issue on github. Just remember, we shouldn't have to have a summit to get things into containerd. Open issues, disscuss with other members of the community and write the code ;) +Here are the notes from the containerd summit that was held after Dockercon. If there are important to you and you would like to start working on a feature, fix, request, please go ahead and open an issue on github. Just remember, we shouldn't have to have a summit to get things into containerd. Open issues, discuss with other members of the community and write the code ;) * “Since containerd is one of the bottom bricks in the stack, how can we setup automated integration tests for consumers of containerd?†- Looking for others to provide compute (testing within Docker, K8s, Microsoft) diff -Nru containerd-1.2.6/reports/2017-05-19.md containerd-1.5.9/reports/2017-05-19.md --- containerd-1.2.6/reports/2017-05-19.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-05-19.md 2022-01-05 17:30:58.000000000 +0000 @@ -4,7 +4,7 @@ Moving more functionality into containerd means more requirements from users. One thing that we have ran into was the disconnect of what our Container model is and what users expect, `docker create;docker start;docker rm` vs a container that is destroyed when it exits. -To users, containers are more of a metadata object that resources(rw, configuration) and information(state, last exit status) are attached to. We have been reworking what we call a "container" today to be called a "task" and a Container metadata object. The task only has runtime state: a pid, namepsaces, cgroups, etc. A container has an id, root filesystem, configuration, and other metadata from a user. +To users, containers are more of a metadata object that resources(rw, configuration) and information(state, last exit status) are attached to. We have been reworking what we call a "container" today to be called a "task" and a Container metadata object. The task only has runtime state: a pid, namespaces, cgroups, etc. A container has an id, root filesystem, configuration, and other metadata from a user. Managing static state and runtime state in the same object is very tricky so we choose to keep execution and metadata separate. We are hoping to not cause more confusion with this additional task object. You can see a mockup of a client interacting with a container and how the task is handled below: diff -Nru containerd-1.2.6/reports/2017-05-26.md containerd-1.5.9/reports/2017-05-26.md --- containerd-1.2.6/reports/2017-05-26.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-05-26.md 2022-01-05 17:30:58.000000000 +0000 @@ -124,7 +124,7 @@ You can view the PR [here](https://github.com/containerd/containerd/pull/910). -## Whats Next? +## What's Next? We still need to finish Events. This is one of the last major features that we need before we consider containerd feature complete. The namespace work is in progress with the initial service spec'd. diff -Nru containerd-1.2.6/reports/2017-06-09.md containerd-1.5.9/reports/2017-06-09.md --- containerd-1.2.6/reports/2017-06-09.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/reports/2017-06-09.md 2022-01-05 17:30:58.000000000 +0000 @@ -28,7 +28,7 @@ [checkpoint](https://github.com/containerd/containerd/pull/958) [attach](https://github.com/containerd/containerd/pull/976) -# Whats Next? +# What's Next? We only have a few features left to implement, such as [events](https://github.com/containerd/containerd/pull/956), for our 1.0 release. The rest of the month we are working on usability, bug fixes, and stability. diff -Nru containerd-1.2.6/rootfs/apply.go containerd-1.5.9/rootfs/apply.go --- containerd-1.2.6/rootfs/apply.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/rootfs/apply.go 2022-01-05 17:30:58.000000000 +0000 @@ -48,6 +48,14 @@ // Layers are applied in order they are given, making the first layer the // bottom-most layer in the layer chain. func ApplyLayers(ctx context.Context, layers []Layer, sn snapshots.Snapshotter, a diff.Applier) (digest.Digest, error) { + return ApplyLayersWithOpts(ctx, layers, sn, a, nil) +} + +// ApplyLayersWithOpts applies all the layers using the given snapshotter, applier, and apply opts. +// The returned result is a chain id digest representing all the applied layers. +// Layers are applied in order they are given, making the first layer the +// bottom-most layer in the layer chain. +func ApplyLayersWithOpts(ctx context.Context, layers []Layer, sn snapshots.Snapshotter, a diff.Applier, applyOpts []diff.ApplyOpt) (digest.Digest, error) { chain := make([]digest.Digest, len(layers)) for i, layer := range layers { chain[i] = layer.Diff.Digest @@ -63,7 +71,7 @@ return "", errors.Wrapf(err, "failed to stat snapshot %s", chainID) } - if err := applyLayers(ctx, layers, chain, sn, a); err != nil && !errdefs.IsAlreadyExists(err) { + if err := applyLayers(ctx, layers, chain, sn, a, nil, applyOpts); err != nil && !errdefs.IsAlreadyExists(err) { return "", err } } @@ -75,6 +83,13 @@ // using the provided snapshotter and applier. If the layer was unpacked true // is returned, if the layer already exists false is returned. func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts ...snapshots.Opt) (bool, error) { + return ApplyLayerWithOpts(ctx, layer, chain, sn, a, opts, nil) +} + +// ApplyLayerWithOpts applies a single layer on top of the given provided layer chain, +// using the provided snapshotter, applier, and apply opts. If the layer was unpacked true +// is returned, if the layer already exists false is returned. +func ApplyLayerWithOpts(ctx context.Context, layer Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts []snapshots.Opt, applyOpts []diff.ApplyOpt) (bool, error) { var ( chainID = identity.ChainID(append(chain, layer.Diff.Digest)).String() applied bool @@ -84,7 +99,7 @@ return false, errors.Wrapf(err, "failed to stat snapshot %s", chainID) } - if err := applyLayers(ctx, []Layer{layer}, append(chain, layer.Diff.Digest), sn, a, opts...); err != nil { + if err := applyLayers(ctx, []Layer{layer}, append(chain, layer.Diff.Digest), sn, a, opts, applyOpts); err != nil { if !errdefs.IsAlreadyExists(err) { return false, err } @@ -93,9 +108,10 @@ } } return applied, nil + } -func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts ...snapshots.Opt) error { +func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts []snapshots.Opt, applyOpts []diff.ApplyOpt) error { var ( parent = identity.ChainID(chain[:len(chain)-1]) chainID = identity.ChainID(chain) @@ -107,13 +123,13 @@ ) for { - key = fmt.Sprintf("extract-%s %s", uniquePart(), chainID) + key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID) // Prepare snapshot with from parent, label as root mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) if err != nil { if errdefs.IsNotFound(err) && len(layers) > 1 { - if err := applyLayers(ctx, layers[:len(layers)-1], chain[:len(chain)-1], sn, a); err != nil { + if err := applyLayers(ctx, layers[:len(layers)-1], chain[:len(chain)-1], sn, a, opts, applyOpts); err != nil { if !errdefs.IsAlreadyExists(err) { return err } @@ -144,7 +160,7 @@ } }() - diff, err = a.Apply(ctx, layer.Blob, mounts) + diff, err = a.Apply(ctx, layer.Blob, mounts, applyOpts...) if err != nil { err = errors.Wrapf(err, "failed to extract layer %s", layer.Diff.Digest) return err diff -Nru containerd-1.2.6/rootfs/diff.go containerd-1.5.9/rootfs/diff.go --- containerd-1.2.6/rootfs/diff.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/rootfs/diff.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,6 +22,7 @@ "github.com/containerd/containerd/diff" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshots" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -31,6 +32,13 @@ // the content creation and the provided snapshotter and mount differ are used // for calculating the diff. The descriptor for the layer diff is returned. func CreateDiff(ctx context.Context, snapshotID string, sn snapshots.Snapshotter, d diff.Comparer, opts ...diff.Opt) (ocispec.Descriptor, error) { + // dctx is used to handle cleanup things just in case the param ctx + // has been canceled, which causes that the defer cleanup fails. + dctx := context.Background() + if ns, ok := namespaces.Namespace(ctx); ok { + dctx = namespaces.WithNamespace(dctx, ns) + } + info, err := sn.Stat(ctx, snapshotID) if err != nil { return ocispec.Descriptor{}, err @@ -41,7 +49,7 @@ if err != nil { return ocispec.Descriptor{}, err } - defer sn.Remove(ctx, lowerKey) + defer sn.Remove(dctx, lowerKey) var upper []mount.Mount if info.Kind == snapshots.KindActive { @@ -55,7 +63,7 @@ if err != nil { return ocispec.Descriptor{}, err } - defer sn.Remove(ctx, upperKey) + defer sn.Remove(dctx, upperKey) } return d.Compare(ctx, lower, upper, opts...) diff -Nru containerd-1.2.6/rootfs/init.go containerd-1.5.9/rootfs/init.go --- containerd-1.2.6/rootfs/init.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/rootfs/init.go 2022-01-05 17:30:58.000000000 +0000 @@ -67,7 +67,7 @@ return snapshotter.Prepare(ctx, name, parentS) } -func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshots.Snapshotter, mounter Mounter) (string, error) { +func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshots.Snapshotter, mounter Mounter) (_ string, retErr error) { initS := fmt.Sprintf("%s %s", parent, initName) if _, err := snapshotter.Stat(ctx, initS); err == nil { return initS, nil @@ -87,7 +87,7 @@ } defer func() { - if err != nil { + if retErr != nil { if rerr := snapshotter.Remove(ctx, td); rerr != nil { log.G(ctx).Errorf("Failed to remove snapshot %s: %v", td, rerr) } diff -Nru containerd-1.2.6/RUNC.md containerd-1.5.9/RUNC.md --- containerd-1.2.6/RUNC.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/RUNC.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -containerd is built with OCI support and with support for advanced features provided by [runc](https://github.com/opencontainers/runc). - -We depend on a specific `runc` version when dealing with advanced features. You should have a specific runc build for development. The current supported runc commit is described in [`vendor.conf`](vendor.conf). Please refer to the line that starts with `github.com/opencontainers/runc`. - -For more information on how to clone and build runc see the runc Building [documentation](https://github.com/opencontainers/runc#building). - -Note: before building you may need to install additional support, which will vary by platform. For example, you may need to install `libseccomp` e.g. `libseccomp-dev` for Ubuntu. - -## building - -From within your `opencontainers/runc` repository run: - -### apparmor - -```bash -make BUILDTAGS='seccomp apparmor' && sudo make install -``` - -### selinux - -```bash -make BUILDTAGS='seccomp selinux' && sudo make install -``` - -After an official runc release we will start pinning containerd support to a specific version but various development and testing features may require a newer runc version than the latest release. If you encounter any runtime errors, please make sure your runc is in sync with the commit/tag provided in this document. diff -Nru containerd-1.2.6/runtime/linux/runctypes/next.pb.txt containerd-1.5.9/runtime/linux/runctypes/next.pb.txt --- containerd-1.2.6/runtime/linux/runctypes/next.pb.txt 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/linux/runctypes/next.pb.txt 2022-01-05 17:30:58.000000000 +0000 @@ -112,6 +112,20 @@ type: TYPE_UINT32 json_name: "ioGid" } + field { + name: "criu_work_path" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuWorkPath" + } + field { + name: "criu_image_path" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuImagePath" + } } message_type { name: "CheckpointOptions" @@ -164,6 +178,20 @@ type: TYPE_STRING json_name: "cgroupsMode" } + field { + name: "work_path" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "workPath" + } + field { + name: "image_path" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "imagePath" + } } message_type { name: "ProcessDetails" diff -Nru containerd-1.2.6/runtime/linux/runctypes/runc.pb.go containerd-1.5.9/runtime/linux/runctypes/runc.pb.go --- containerd-1.2.6/runtime/linux/runctypes/runc.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/linux/runctypes/runc.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,30 +1,17 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/runtime/linux/runctypes/runc.proto -/* - Package runctypes is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/runtime/linux/runctypes/runc.proto - - It has these top-level messages: - RuncOptions - CreateOptions - CheckpointOptions - ProcessDetails -*/ package runctypes -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -35,58 +22,186 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type RuncOptions struct { - Runtime string `protobuf:"bytes,1,opt,name=runtime,proto3" json:"runtime,omitempty"` - RuntimeRoot string `protobuf:"bytes,2,opt,name=runtime_root,json=runtimeRoot,proto3" json:"runtime_root,omitempty"` - CriuPath string `protobuf:"bytes,3,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"` - SystemdCgroup bool `protobuf:"varint,4,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` + Runtime string `protobuf:"bytes,1,opt,name=runtime,proto3" json:"runtime,omitempty"` + RuntimeRoot string `protobuf:"bytes,2,opt,name=runtime_root,json=runtimeRoot,proto3" json:"runtime_root,omitempty"` + CriuPath string `protobuf:"bytes,3,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"` + SystemdCgroup bool `protobuf:"varint,4,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RuncOptions) Reset() { *m = RuncOptions{} } +func (*RuncOptions) ProtoMessage() {} +func (*RuncOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_d20e2ba8b3cc58b9, []int{0} +} +func (m *RuncOptions) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RuncOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RuncOptions.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RuncOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_RuncOptions.Merge(m, src) +} +func (m *RuncOptions) XXX_Size() int { + return m.Size() +} +func (m *RuncOptions) XXX_DiscardUnknown() { + xxx_messageInfo_RuncOptions.DiscardUnknown(m) } -func (m *RuncOptions) Reset() { *m = RuncOptions{} } -func (*RuncOptions) ProtoMessage() {} -func (*RuncOptions) Descriptor() ([]byte, []int) { return fileDescriptorRunc, []int{0} } +var xxx_messageInfo_RuncOptions proto.InternalMessageInfo type CreateOptions struct { - NoPivotRoot bool `protobuf:"varint,1,opt,name=no_pivot_root,json=noPivotRoot,proto3" json:"no_pivot_root,omitempty"` - OpenTcp bool `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` - ExternalUnixSockets bool `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` - Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` - FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` - EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"` - CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` - NoNewKeyring bool `protobuf:"varint,8,opt,name=no_new_keyring,json=noNewKeyring,proto3" json:"no_new_keyring,omitempty"` - ShimCgroup string `protobuf:"bytes,9,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"` - IoUid uint32 `protobuf:"varint,10,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"` - IoGid uint32 `protobuf:"varint,11,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"` -} - -func (m *CreateOptions) Reset() { *m = CreateOptions{} } -func (*CreateOptions) ProtoMessage() {} -func (*CreateOptions) Descriptor() ([]byte, []int) { return fileDescriptorRunc, []int{1} } + NoPivotRoot bool `protobuf:"varint,1,opt,name=no_pivot_root,json=noPivotRoot,proto3" json:"no_pivot_root,omitempty"` + OpenTcp bool `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` + ExternalUnixSockets bool `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` + EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces,proto3" json:"empty_namespaces,omitempty"` + CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` + NoNewKeyring bool `protobuf:"varint,8,opt,name=no_new_keyring,json=noNewKeyring,proto3" json:"no_new_keyring,omitempty"` + ShimCgroup string `protobuf:"bytes,9,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"` + IoUid uint32 `protobuf:"varint,10,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"` + IoGid uint32 `protobuf:"varint,11,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"` + CriuWorkPath string `protobuf:"bytes,12,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"` + CriuImagePath string `protobuf:"bytes,13,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateOptions) Reset() { *m = CreateOptions{} } +func (*CreateOptions) ProtoMessage() {} +func (*CreateOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_d20e2ba8b3cc58b9, []int{1} +} +func (m *CreateOptions) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateOptions.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateOptions.Merge(m, src) +} +func (m *CreateOptions) XXX_Size() int { + return m.Size() +} +func (m *CreateOptions) XXX_DiscardUnknown() { + xxx_messageInfo_CreateOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateOptions proto.InternalMessageInfo type CheckpointOptions struct { - Exit bool `protobuf:"varint,1,opt,name=exit,proto3" json:"exit,omitempty"` - OpenTcp bool `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` - ExternalUnixSockets bool `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` - Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` - FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` - EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"` - CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` + Exit bool `protobuf:"varint,1,opt,name=exit,proto3" json:"exit,omitempty"` + OpenTcp bool `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` + ExternalUnixSockets bool `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` + EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces,proto3" json:"empty_namespaces,omitempty"` + CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` + WorkPath string `protobuf:"bytes,8,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"` + ImagePath string `protobuf:"bytes,9,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} } +func (*CheckpointOptions) ProtoMessage() {} +func (*CheckpointOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_d20e2ba8b3cc58b9, []int{2} +} +func (m *CheckpointOptions) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointOptions.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointOptions.Merge(m, src) +} +func (m *CheckpointOptions) XXX_Size() int { + return m.Size() +} +func (m *CheckpointOptions) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointOptions.DiscardUnknown(m) } -func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} } -func (*CheckpointOptions) ProtoMessage() {} -func (*CheckpointOptions) Descriptor() ([]byte, []int) { return fileDescriptorRunc, []int{2} } +var xxx_messageInfo_CheckpointOptions proto.InternalMessageInfo type ProcessDetails struct { - ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *ProcessDetails) Reset() { *m = ProcessDetails{} } -func (*ProcessDetails) ProtoMessage() {} -func (*ProcessDetails) Descriptor() ([]byte, []int) { return fileDescriptorRunc, []int{3} } +func (m *ProcessDetails) Reset() { *m = ProcessDetails{} } +func (*ProcessDetails) ProtoMessage() {} +func (*ProcessDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_d20e2ba8b3cc58b9, []int{3} +} +func (m *ProcessDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProcessDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProcessDetails.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProcessDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProcessDetails.Merge(m, src) +} +func (m *ProcessDetails) XXX_Size() int { + return m.Size() +} +func (m *ProcessDetails) XXX_DiscardUnknown() { + xxx_messageInfo_ProcessDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_ProcessDetails proto.InternalMessageInfo func init() { proto.RegisterType((*RuncOptions)(nil), "containerd.linux.runc.RuncOptions") @@ -94,10 +209,57 @@ proto.RegisterType((*CheckpointOptions)(nil), "containerd.linux.runc.CheckpointOptions") proto.RegisterType((*ProcessDetails)(nil), "containerd.linux.runc.ProcessDetails") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/runtime/linux/runctypes/runc.proto", fileDescriptor_d20e2ba8b3cc58b9) +} + +var fileDescriptor_d20e2ba8b3cc58b9 = []byte{ + // 604 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x94, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xeb, 0xfe, 0x49, 0x9c, 0x49, 0xd2, 0xc2, 0x42, 0x25, 0xd3, 0xaa, 0x69, 0x08, 0x7f, + 0x14, 0x2e, 0xa9, 0x04, 0xe2, 0xc4, 0xad, 0x29, 0x42, 0x15, 0x50, 0x2a, 0x43, 0x05, 0x42, 0x48, + 0x2b, 0x77, 0x3d, 0x24, 0xab, 0xc4, 0x3b, 0x96, 0x77, 0x4d, 0x92, 0x1b, 0x4f, 0xc0, 0x0b, 0xf1, + 0x02, 0x3d, 0x21, 0x8e, 0x9c, 0x10, 0xcd, 0x93, 0xa0, 0x5d, 0xc7, 0x69, 0xcf, 0x1c, 0xb9, 0xcd, + 0xfc, 0xe6, 0xb3, 0x67, 0xf4, 0x7d, 0xb2, 0xa1, 0x3f, 0x90, 0x66, 0x98, 0x9f, 0xf7, 0x04, 0x25, + 0x07, 0x82, 0x94, 0x89, 0xa4, 0xc2, 0x2c, 0xbe, 0x5e, 0x66, 0xb9, 0x32, 0x32, 0xc1, 0x83, 0xb1, + 0x54, 0xf9, 0xd4, 0x76, 0xc2, 0xcc, 0x52, 0xd4, 0xae, 0xea, 0xa5, 0x19, 0x19, 0x62, 0xdb, 0x57, + 0xf2, 0x9e, 0x93, 0xf5, 0xec, 0x70, 0xe7, 0xf6, 0x80, 0x06, 0xe4, 0x14, 0x07, 0xb6, 0x2a, 0xc4, + 0x9d, 0x6f, 0x1e, 0xd4, 0xc3, 0x5c, 0x89, 0x37, 0xa9, 0x91, 0xa4, 0x34, 0x0b, 0xa0, 0xba, 0x58, + 0x11, 0x78, 0x6d, 0xaf, 0x5b, 0x0b, 0xcb, 0x96, 0xdd, 0x85, 0xc6, 0xa2, 0xe4, 0x19, 0x91, 0x09, + 0x56, 0xdd, 0xb8, 0xbe, 0x60, 0x21, 0x91, 0x61, 0xbb, 0x50, 0x13, 0x99, 0xcc, 0x79, 0x1a, 0x99, + 0x61, 0xb0, 0xe6, 0xe6, 0xbe, 0x05, 0xa7, 0x91, 0x19, 0xb2, 0x07, 0xb0, 0xa9, 0x67, 0xda, 0x60, + 0x12, 0x73, 0x31, 0xc8, 0x28, 0x4f, 0x83, 0xf5, 0xb6, 0xd7, 0xf5, 0xc3, 0xe6, 0x82, 0xf6, 0x1d, + 0xec, 0xfc, 0x58, 0x83, 0x66, 0x3f, 0xc3, 0xc8, 0x60, 0x79, 0x52, 0x07, 0x9a, 0x8a, 0x78, 0x2a, + 0xbf, 0x90, 0x29, 0x36, 0x7b, 0xee, 0xb9, 0xba, 0xa2, 0x53, 0xcb, 0xdc, 0xe6, 0x3b, 0xe0, 0x53, + 0x8a, 0x8a, 0x1b, 0x91, 0xba, 0xc3, 0xfc, 0xb0, 0x6a, 0xfb, 0x77, 0x22, 0x65, 0x8f, 0x61, 0x1b, + 0xa7, 0x06, 0x33, 0x15, 0x8d, 0x79, 0xae, 0xe4, 0x94, 0x6b, 0x12, 0x23, 0x34, 0xda, 0x1d, 0xe8, + 0x87, 0xb7, 0xca, 0xe1, 0x99, 0x92, 0xd3, 0xb7, 0xc5, 0x88, 0xed, 0x80, 0x6f, 0x30, 0x4b, 0xa4, + 0x8a, 0xc6, 0x8b, 0x2b, 0x97, 0x3d, 0xdb, 0x03, 0xf8, 0x2c, 0xc7, 0xc8, 0xc7, 0x24, 0x46, 0x3a, + 0xd8, 0x70, 0xd3, 0x9a, 0x25, 0xaf, 0x2c, 0x60, 0x8f, 0xe0, 0x06, 0x26, 0xa9, 0x99, 0x71, 0x15, + 0x25, 0xa8, 0xd3, 0x48, 0xa0, 0x0e, 0x2a, 0xed, 0xb5, 0x6e, 0x2d, 0xdc, 0x72, 0xfc, 0x64, 0x89, + 0xad, 0xa3, 0x85, 0x13, 0x9a, 0x27, 0x14, 0x63, 0x50, 0x2d, 0x1c, 0x5d, 0xb0, 0xd7, 0x14, 0x23, + 0xbb, 0x0f, 0x9b, 0x8a, 0xb8, 0xc2, 0x09, 0x1f, 0xe1, 0x2c, 0x93, 0x6a, 0x10, 0xf8, 0x6e, 0x61, + 0x43, 0xd1, 0x09, 0x4e, 0x5e, 0x16, 0x8c, 0xed, 0x43, 0x5d, 0x0f, 0x65, 0x52, 0xfa, 0x5a, 0x73, + 0xef, 0x01, 0x8b, 0x0a, 0x53, 0xd9, 0x36, 0x54, 0x24, 0xf1, 0x5c, 0xc6, 0x01, 0xb4, 0xbd, 0x6e, + 0x33, 0xdc, 0x90, 0x74, 0x26, 0xe3, 0x05, 0x1e, 0xc8, 0x38, 0xa8, 0x97, 0xf8, 0x85, 0x8c, 0xed, + 0x52, 0x17, 0xe3, 0x84, 0xb2, 0x51, 0x91, 0x65, 0xc3, 0xbd, 0xb1, 0x61, 0xe9, 0x7b, 0xca, 0x46, + 0x2e, 0xcf, 0x87, 0xb0, 0xe5, 0x54, 0x32, 0x89, 0x06, 0x58, 0xc8, 0x9a, 0x4e, 0xd6, 0xb4, 0xf8, + 0xd8, 0x52, 0xab, 0xeb, 0x7c, 0x5f, 0x85, 0x9b, 0xfd, 0x21, 0x8a, 0x51, 0x4a, 0x52, 0x99, 0x32, + 0x54, 0x06, 0xeb, 0x38, 0x95, 0x65, 0x96, 0xae, 0xfe, 0x6f, 0x43, 0xdc, 0x85, 0xda, 0x95, 0x95, + 0x7e, 0xf1, 0x59, 0x4c, 0x4a, 0x1b, 0xf7, 0x00, 0xae, 0x39, 0x58, 0x44, 0x57, 0x93, 0x4b, 0xf7, + 0x9e, 0xc2, 0xe6, 0x69, 0x46, 0x02, 0xb5, 0x3e, 0x42, 0x13, 0xc9, 0xb1, 0x66, 0xf7, 0xa0, 0x8a, + 0x53, 0x14, 0x5c, 0xc6, 0xc5, 0x17, 0x7a, 0x08, 0xf3, 0xdf, 0xfb, 0x95, 0xe7, 0x53, 0x14, 0xc7, + 0x47, 0x61, 0xc5, 0x8e, 0x8e, 0xe3, 0xc3, 0x4f, 0x17, 0x97, 0xad, 0x95, 0x5f, 0x97, 0xad, 0x95, + 0xaf, 0xf3, 0x96, 0x77, 0x31, 0x6f, 0x79, 0x3f, 0xe7, 0x2d, 0xef, 0xcf, 0xbc, 0xe5, 0x7d, 0x3c, + 0xfc, 0xd7, 0x5f, 0xcc, 0xb3, 0x65, 0xf5, 0x61, 0xe5, 0xbc, 0xe2, 0xfe, 0x1e, 0x4f, 0xfe, 0x06, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x24, 0x6f, 0x2e, 0xb1, 0x04, 0x00, 0x00, +} + func (m *RuncOptions) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -105,45 +267,57 @@ } func (m *RuncOptions) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RuncOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Runtime) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.Runtime))) - i += copy(dAtA[i:], m.Runtime) - } - if len(m.RuntimeRoot) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.RuntimeRoot))) - i += copy(dAtA[i:], m.RuntimeRoot) - } - if len(m.CriuPath) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath))) - i += copy(dAtA[i:], m.CriuPath) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.SystemdCgroup { - dAtA[i] = 0x20 - i++ + i-- if m.SystemdCgroup { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 + } + if len(m.CriuPath) > 0 { + i -= len(m.CriuPath) + copy(dAtA[i:], m.CriuPath) + i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuPath))) + i-- + dAtA[i] = 0x1a + } + if len(m.RuntimeRoot) > 0 { + i -= len(m.RuntimeRoot) + copy(dAtA[i:], m.RuntimeRoot) + i = encodeVarintRunc(dAtA, i, uint64(len(m.RuntimeRoot))) + i-- + dAtA[i] = 0x12 + } + if len(m.Runtime) > 0 { + i -= len(m.Runtime) + copy(dAtA[i:], m.Runtime) + i = encodeVarintRunc(dAtA, i, uint64(len(m.Runtime))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CreateOptions) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -151,114 +325,133 @@ } func (m *CreateOptions) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.NoPivotRoot { - dAtA[i] = 0x8 - i++ - if m.NoPivotRoot { + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.CriuImagePath) > 0 { + i -= len(m.CriuImagePath) + copy(dAtA[i:], m.CriuImagePath) + i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuImagePath))) + i-- + dAtA[i] = 0x6a + } + if len(m.CriuWorkPath) > 0 { + i -= len(m.CriuWorkPath) + copy(dAtA[i:], m.CriuWorkPath) + i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuWorkPath))) + i-- + dAtA[i] = 0x62 + } + if m.IoGid != 0 { + i = encodeVarintRunc(dAtA, i, uint64(m.IoGid)) + i-- + dAtA[i] = 0x58 + } + if m.IoUid != 0 { + i = encodeVarintRunc(dAtA, i, uint64(m.IoUid)) + i-- + dAtA[i] = 0x50 + } + if len(m.ShimCgroup) > 0 { + i -= len(m.ShimCgroup) + copy(dAtA[i:], m.ShimCgroup) + i = encodeVarintRunc(dAtA, i, uint64(len(m.ShimCgroup))) + i-- + dAtA[i] = 0x4a + } + if m.NoNewKeyring { + i-- + if m.NoNewKeyring { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x40 } - if m.OpenTcp { - dAtA[i] = 0x10 - i++ - if m.OpenTcp { - dAtA[i] = 1 - } else { - dAtA[i] = 0 + if len(m.CgroupsMode) > 0 { + i -= len(m.CgroupsMode) + copy(dAtA[i:], m.CgroupsMode) + i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode))) + i-- + dAtA[i] = 0x3a + } + if len(m.EmptyNamespaces) > 0 { + for iNdEx := len(m.EmptyNamespaces) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EmptyNamespaces[iNdEx]) + copy(dAtA[i:], m.EmptyNamespaces[iNdEx]) + i = encodeVarintRunc(dAtA, i, uint64(len(m.EmptyNamespaces[iNdEx]))) + i-- + dAtA[i] = 0x32 } - i++ } - if m.ExternalUnixSockets { - dAtA[i] = 0x18 - i++ - if m.ExternalUnixSockets { + if m.FileLocks { + i-- + if m.FileLocks { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x28 } if m.Terminal { - dAtA[i] = 0x20 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 } - if m.FileLocks { - dAtA[i] = 0x28 - i++ - if m.FileLocks { + if m.ExternalUnixSockets { + i-- + if m.ExternalUnixSockets { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 } - if len(m.EmptyNamespaces) > 0 { - for _, s := range m.EmptyNamespaces { - dAtA[i] = 0x32 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) + if m.OpenTcp { + i-- + if m.OpenTcp { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x10 } - if len(m.CgroupsMode) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode))) - i += copy(dAtA[i:], m.CgroupsMode) - } - if m.NoNewKeyring { - dAtA[i] = 0x40 - i++ - if m.NoNewKeyring { + if m.NoPivotRoot { + i-- + if m.NoPivotRoot { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.ShimCgroup) > 0 { - dAtA[i] = 0x4a - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.ShimCgroup))) - i += copy(dAtA[i:], m.ShimCgroup) - } - if m.IoUid != 0 { - dAtA[i] = 0x50 - i++ - i = encodeVarintRunc(dAtA, i, uint64(m.IoUid)) - } - if m.IoGid != 0 { - dAtA[i] = 0x58 - i++ - i = encodeVarintRunc(dAtA, i, uint64(m.IoGid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointOptions) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -266,88 +459,106 @@ } func (m *CheckpointOptions) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Exit { - dAtA[i] = 0x8 - i++ - if m.Exit { + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.ImagePath) > 0 { + i -= len(m.ImagePath) + copy(dAtA[i:], m.ImagePath) + i = encodeVarintRunc(dAtA, i, uint64(len(m.ImagePath))) + i-- + dAtA[i] = 0x4a + } + if len(m.WorkPath) > 0 { + i -= len(m.WorkPath) + copy(dAtA[i:], m.WorkPath) + i = encodeVarintRunc(dAtA, i, uint64(len(m.WorkPath))) + i-- + dAtA[i] = 0x42 + } + if len(m.CgroupsMode) > 0 { + i -= len(m.CgroupsMode) + copy(dAtA[i:], m.CgroupsMode) + i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode))) + i-- + dAtA[i] = 0x3a + } + if len(m.EmptyNamespaces) > 0 { + for iNdEx := len(m.EmptyNamespaces) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EmptyNamespaces[iNdEx]) + copy(dAtA[i:], m.EmptyNamespaces[iNdEx]) + i = encodeVarintRunc(dAtA, i, uint64(len(m.EmptyNamespaces[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if m.FileLocks { + i-- + if m.FileLocks { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x28 } - if m.OpenTcp { - dAtA[i] = 0x10 - i++ - if m.OpenTcp { + if m.Terminal { + i-- + if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 } if m.ExternalUnixSockets { - dAtA[i] = 0x18 - i++ + i-- if m.ExternalUnixSockets { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 } - if m.Terminal { - dAtA[i] = 0x20 - i++ - if m.Terminal { + if m.OpenTcp { + i-- + if m.OpenTcp { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 } - if m.FileLocks { - dAtA[i] = 0x28 - i++ - if m.FileLocks { + if m.Exit { + i-- + if m.Exit { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.EmptyNamespaces) > 0 { - for _, s := range m.EmptyNamespaces { - dAtA[i] = 0x32 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } - } - if len(m.CgroupsMode) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode))) - i += copy(dAtA[i:], m.CgroupsMode) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *ProcessDetails) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -355,29 +566,44 @@ } func (m *ProcessDetails) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProcessDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ExecID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintRunc(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintRunc(dAtA []byte, offset int, v uint64) int { + offset -= sovRunc(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *RuncOptions) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Runtime) @@ -395,10 +621,16 @@ if m.SystemdCgroup { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateOptions) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.NoPivotRoot { @@ -439,10 +671,24 @@ if m.IoGid != 0 { n += 1 + sovRunc(uint64(m.IoGid)) } + l = len(m.CriuWorkPath) + if l > 0 { + n += 1 + l + sovRunc(uint64(l)) + } + l = len(m.CriuImagePath) + if l > 0 { + n += 1 + l + sovRunc(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointOptions) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Exit { @@ -470,28 +716,38 @@ if l > 0 { n += 1 + l + sovRunc(uint64(l)) } + l = len(m.WorkPath) + if l > 0 { + n += 1 + l + sovRunc(uint64(l)) + } + l = len(m.ImagePath) + if l > 0 { + n += 1 + l + sovRunc(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ProcessDetails) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ExecID) if l > 0 { n += 1 + l + sovRunc(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovRunc(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozRunc(x uint64) (n int) { return sovRunc(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -505,6 +761,7 @@ `RuntimeRoot:` + fmt.Sprintf("%v", this.RuntimeRoot) + `,`, `CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`, `SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -525,6 +782,9 @@ `ShimCgroup:` + fmt.Sprintf("%v", this.ShimCgroup) + `,`, `IoUid:` + fmt.Sprintf("%v", this.IoUid) + `,`, `IoGid:` + fmt.Sprintf("%v", this.IoGid) + `,`, + `CriuWorkPath:` + fmt.Sprintf("%v", this.CriuWorkPath) + `,`, + `CriuImagePath:` + fmt.Sprintf("%v", this.CriuImagePath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -541,6 +801,9 @@ `FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`, `EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`, `CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`, + `WorkPath:` + fmt.Sprintf("%v", this.WorkPath) + `,`, + `ImagePath:` + fmt.Sprintf("%v", this.ImagePath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -551,6 +814,7 @@ } s := strings.Join([]string{`&ProcessDetails{`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -578,7 +842,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -606,7 +870,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -616,6 +880,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -635,7 +902,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -645,6 +912,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -664,7 +934,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -674,6 +944,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -693,7 +966,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -705,12 +978,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthRunc } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -735,7 +1009,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -763,7 +1037,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -783,7 +1057,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -803,7 +1077,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -823,7 +1097,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -843,7 +1117,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -863,7 +1137,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -873,6 +1147,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -892,7 +1169,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -902,6 +1179,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -921,7 +1201,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -941,7 +1221,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -951,6 +1231,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -970,7 +1253,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.IoUid |= (uint32(b) & 0x7F) << shift + m.IoUid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -989,23 +1272,88 @@ } b := dAtA[iNdEx] iNdEx++ - m.IoGid |= (uint32(b) & 0x7F) << shift + m.IoGid |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CriuWorkPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRunc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRunc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CriuWorkPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CriuImagePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRunc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRunc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CriuImagePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRunc(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthRunc } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1030,7 +1378,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1058,7 +1406,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1078,7 +1426,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1098,7 +1446,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1118,7 +1466,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1138,7 +1486,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1158,7 +1506,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1168,6 +1516,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1187,7 +1538,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1197,23 +1548,91 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } m.CgroupsMode = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WorkPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRunc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRunc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WorkPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ImagePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRunc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRunc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ImagePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRunc(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthRunc } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1238,7 +1657,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1266,7 +1685,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1276,6 +1695,9 @@ return ErrInvalidLengthRunc } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRunc + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1287,12 +1709,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthRunc } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -1305,6 +1728,7 @@ func skipRunc(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1336,10 +1760,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1356,95 +1778,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthRunc } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRunc - } - 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 := skipRunc(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRunc + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthRunc + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthRunc = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowRunc = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthRunc = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRunc = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRunc = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/runtime/linux/runctypes/runc.proto", fileDescriptorRunc) -} - -var fileDescriptorRunc = []byte{ - // 541 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x86, 0x6b, 0xda, 0x26, 0xce, 0xa4, 0x29, 0xb0, 0x50, 0xc9, 0x14, 0x91, 0x86, 0x00, 0x52, - 0xb8, 0xa4, 0x12, 0x88, 0x13, 0xb7, 0xa6, 0x08, 0x55, 0x40, 0xa9, 0x0c, 0x95, 0x10, 0x42, 0x5a, - 0xb9, 0xeb, 0x21, 0x59, 0xc5, 0xde, 0x59, 0x79, 0xd7, 0xd4, 0xb9, 0xf5, 0x09, 0x78, 0xae, 0x1e, - 0x39, 0x72, 0x42, 0x34, 0x2f, 0x02, 0xf2, 0xda, 0x0e, 0x9c, 0x39, 0x72, 0xfb, 0xe7, 0xfb, 0xc7, - 0x9e, 0xd1, 0xbf, 0x1a, 0x98, 0x4c, 0xa5, 0x9d, 0xe5, 0x67, 0x63, 0x41, 0xe9, 0xbe, 0x20, 0x65, - 0x23, 0xa9, 0x30, 0x8b, 0xff, 0x96, 0x59, 0xae, 0xac, 0x4c, 0x71, 0x3f, 0x91, 0x2a, 0x2f, 0xca, - 0x4a, 0xd8, 0x85, 0x46, 0xe3, 0xd4, 0x58, 0x67, 0x64, 0x89, 0xed, 0xfc, 0x69, 0x1f, 0xbb, 0xb6, - 0x71, 0x69, 0xee, 0xde, 0x9e, 0xd2, 0x94, 0x5c, 0xc7, 0x7e, 0xa9, 0xaa, 0xe6, 0xe1, 0x57, 0x0f, - 0xba, 0x61, 0xae, 0xc4, 0x5b, 0x6d, 0x25, 0x29, 0xc3, 0x02, 0x68, 0xd7, 0x23, 0x02, 0x6f, 0xe0, - 0x8d, 0x3a, 0x61, 0x53, 0xb2, 0xfb, 0xb0, 0x55, 0x4b, 0x9e, 0x11, 0xd9, 0xe0, 0x9a, 0xb3, 0xbb, - 0x35, 0x0b, 0x89, 0x2c, 0xbb, 0x0b, 0x1d, 0x91, 0xc9, 0x9c, 0xeb, 0xc8, 0xce, 0x82, 0x75, 0xe7, - 0xfb, 0x25, 0x38, 0x89, 0xec, 0x8c, 0x3d, 0x82, 0x6d, 0xb3, 0x30, 0x16, 0xd3, 0x98, 0x8b, 0x69, - 0x46, 0xb9, 0x0e, 0x36, 0x06, 0xde, 0xc8, 0x0f, 0x7b, 0x35, 0x9d, 0x38, 0x38, 0xbc, 0x58, 0x87, - 0xde, 0x24, 0xc3, 0xc8, 0x62, 0xb3, 0xd2, 0x10, 0x7a, 0x8a, 0xb8, 0x96, 0x5f, 0xc8, 0x56, 0x93, - 0x3d, 0xf7, 0x5d, 0x57, 0xd1, 0x49, 0xc9, 0xdc, 0xe4, 0x3b, 0xe0, 0x93, 0x46, 0xc5, 0xad, 0xd0, - 0x6e, 0x31, 0x3f, 0x6c, 0x97, 0xf5, 0x7b, 0xa1, 0xd9, 0x13, 0xd8, 0xc1, 0xc2, 0x62, 0xa6, 0xa2, - 0x84, 0xe7, 0x4a, 0x16, 0xdc, 0x90, 0x98, 0xa3, 0x35, 0x6e, 0x41, 0x3f, 0xbc, 0xd5, 0x98, 0xa7, - 0x4a, 0x16, 0xef, 0x2a, 0x8b, 0xed, 0x82, 0x6f, 0x31, 0x4b, 0xa5, 0x8a, 0x92, 0x7a, 0xcb, 0x55, - 0xcd, 0xee, 0x01, 0x7c, 0x96, 0x09, 0xf2, 0x84, 0xc4, 0xdc, 0x04, 0x9b, 0xce, 0xed, 0x94, 0xe4, - 0x75, 0x09, 0xd8, 0x63, 0xb8, 0x81, 0xa9, 0xb6, 0x0b, 0xae, 0xa2, 0x14, 0x8d, 0x8e, 0x04, 0x9a, - 0xa0, 0x35, 0x58, 0x1f, 0x75, 0xc2, 0xeb, 0x8e, 0x1f, 0xaf, 0x70, 0x99, 0x68, 0x95, 0x84, 0xe1, - 0x29, 0xc5, 0x18, 0xb4, 0xab, 0x44, 0x6b, 0xf6, 0x86, 0x62, 0x64, 0x0f, 0x61, 0x5b, 0x11, 0x57, - 0x78, 0xce, 0xe7, 0xb8, 0xc8, 0xa4, 0x9a, 0x06, 0xbe, 0x1b, 0xb8, 0xa5, 0xe8, 0x18, 0xcf, 0x5f, - 0x55, 0x8c, 0xed, 0x41, 0xd7, 0xcc, 0x64, 0xda, 0xe4, 0xda, 0x71, 0xff, 0x81, 0x12, 0x55, 0xa1, - 0xb2, 0x1d, 0x68, 0x49, 0xe2, 0xb9, 0x8c, 0x03, 0x18, 0x78, 0xa3, 0x5e, 0xb8, 0x29, 0xe9, 0x54, - 0xc6, 0x35, 0x9e, 0xca, 0x38, 0xe8, 0x36, 0xf8, 0xa5, 0x8c, 0x87, 0xbf, 0x3c, 0xb8, 0x39, 0x99, - 0xa1, 0x98, 0x6b, 0x92, 0xca, 0x36, 0xcf, 0xc0, 0x60, 0x03, 0x0b, 0xd9, 0xa4, 0xef, 0xf4, 0xff, - 0x1a, 0xfb, 0xf0, 0x19, 0x6c, 0x9f, 0x64, 0x24, 0xd0, 0x98, 0x43, 0xb4, 0x91, 0x4c, 0x0c, 0x7b, - 0x00, 0x6d, 0x2c, 0x50, 0x70, 0x19, 0x57, 0x77, 0x71, 0x00, 0xcb, 0x1f, 0x7b, 0xad, 0x17, 0x05, - 0x8a, 0xa3, 0xc3, 0xb0, 0x55, 0x5a, 0x47, 0xf1, 0xc1, 0xa7, 0xcb, 0xab, 0xfe, 0xda, 0xf7, 0xab, - 0xfe, 0xda, 0xc5, 0xb2, 0xef, 0x5d, 0x2e, 0xfb, 0xde, 0xb7, 0x65, 0xdf, 0xfb, 0xb9, 0xec, 0x7b, - 0x1f, 0x0f, 0xfe, 0xf5, 0xb0, 0x9f, 0xaf, 0xd4, 0x87, 0xb5, 0xb3, 0x96, 0xbb, 0xd9, 0xa7, 0xbf, - 0x03, 0x00, 0x00, 0xff, 0xff, 0x18, 0xa1, 0x4b, 0x5b, 0x27, 0x04, 0x00, 0x00, -} diff -Nru containerd-1.2.6/runtime/linux/runctypes/runc.proto containerd-1.5.9/runtime/linux/runctypes/runc.proto --- containerd-1.2.6/runtime/linux/runctypes/runc.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/linux/runctypes/runc.proto 2022-01-05 17:30:58.000000000 +0000 @@ -25,6 +25,8 @@ string shim_cgroup = 9; uint32 io_uid = 10; uint32 io_gid = 11; + string criu_work_path = 12; + string criu_image_path = 13; } message CheckpointOptions { @@ -35,6 +37,8 @@ bool file_locks = 5; repeated string empty_namespaces = 6; string cgroups_mode = 7; + string work_path = 8; + string image_path = 9; } message ProcessDetails { diff -Nru containerd-1.2.6/runtime/opts/opts_linux.go containerd-1.5.9/runtime/opts/opts_linux.go --- containerd-1.2.6/runtime/opts/opts_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/opts/opts_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package opts + +import ( + "context" + + "github.com/containerd/cgroups" + cgroupsv2 "github.com/containerd/cgroups/v2" + "github.com/containerd/containerd/namespaces" +) + +// WithNamespaceCgroupDeletion removes the cgroup directory that was created for the namespace +func WithNamespaceCgroupDeletion(ctx context.Context, i *namespaces.DeleteInfo) error { + if cgroups.Mode() == cgroups.Unified { + cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", i.Name) + if err != nil { + if err == cgroupsv2.ErrCgroupDeleted { + return nil + } + return err + } + return cg.Delete() + } + cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(i.Name)) + if err != nil { + if err == cgroups.ErrCgroupDeleted { + return nil + } + return err + } + return cg.Delete() +} diff -Nru containerd-1.2.6/runtime/proc/proc.go containerd-1.5.9/runtime/proc/proc.go --- containerd-1.2.6/runtime/proc/proc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/proc/proc.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - "io" - "sync" - "time" - - "github.com/containerd/console" -) - -// Stdio of a process -type Stdio struct { - Stdin string - Stdout string - Stderr string - Terminal bool -} - -// IsNull returns true if the stdio is not defined -func (s Stdio) IsNull() bool { - return s.Stdin == "" && s.Stdout == "" && s.Stderr == "" -} - -// Process on a system -type Process interface { - // ID returns the id for the process - ID() string - // Pid returns the pid for the process - Pid() int - // ExitStatus returns the exit status - ExitStatus() int - // ExitedAt is the time the process exited - ExitedAt() time.Time - // Stdin returns the process STDIN - Stdin() io.Closer - // Stdio returns io information for the container - Stdio() Stdio - // Status returns the process status - Status(context.Context) (string, error) - // Wait blocks until the process has exited - Wait() - // Resize resizes the process console - Resize(ws console.WinSize) error - // Start execution of the process - Start(context.Context) error - // Delete deletes the process and its resourcess - Delete(context.Context) error - // Kill kills the process - Kill(context.Context, uint32, bool) error - // SetExited sets the exit status for the process - SetExited(status int) -} - -// Platform handles platform-specific behavior that may differs across -// platform implementations -type Platform interface { - CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, - wg, cwg *sync.WaitGroup) (console.Console, error) - ShutdownConsole(ctx context.Context, console console.Console) error - Close() error -} diff -Nru containerd-1.2.6/runtime/restart/monitor/change.go containerd-1.5.9/runtime/restart/monitor/change.go --- containerd-1.2.6/runtime/restart/monitor/change.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/restart/monitor/change.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,10 +18,13 @@ import ( "context" + "net/url" "syscall" "github.com/containerd/containerd" "github.com/containerd/containerd/cio" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) type stopChange struct { @@ -34,14 +37,30 @@ type startChange struct { container containerd.Container - logPath string + logURI string + + // Deprecated(in release 1.5): but recognized now, prefer to use logURI + logPath string } func (s *startChange) apply(ctx context.Context, client *containerd.Client) error { log := cio.NullIO - if s.logPath != "" { + + if s.logURI != "" { + uri, err := url.Parse(s.logURI) + if err != nil { + return errors.Wrapf(err, "failed to parse %v into url", s.logURI) + } + log = cio.LogURI(uri) + } else if s.logPath != "" { log = cio.LogFile(s.logPath) } + + if s.logURI != "" && s.logPath != "" { + logrus.Warnf("LogPathLabel=%v has been deprecated, using LogURILabel=%v", + s.logPath, s.logURI) + } + killTask(ctx, s.container) task, err := s.container.NewTask(ctx, log) if err != nil { diff -Nru containerd-1.2.6/runtime/restart/monitor/monitor.go containerd-1.5.9/runtime/restart/monitor/monitor.go --- containerd-1.2.6/runtime/restart/monitor/monitor.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/restart/monitor/monitor.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,7 @@ import ( "context" "fmt" + "sync" "time" "github.com/containerd/containerd" @@ -152,10 +153,10 @@ interval = 10 * time.Second } for { - time.Sleep(interval) if err := m.reconcile(context.Background()); err != nil { logrus.WithError(err).Error("reconcile") } + time.Sleep(interval) } } @@ -164,19 +165,33 @@ if err != nil { return err } + var wgNSLoop sync.WaitGroup for _, name := range ns { - ctx = namespaces.WithNamespace(ctx, name) - changes, err := m.monitor(ctx) - if err != nil { - logrus.WithError(err).Error("monitor for changes") - continue - } - for _, c := range changes { - if err := c.apply(ctx, m.client); err != nil { - logrus.WithError(err).Error("apply change") + name := name + wgNSLoop.Add(1) + go func() { + defer wgNSLoop.Done() + ctx := namespaces.WithNamespace(ctx, name) + changes, err := m.monitor(ctx) + if err != nil { + logrus.WithError(err).Error("monitor for changes") + return } - } + var wgChangesLoop sync.WaitGroup + for _, c := range changes { + c := c + wgChangesLoop.Add(1) + go func() { + defer wgChangesLoop.Done() + if err := c.apply(ctx, m.client); err != nil { + logrus.WithError(err).Error("apply change") + } + }() + } + wgChangesLoop.Wait() + }() } + wgNSLoop.Wait() return nil } @@ -200,6 +215,7 @@ changes = append(changes, &startChange{ container: c, logPath: labels[restart.LogPathLabel], + logURI: labels[restart.LogURILabel], }) case containerd.Stopped: changes = append(changes, &stopChange{ diff -Nru containerd-1.2.6/runtime/restart/restart.go containerd-1.5.9/runtime/restart/restart.go --- containerd-1.2.6/runtime/restart/restart.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/restart/restart.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,19 +31,68 @@ import ( "context" + "net/url" "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" "github.com/containerd/containerd/containers" ) const ( // StatusLabel sets the restart status label for a container StatusLabel = "containerd.io/restart.status" + // LogURILabel sets the restart log uri label for a container + LogURILabel = "containerd.io/restart.loguri" + // LogPathLabel sets the restart log path label for a container + // + // Deprecated(in release 1.5): use LogURILabel LogPathLabel = "containerd.io/restart.logpath" ) +// WithLogURI sets the specified log uri for a container. +func WithLogURI(uri *url.URL) func(context.Context, *containerd.Client, *containers.Container) error { + return WithLogURIString(uri.String()) +} + +// WithLogURIString sets the specified log uri string for a container. +func WithLogURIString(uriString string) func(context.Context, *containerd.Client, *containers.Container) error { + return func(_ context.Context, _ *containerd.Client, c *containers.Container) error { + ensureLabels(c) + c.Labels[LogURILabel] = uriString + return nil + } +} + +// WithBinaryLogURI sets the binary-type log uri for a container. +// +// Deprecated(in release 1.5): use WithLogURI +func WithBinaryLogURI(binary string, args map[string]string) func(context.Context, *containerd.Client, *containers.Container) error { + uri, err := cio.LogURIGenerator("binary", binary, args) + if err != nil { + return func(context.Context, *containerd.Client, *containers.Container) error { + return err + } + } + return WithLogURI(uri) +} + +// WithFileLogURI sets the file-type log uri for a container. +// +// Deprecated(in release 1.5): use WithLogURI +func WithFileLogURI(path string) func(context.Context, *containerd.Client, *containers.Container) error { + uri, err := cio.LogURIGenerator("file", path, nil) + if err != nil { + return func(context.Context, *containerd.Client, *containers.Container) error { + return err + } + } + return WithLogURI(uri) +} + // WithLogPath sets the log path for a container +// +// Deprecated(in release 1.5): use WithLogURI with "file://" URI. func WithLogPath(path string) func(context.Context, *containerd.Client, *containers.Container) error { return func(_ context.Context, _ *containerd.Client, c *containers.Container) error { ensureLabels(c) @@ -68,6 +117,7 @@ } delete(c.Labels, StatusLabel) delete(c.Labels, LogPathLabel) + delete(c.Labels, LogURILabel) return nil } diff -Nru containerd-1.2.6/runtime/runtime.go containerd-1.5.9/runtime/runtime.go --- containerd-1.2.6/runtime/runtime.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/runtime.go 2022-01-05 17:30:58.000000000 +0000 @@ -63,14 +63,14 @@ // ID of the runtime ID() string // Create creates a task with the provided id and options. - Create(ctx context.Context, id string, opts CreateOpts) (Task, error) + Create(ctx context.Context, taskID string, opts CreateOpts) (Task, error) // Get returns a task. - Get(context.Context, string) (Task, error) + Get(ctx context.Context, taskID string) (Task, error) // Tasks returns all the current tasks for the runtime. // Any container runs at most one task at a time. - Tasks(context.Context, bool) ([]Task, error) + Tasks(ctx context.Context, all bool) ([]Task, error) // Add adds a task into runtime. - Add(context.Context, Task) error + Add(ctx context.Context, task Task) error // Delete remove a task. - Delete(context.Context, string) + Delete(ctx context.Context, taskID string) } diff -Nru containerd-1.2.6/runtime/task.go containerd-1.5.9/runtime/task.go --- containerd-1.2.6/runtime/task.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/task.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,45 +33,48 @@ // Process is a runtime object for an executing process inside a container type Process interface { + // ID of the process ID() string // State returns the process state - State(context.Context) (State, error) + State(ctx context.Context) (State, error) // Kill signals a container - Kill(context.Context, uint32, bool) error - // Pty resizes the processes pty/console - ResizePty(context.Context, ConsoleSize) error - // CloseStdin closes the processes stdin - CloseIO(context.Context) error + Kill(ctx context.Context, signal uint32, all bool) error + // ResizePty resizes the processes pty/console + ResizePty(ctx context.Context, size ConsoleSize) error + // CloseIO closes the processes IO + CloseIO(ctx context.Context) error // Start the container's user defined process - Start(context.Context) error + Start(ctx context.Context) error // Wait for the process to exit - Wait(context.Context) (*Exit, error) + Wait(ctx context.Context) (*Exit, error) // Delete deletes the process - Delete(context.Context) (*Exit, error) + Delete(ctx context.Context) (*Exit, error) } // Task is the runtime object for an executing container type Task interface { Process + // PID of the process + PID() uint32 // Namespace that the task exists in Namespace() string // Pause pauses the container process - Pause(context.Context) error + Pause(ctx context.Context) error // Resume unpauses the container process - Resume(context.Context) error + Resume(ctx context.Context) error // Exec adds a process into the container - Exec(context.Context, string, ExecOpts) (Process, error) + Exec(ctx context.Context, id string, opts ExecOpts) (Process, error) // Pids returns all pids - Pids(context.Context) ([]ProcessInfo, error) + Pids(ctx context.Context) ([]ProcessInfo, error) // Checkpoint checkpoints a container to an image with live system data - Checkpoint(context.Context, string, *types.Any) error + Checkpoint(ctx context.Context, path string, opts *types.Any) error // Update sets the provided resources to a running task - Update(context.Context, *types.Any) error + Update(ctx context.Context, resources *types.Any, annotations map[string]string) error // Process returns a process within the task for the provided id - Process(context.Context, string) (Process, error) + Process(ctx context.Context, id string) (Process, error) // Stats returns runtime specific metrics for a task - Stats(context.Context) (*types.Any, error) + Stats(ctx context.Context) (*types.Any, error) } // ExecOpts provides additional options for additional processes running in a task diff -Nru containerd-1.2.6/runtime/v1/linux/bundle.go containerd-1.5.9/runtime/v1/linux/bundle.go --- containerd-1.2.6/runtime/v1/linux/bundle.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/bundle.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,9 @@ import ( "context" + "crypto/sha256" + "encoding/json" + "fmt" "io/ioutil" "os" "path/filepath" @@ -28,6 +31,7 @@ "github.com/containerd/containerd/runtime/linux/runctypes" "github.com/containerd/containerd/runtime/v1/shim" "github.com/containerd/containerd/runtime/v1/shim/client" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -46,7 +50,7 @@ return nil, err } path = filepath.Join(path, id) - if err := os.Mkdir(path, 0711); err != nil { + if err := os.Mkdir(path, 0700); err != nil { return nil, err } defer func() { @@ -54,6 +58,9 @@ os.RemoveAll(path) } }() + if err := prepareBundleDirectoryPermissions(path, spec); err != nil { + return nil, err + } workDir = filepath.Join(workDir, id) if err := os.MkdirAll(workDir, 0711); err != nil { return nil, err @@ -63,7 +70,8 @@ os.RemoveAll(workDir) } }() - if err := os.Mkdir(filepath.Join(path, "rootfs"), 0711); err != nil { + rootfs := filepath.Join(path, "rootfs") + if err := os.MkdirAll(rootfs, 0711); err != nil { return nil, err } err = ioutil.WriteFile(filepath.Join(path, configFilename), spec, 0666) @@ -74,6 +82,55 @@ }, err } +// prepareBundleDirectoryPermissions prepares the permissions of the bundle +// directory. When user namespaces are enabled, the permissions are modified +// to allow the remapped root GID to access the bundle. +func prepareBundleDirectoryPermissions(path string, spec []byte) error { + gid, err := remappedGID(spec) + if err != nil { + return err + } + if gid == 0 { + return nil + } + if err := os.Chown(path, -1, int(gid)); err != nil { + return err + } + return os.Chmod(path, 0710) +} + +// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during +// unmarshal. +type ociSpecUserNS struct { + Linux *linuxSpecUserNS +} + +// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during +// unmarshal. +type linuxSpecUserNS struct { + GIDMappings []specs.LinuxIDMapping +} + +// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If +// there is no remapping, remappedGID returns 0. If the spec cannot be parsed, +// remappedGID returns an error. +func remappedGID(spec []byte) (uint32, error) { + var ociSpec ociSpecUserNS + err := json.Unmarshal(spec, &ociSpec) + if err != nil { + return 0, err + } + if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 { + return 0, nil + } + for _, mapping := range ociSpec.Linux.GIDMappings { + if mapping.ContainerID == 0 { + return mapping.HostID, nil + } + } + return 0, nil +} + type bundle struct { id string path string @@ -88,7 +145,7 @@ return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { config := b.shimConfig(ns, c, ropts) return config, - client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler) + client.WithStart(c.Shim, b.shimAddress(ns, daemonAddress), daemonAddress, cgroup, c.ShimDebug, exitHandler) } } @@ -102,7 +159,7 @@ // ShimConnect is a ShimOpt for connecting to an existing remote shim func ShimConnect(c *Config, onClose func()) ShimOpt { return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { - return b.shimConfig(ns, c, ropts), client.WithConnect(b.shimAddress(ns), onClose) + return b.shimConfig(ns, c, ropts), client.WithConnect(b.decideShimAddress(ns), onClose) } } @@ -114,22 +171,51 @@ // Delete deletes the bundle from disk func (b *bundle) Delete() error { - err := os.RemoveAll(b.path) + address, _ := b.loadAddress() + if address != "" { + // we don't care about errors here + client.RemoveSocket(address) + } + err := atomicDelete(b.path) if err == nil { - return os.RemoveAll(b.workDir) + return atomicDelete(b.workDir) } // error removing the bundle path; still attempt removing work dir - err2 := os.RemoveAll(b.workDir) + err2 := atomicDelete(b.workDir) if err2 == nil { return err } return errors.Wrapf(err, "Failed to remove both bundle and workdir locations: %v", err2) } -func (b *bundle) shimAddress(namespace string) string { +func (b *bundle) legacyShimAddress(namespace string) string { return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock") } +const socketRoot = "/run/containerd" + +func (b *bundle) shimAddress(namespace, socketPath string) string { + d := sha256.Sum256([]byte(filepath.Join(socketPath, namespace, b.id))) + return fmt.Sprintf("unix://%s/%x", filepath.Join(socketRoot, "s"), d) +} + +func (b *bundle) loadAddress() (string, error) { + addressPath := filepath.Join(b.path, "address") + data, err := ioutil.ReadFile(addressPath) + if err != nil { + return "", err + } + return string(data), nil +} + +func (b *bundle) decideShimAddress(namespace string) string { + address, err := b.loadAddress() + if err != nil { + return b.legacyShimAddress(namespace) + } + return address +} + func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config { var ( criuPath string @@ -152,3 +238,16 @@ SystemdCgroup: systemdCgroup, } } + +// atomicDelete renames the path to a hidden file before removal +func atomicDelete(path string) error { + // create a hidden dir for an atomic removal + atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) + if err := os.Rename(path, atomicPath); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + return os.RemoveAll(atomicPath) +} diff -Nru containerd-1.2.6/runtime/v1/linux/bundle_test.go containerd-1.5.9/runtime/v1/linux/bundle_test.go --- containerd-1.2.6/runtime/v1/linux/bundle_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/bundle_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,145 @@ +//go:build linux +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package linux + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "syscall" + "testing" + + "github.com/containerd/containerd/oci" + "github.com/containerd/continuity/testutil" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewBundle(t *testing.T) { + testutil.RequiresRoot(t) + tests := []struct { + userns bool + }{{ + userns: false, + }, { + userns: true, + }} + const usernsGID = 4200 + + for i, tc := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + dir, err := ioutil.TempDir("", "test-new-bundle") + require.NoError(t, err, "failed to create test directory") + defer os.RemoveAll(dir) + work := filepath.Join(dir, "work") + state := filepath.Join(dir, "state") + id := fmt.Sprintf("new-bundle-%d", i) + spec := oci.Spec{} + if tc.userns { + spec.Linux = &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}}, + } + } + specBytes, err := json.Marshal(&spec) + require.NoError(t, err, "failed to marshal spec") + + b, err := newBundle(id, work, state, specBytes) + require.NoError(t, err, "newBundle should succeed") + require.NotNil(t, b, "bundle should not be nil") + + fi, err := os.Stat(b.path) + assert.NoError(t, err, "should be able to stat bundle path") + if tc.userns { + assert.Equal(t, os.ModeDir|0710, fi.Mode(), "bundle path should be a directory with perm 0710") + } else { + assert.Equal(t, os.ModeDir|0700, fi.Mode(), "bundle path should be a directory with perm 0700") + } + stat, ok := fi.Sys().(*syscall.Stat_t) + require.True(t, ok, "should assert to *syscall.Stat_t") + expectedGID := uint32(0) + if tc.userns { + expectedGID = usernsGID + } + assert.Equal(t, expectedGID, stat.Gid, "gid should match") + + }) + } +} + +func TestRemappedGID(t *testing.T) { + tests := []struct { + spec oci.Spec + gid uint32 + }{{ + // empty spec + spec: oci.Spec{}, + gid: 0, + }, { + // empty Linux section + spec: oci.Spec{ + Linux: &specs.Linux{}, + }, + gid: 0, + }, { + // empty ID mappings + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: make([]specs.LinuxIDMapping, 0), + }, + }, + gid: 0, + }, { + // valid ID mapping + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ + ContainerID: 0, + HostID: 1000, + }}, + }, + }, + gid: 1000, + }, { + // missing ID mapping + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ + ContainerID: 100, + HostID: 1000, + }}, + }, + }, + gid: 0, + }} + + for i, tc := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + s, err := json.Marshal(tc.spec) + require.NoError(t, err, "failed to marshal spec") + gid, err := remappedGID(s) + assert.NoError(t, err, "should unmarshal successfully") + assert.Equal(t, tc.gid, gid, "expected GID to match") + }) + } +} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/deleted_state.go containerd-1.5.9/runtime/v1/linux/proc/deleted_state.go --- containerd-1.2.6/runtime/v1/linux/proc/deleted_state.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/deleted_state.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - - "github.com/containerd/console" - "github.com/containerd/containerd/runtime/proc" - google_protobuf "github.com/gogo/protobuf/types" - "github.com/pkg/errors" -) - -type deletedState struct { -} - -func (s *deletedState) Pause(ctx context.Context) error { - return errors.Errorf("cannot pause a deleted process") -} - -func (s *deletedState) Resume(ctx context.Context) error { - return errors.Errorf("cannot resume a deleted process") -} - -func (s *deletedState) Update(context context.Context, r *google_protobuf.Any) error { - return errors.Errorf("cannot update a deleted process") -} - -func (s *deletedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return errors.Errorf("cannot checkpoint a deleted process") -} - -func (s *deletedState) Resize(ws console.WinSize) error { - return errors.Errorf("cannot resize a deleted process") -} - -func (s *deletedState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a deleted process") -} - -func (s *deletedState) Delete(ctx context.Context) error { - return errors.Errorf("cannot delete a deleted process") -} - -func (s *deletedState) Kill(ctx context.Context, sig uint32, all bool) error { - return errors.Errorf("cannot kill a deleted process") -} - -func (s *deletedState) SetExited(status int) { - // no op -} - -func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return nil, errors.Errorf("cannot exec in a deleted state") -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/exec.go containerd-1.5.9/runtime/v1/linux/proc/exec.go --- containerd-1.2.6/runtime/v1/linux/proc/exec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/exec.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - "fmt" - "io" - "os" - "path/filepath" - "sync" - "syscall" - "time" - - "golang.org/x/sys/unix" - - "github.com/containerd/console" - "github.com/containerd/containerd/runtime/proc" - "github.com/containerd/fifo" - runc "github.com/containerd/go-runc" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" -) - -type execProcess struct { - wg sync.WaitGroup - - execState execState - - mu sync.Mutex - id string - console console.Console - io runc.IO - status int - exited time.Time - pid *safePid - closers []io.Closer - stdin io.Closer - stdio proc.Stdio - path string - spec specs.Process - - parent *Init - waitBlock chan struct{} -} - -func (e *execProcess) Wait() { - <-e.waitBlock -} - -func (e *execProcess) ID() string { - return e.id -} - -func (e *execProcess) Pid() int { - return e.pid.get() -} - -func (e *execProcess) ExitStatus() int { - e.mu.Lock() - defer e.mu.Unlock() - return e.status -} - -func (e *execProcess) ExitedAt() time.Time { - e.mu.Lock() - defer e.mu.Unlock() - return e.exited -} - -func (e *execProcess) SetExited(status int) { - e.mu.Lock() - defer e.mu.Unlock() - - e.execState.SetExited(status) -} - -func (e *execProcess) setExited(status int) { - e.status = status - e.exited = time.Now() - e.parent.Platform.ShutdownConsole(context.Background(), e.console) - close(e.waitBlock) -} - -func (e *execProcess) Delete(ctx context.Context) error { - e.mu.Lock() - defer e.mu.Unlock() - - return e.execState.Delete(ctx) -} - -func (e *execProcess) delete(ctx context.Context) error { - e.wg.Wait() - if e.io != nil { - for _, c := range e.closers { - c.Close() - } - e.io.Close() - } - pidfile := filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id)) - // silently ignore error - os.Remove(pidfile) - return nil -} - -func (e *execProcess) Resize(ws console.WinSize) error { - e.mu.Lock() - defer e.mu.Unlock() - - return e.execState.Resize(ws) -} - -func (e *execProcess) resize(ws console.WinSize) error { - if e.console == nil { - return nil - } - return e.console.Resize(ws) -} - -func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error { - e.mu.Lock() - defer e.mu.Unlock() - - return e.execState.Kill(ctx, sig, false) -} - -func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error { - pid := e.pid.get() - if pid != 0 { - if err := unix.Kill(pid, syscall.Signal(sig)); err != nil { - return errors.Wrapf(checkKillError(err), "exec kill error") - } - } - return nil -} - -func (e *execProcess) Stdin() io.Closer { - return e.stdin -} - -func (e *execProcess) Stdio() proc.Stdio { - return e.stdio -} - -func (e *execProcess) Start(ctx context.Context) error { - e.mu.Lock() - defer e.mu.Unlock() - - return e.execState.Start(ctx) -} - -func (e *execProcess) start(ctx context.Context) (err error) { - // The reaper may receive exit signal right after - // the container is started, before the e.pid is updated. - // In that case, we want to block the signal handler to - // access e.pid until it is updated. - e.pid.Lock() - defer e.pid.Unlock() - var ( - socket *runc.Socket - pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id)) - ) - if e.stdio.Terminal { - if socket, err = runc.NewTempConsoleSocket(); err != nil { - return errors.Wrap(err, "failed to create runc console socket") - } - defer socket.Close() - } else if e.stdio.IsNull() { - if e.io, err = runc.NewNullIO(); err != nil { - return errors.Wrap(err, "creating new NULL IO") - } - } else { - if e.io, err = runc.NewPipeIO(e.parent.IoUID, e.parent.IoGID, withConditionalIO(e.stdio)); err != nil { - return errors.Wrap(err, "failed to create runc io pipes") - } - } - opts := &runc.ExecOpts{ - PidFile: pidfile, - IO: e.io, - Detach: true, - } - if socket != nil { - opts.ConsoleSocket = socket - } - if err := e.parent.runtime.Exec(ctx, e.parent.id, e.spec, opts); err != nil { - close(e.waitBlock) - return e.parent.runtimeError(err, "OCI runtime exec failed") - } - if e.stdio.Stdin != "" { - sc, err := fifo.OpenFifo(context.Background(), e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) - if err != nil { - return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.Stdin) - } - e.closers = append(e.closers, sc) - e.stdin = sc - } - var copyWaitGroup sync.WaitGroup - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - if socket != nil { - console, err := socket.ReceiveMaster() - if err != nil { - return errors.Wrap(err, "failed to retrieve console master") - } - if e.console, err = e.parent.Platform.CopyConsole(ctx, console, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, ©WaitGroup); err != nil { - return errors.Wrap(err, "failed to start console copy") - } - } else if !e.stdio.IsNull() { - if err := copyPipes(ctx, e.io, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg, ©WaitGroup); err != nil { - return errors.Wrap(err, "failed to start io pipe copy") - } - } - copyWaitGroup.Wait() - pid, err := runc.ReadPidFile(opts.PidFile) - if err != nil { - return errors.Wrap(err, "failed to retrieve OCI runtime exec pid") - } - e.pid.pid = pid - return nil -} - -func (e *execProcess) Status(ctx context.Context) (string, error) { - s, err := e.parent.Status(ctx) - if err != nil { - return "", err - } - // if the container as a whole is in the pausing/paused state, so are all - // other processes inside the container, use container state here - switch s { - case "paused", "pausing": - return s, nil - } - e.mu.Lock() - defer e.mu.Unlock() - // if we don't have a pid then the exec process has just been created - if e.pid.get() == 0 { - return "created", nil - } - // if we have a pid and it can be signaled, the process is running - if err := unix.Kill(e.pid.get(), 0); err == nil { - return "running", nil - } - // else if we have a pid but it can nolonger be signaled, it has stopped - return "stopped", nil -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/exec_state.go containerd-1.5.9/runtime/v1/linux/proc/exec_state.go --- containerd-1.2.6/runtime/v1/linux/proc/exec_state.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/exec_state.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - - "github.com/containerd/console" - "github.com/pkg/errors" -) - -type execState interface { - Resize(console.WinSize) error - Start(context.Context) error - Delete(context.Context) error - Kill(context.Context, uint32, bool) error - SetExited(int) -} - -type execCreatedState struct { - p *execProcess -} - -func (s *execCreatedState) transition(name string) error { - switch name { - case "running": - s.p.execState = &execRunningState{p: s.p} - case "stopped": - s.p.execState = &execStoppedState{p: s.p} - case "deleted": - s.p.execState = &deletedState{} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *execCreatedState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *execCreatedState) Start(ctx context.Context) error { - if err := s.p.start(ctx); err != nil { - return err - } - return s.transition("running") -} - -func (s *execCreatedState) Delete(ctx context.Context) error { - if err := s.p.delete(ctx); err != nil { - return err - } - - return s.transition("deleted") -} - -func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *execCreatedState) SetExited(status int) { - s.p.setExited(status) - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -type execRunningState struct { - p *execProcess -} - -func (s *execRunningState) transition(name string) error { - switch name { - case "stopped": - s.p.execState = &execStoppedState{p: s.p} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *execRunningState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *execRunningState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a running process") -} - -func (s *execRunningState) Delete(ctx context.Context) error { - return errors.Errorf("cannot delete a running process") -} - -func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *execRunningState) SetExited(status int) { - s.p.setExited(status) - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -type execStoppedState struct { - p *execProcess -} - -func (s *execStoppedState) transition(name string) error { - switch name { - case "deleted": - s.p.execState = &deletedState{} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *execStoppedState) Resize(ws console.WinSize) error { - return errors.Errorf("cannot resize a stopped container") -} - -func (s *execStoppedState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a stopped process") -} - -func (s *execStoppedState) Delete(ctx context.Context) error { - if err := s.p.delete(ctx); err != nil { - return err - } - - return s.transition("deleted") -} - -func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *execStoppedState) SetExited(status int) { - // no op -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/init.go containerd-1.5.9/runtime/v1/linux/proc/init.go --- containerd-1.2.6/runtime/v1/linux/proc/init.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/init.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,491 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "sync" - "syscall" - "time" - - "github.com/containerd/console" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/runtime/proc" - "github.com/containerd/fifo" - runc "github.com/containerd/go-runc" - google_protobuf "github.com/gogo/protobuf/types" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" -) - -// 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 - initState initState - - // mu is used to ensure that `Start()` and `Exited()` calls return in - // the right order when invoked in separate go routines. - // This is the case within the shim implementation as it makes use of - // the reaper interface. - mu sync.Mutex - - waitBlock chan struct{} - - WorkDir string - - id string - Bundle string - console console.Console - Platform proc.Platform - io runc.IO - runtime *runc.Runc - status int - exited time.Time - pid int - closers []io.Closer - stdin io.Closer - stdio proc.Stdio - Rootfs string - IoUID int - IoGID int - NoPivotRoot bool - NoNewKeyring bool -} - -// NewRunc returns a new runc instance for a process -func NewRunc(root, path, namespace, runtime, criu string, systemd bool) *runc.Runc { - if root == "" { - root = RuncRoot - } - return &runc.Runc{ - Command: runtime, - Log: filepath.Join(path, "log.json"), - LogFormat: runc.JSON, - PdeathSignal: syscall.SIGKILL, - Root: filepath.Join(root, namespace), - Criu: criu, - SystemdCgroup: systemd, - } -} - -// New returns a new process -func New(id string, runtime *runc.Runc, stdio proc.Stdio) *Init { - p := &Init{ - id: id, - runtime: runtime, - stdio: stdio, - status: 0, - waitBlock: make(chan struct{}), - } - p.initState = &createdState{p: p} - return p -} - -// Create the process with the provided config -func (p *Init) Create(ctx context.Context, r *CreateConfig) error { - var ( - err error - socket *runc.Socket - ) - if r.Terminal { - if socket, err = runc.NewTempConsoleSocket(); err != nil { - return errors.Wrap(err, "failed to create OCI runtime console socket") - } - defer socket.Close() - } else if hasNoIO(r) { - if p.io, err = runc.NewNullIO(); err != nil { - return errors.Wrap(err, "creating new NULL IO") - } - } else { - if p.io, err = runc.NewPipeIO(p.IoUID, p.IoGID, withConditionalIO(p.stdio)); err != nil { - return errors.Wrap(err, "failed to create OCI runtime io pipes") - } - } - pidFile := filepath.Join(p.Bundle, InitPidFile) - if r.Checkpoint != "" { - opts := &runc.RestoreOpts{ - CheckpointOpts: runc.CheckpointOpts{ - ImagePath: r.Checkpoint, - WorkDir: p.WorkDir, - ParentPath: r.ParentCheckpoint, - }, - PidFile: pidFile, - IO: p.io, - NoPivot: p.NoPivotRoot, - Detach: true, - NoSubreaper: true, - } - p.initState = &createdCheckpointState{ - p: p, - opts: opts, - } - return nil - } - opts := &runc.CreateOpts{ - PidFile: pidFile, - IO: p.io, - NoPivot: p.NoPivotRoot, - NoNewKeyring: p.NoNewKeyring, - } - if socket != nil { - opts.ConsoleSocket = socket - } - if err := p.runtime.Create(ctx, r.ID, r.Bundle, opts); err != nil { - return p.runtimeError(err, "OCI runtime create failed") - } - if r.Stdin != "" { - sc, err := fifo.OpenFifo(context.Background(), r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) - if err != nil { - return errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin) - } - p.stdin = sc - p.closers = append(p.closers, sc) - } - var copyWaitGroup sync.WaitGroup - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - if socket != nil { - console, err := socket.ReceiveMaster() - if err != nil { - return errors.Wrap(err, "failed to retrieve console master") - } - console, err = p.Platform.CopyConsole(ctx, console, r.Stdin, r.Stdout, r.Stderr, &p.wg, ©WaitGroup) - if err != nil { - return errors.Wrap(err, "failed to start console copy") - } - p.console = console - } else if !hasNoIO(r) { - if err := copyPipes(ctx, p.io, r.Stdin, r.Stdout, r.Stderr, &p.wg, ©WaitGroup); err != nil { - return errors.Wrap(err, "failed to start io pipe copy") - } - } - - copyWaitGroup.Wait() - pid, err := runc.ReadPidFile(pidFile) - if err != nil { - return errors.Wrap(err, "failed to retrieve OCI runtime container pid") - } - p.pid = pid - return nil -} - -// Wait for the process to exit -func (p *Init) Wait() { - <-p.waitBlock -} - -// ID of the process -func (p *Init) ID() string { - return p.id -} - -// Pid of the process -func (p *Init) Pid() int { - return p.pid -} - -// ExitStatus of the process -func (p *Init) ExitStatus() int { - p.mu.Lock() - defer p.mu.Unlock() - - return p.status -} - -// ExitedAt at time when the process exited -func (p *Init) ExitedAt() time.Time { - p.mu.Lock() - defer p.mu.Unlock() - - return p.exited -} - -// Status of the process -func (p *Init) Status(ctx context.Context) (string, error) { - p.mu.Lock() - defer p.mu.Unlock() - - c, err := p.runtime.State(ctx, p.id) - if err != nil { - if strings.Contains(err.Error(), "does not exist") { - return "stopped", nil - } - return "", p.runtimeError(err, "OCI runtime state failed") - } - return c.Status, nil -} - -// Start the init process -func (p *Init) Start(ctx context.Context) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Start(ctx) -} - -func (p *Init) start(ctx context.Context) error { - err := p.runtime.Start(ctx, p.id) - return p.runtimeError(err, "OCI runtime start failed") -} - -// SetExited of the init process with the next status -func (p *Init) SetExited(status int) { - p.mu.Lock() - defer p.mu.Unlock() - - p.initState.SetExited(status) -} - -func (p *Init) setExited(status int) { - p.exited = time.Now() - p.status = status - p.Platform.ShutdownConsole(context.Background(), p.console) - close(p.waitBlock) -} - -// Delete the init process -func (p *Init) Delete(ctx context.Context) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Delete(ctx) -} - -func (p *Init) delete(ctx context.Context) error { - p.wg.Wait() - err := p.runtime.Delete(ctx, p.id, nil) - // ignore errors if a runtime has already deleted the process - // but we still hold metadata and pipes - // - // this is common during a checkpoint, runc will delete the container state - // after a checkpoint and the container will no longer exist within runc - if err != nil { - if strings.Contains(err.Error(), "does not exist") { - err = nil - } else { - err = p.runtimeError(err, "failed to delete task") - } - } - if p.io != nil { - for _, c := range p.closers { - c.Close() - } - p.io.Close() - } - if err2 := mount.UnmountAll(p.Rootfs, 0); err2 != nil { - log.G(ctx).WithError(err2).Warn("failed to cleanup rootfs mount") - if err == nil { - err = errors.Wrap(err2, "failed rootfs umount") - } - } - return err -} - -// Resize the init processes console -func (p *Init) Resize(ws console.WinSize) error { - p.mu.Lock() - defer p.mu.Unlock() - - if p.console == nil { - return nil - } - return p.console.Resize(ws) -} - -func (p *Init) resize(ws console.WinSize) error { - if p.console == nil { - return nil - } - return p.console.Resize(ws) -} - -// Pause the init process and all its child processes -func (p *Init) Pause(ctx context.Context) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Pause(ctx) -} - -// Resume the init process and all its child processes -func (p *Init) Resume(ctx context.Context) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Resume(ctx) -} - -// Kill the init process -func (p *Init) Kill(ctx context.Context, signal uint32, all bool) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Kill(ctx, signal, all) -} - -func (p *Init) kill(ctx context.Context, signal uint32, all bool) error { - err := p.runtime.Kill(ctx, p.id, int(signal), &runc.KillOpts{ - All: all, - }) - return checkKillError(err) -} - -// KillAll processes belonging to the init process -func (p *Init) KillAll(ctx context.Context) error { - p.mu.Lock() - defer p.mu.Unlock() - - err := p.runtime.Kill(ctx, p.id, int(syscall.SIGKILL), &runc.KillOpts{ - All: true, - }) - return p.runtimeError(err, "OCI runtime killall failed") -} - -// Stdin of the process -func (p *Init) Stdin() io.Closer { - return p.stdin -} - -// Runtime returns the OCI runtime configured for the init process -func (p *Init) Runtime() *runc.Runc { - return p.runtime -} - -// Exec returns a new child process -func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Exec(ctx, path, r) -} - -// exec returns a new exec'd process -func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - // process exec request - var spec specs.Process - if err := json.Unmarshal(r.Spec.Value, &spec); err != nil { - return nil, err - } - spec.Terminal = r.Terminal - - e := &execProcess{ - id: r.ID, - path: path, - parent: p, - spec: spec, - stdio: proc.Stdio{ - Stdin: r.Stdin, - Stdout: r.Stdout, - Stderr: r.Stderr, - Terminal: r.Terminal, - }, - waitBlock: make(chan struct{}), - pid: &safePid{}, - } - e.execState = &execCreatedState{p: e} - return e, nil -} - -// Checkpoint the init process -func (p *Init) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Checkpoint(ctx, r) -} - -func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error { - var actions []runc.CheckpointAction - if !r.Exit { - actions = append(actions, runc.LeaveRunning) - } - work := filepath.Join(p.WorkDir, "criu-work") - defer os.RemoveAll(work) - if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{ - WorkDir: work, - ImagePath: r.Path, - AllowOpenTCP: r.AllowOpenTCP, - AllowExternalUnixSockets: r.AllowExternalUnixSockets, - AllowTerminal: r.AllowTerminal, - FileLocks: r.FileLocks, - EmptyNamespaces: r.EmptyNamespaces, - }, actions...); err != nil { - dumpLog := filepath.Join(p.Bundle, "criu-dump.log") - if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil { - log.G(ctx).Error(err) - } - return fmt.Errorf("%s path= %s", criuError(err), dumpLog) - } - return nil -} - -// Update the processes resource configuration -func (p *Init) Update(ctx context.Context, r *google_protobuf.Any) error { - p.mu.Lock() - defer p.mu.Unlock() - - return p.initState.Update(ctx, r) -} - -func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error { - var resources specs.LinuxResources - if err := json.Unmarshal(r.Value, &resources); err != nil { - return err - } - return p.runtime.Update(ctx, p.id, &resources) -} - -// Stdio of the process -func (p *Init) Stdio() proc.Stdio { - return p.stdio -} - -func (p *Init) runtimeError(rErr error, msg string) error { - if rErr == nil { - return nil - } - - rMsg, err := getLastRuntimeError(p.runtime) - switch { - case err != nil: - return errors.Wrapf(rErr, "%s: %s (%s)", msg, "unable to retrieve OCI runtime error", err.Error()) - case rMsg == "": - return errors.Wrap(rErr, msg) - default: - return errors.Errorf("%s: %s", msg, rMsg) - } -} - -func withConditionalIO(c proc.Stdio) runc.IOOpt { - return func(o *runc.IOOption) { - o.OpenStdin = c.Stdin != "" - o.OpenStdout = c.Stdout != "" - o.OpenStderr = c.Stderr != "" - } -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/init_state.go containerd-1.5.9/runtime/v1/linux/proc/init_state.go --- containerd-1.2.6/runtime/v1/linux/proc/init_state.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/init_state.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,418 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - "sync" - "syscall" - - "github.com/containerd/console" - "github.com/containerd/containerd/runtime/proc" - "github.com/containerd/fifo" - runc "github.com/containerd/go-runc" - google_protobuf "github.com/gogo/protobuf/types" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -type initState interface { - Resize(console.WinSize) error - Start(context.Context) error - Delete(context.Context) error - Pause(context.Context) error - Resume(context.Context) error - Update(context.Context, *google_protobuf.Any) error - Checkpoint(context.Context, *CheckpointConfig) error - Exec(context.Context, string, *ExecConfig) (proc.Process, error) - Kill(context.Context, uint32, bool) error - SetExited(int) -} - -type createdState struct { - p *Init -} - -func (s *createdState) transition(name string) error { - switch name { - case "running": - s.p.initState = &runningState{p: s.p} - case "stopped": - s.p.initState = &stoppedState{p: s.p} - case "deleted": - s.p.initState = &deletedState{} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *createdState) Pause(ctx context.Context) error { - return errors.Errorf("cannot pause task in created state") -} - -func (s *createdState) Resume(ctx context.Context) error { - return errors.Errorf("cannot resume task in created state") -} - -func (s *createdState) Update(ctx context.Context, r *google_protobuf.Any) error { - return s.p.update(ctx, r) -} - -func (s *createdState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return errors.Errorf("cannot checkpoint a task in created state") -} - -func (s *createdState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *createdState) Start(ctx context.Context) error { - if err := s.p.start(ctx); err != nil { - return err - } - return s.transition("running") -} - -func (s *createdState) Delete(ctx context.Context) error { - if err := s.p.delete(ctx); err != nil { - return err - } - return s.transition("deleted") -} - -func (s *createdState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *createdState) SetExited(status int) { - s.p.setExited(status) - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return s.p.exec(ctx, path, r) -} - -type createdCheckpointState struct { - p *Init - opts *runc.RestoreOpts -} - -func (s *createdCheckpointState) transition(name string) error { - switch name { - case "running": - s.p.initState = &runningState{p: s.p} - case "stopped": - s.p.initState = &stoppedState{p: s.p} - case "deleted": - s.p.initState = &deletedState{} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *createdCheckpointState) Pause(ctx context.Context) error { - return errors.Errorf("cannot pause task in created state") -} - -func (s *createdCheckpointState) Resume(ctx context.Context) error { - return errors.Errorf("cannot resume task in created state") -} - -func (s *createdCheckpointState) Update(ctx context.Context, r *google_protobuf.Any) error { - return s.p.update(ctx, r) -} - -func (s *createdCheckpointState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return errors.Errorf("cannot checkpoint a task in created state") -} - -func (s *createdCheckpointState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *createdCheckpointState) Start(ctx context.Context) error { - p := s.p - sio := p.stdio - - var ( - err error - socket *runc.Socket - ) - if sio.Terminal { - if socket, err = runc.NewTempConsoleSocket(); err != nil { - return errors.Wrap(err, "failed to create OCI runtime console socket") - } - defer socket.Close() - s.opts.ConsoleSocket = socket - } - - if _, err := s.p.runtime.Restore(ctx, p.id, p.Bundle, s.opts); err != nil { - return p.runtimeError(err, "OCI runtime restore failed") - } - if sio.Stdin != "" { - sc, err := fifo.OpenFifo(context.Background(), sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) - if err != nil { - return errors.Wrapf(err, "failed to open stdin fifo %s", sio.Stdin) - } - p.stdin = sc - p.closers = append(p.closers, sc) - } - var copyWaitGroup sync.WaitGroup - if socket != nil { - console, err := socket.ReceiveMaster() - if err != nil { - return errors.Wrap(err, "failed to retrieve console master") - } - console, err = p.Platform.CopyConsole(ctx, console, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, ©WaitGroup) - if err != nil { - return errors.Wrap(err, "failed to start console copy") - } - p.console = console - } else if !sio.IsNull() { - if err := copyPipes(ctx, p.io, sio.Stdin, sio.Stdout, sio.Stderr, &p.wg, ©WaitGroup); err != nil { - return errors.Wrap(err, "failed to start io pipe copy") - } - } - - copyWaitGroup.Wait() - pid, err := runc.ReadPidFile(s.opts.PidFile) - if err != nil { - return errors.Wrap(err, "failed to retrieve OCI runtime container pid") - } - p.pid = pid - return s.transition("running") -} - -func (s *createdCheckpointState) Delete(ctx context.Context) error { - if err := s.p.delete(ctx); err != nil { - return err - } - return s.transition("deleted") -} - -func (s *createdCheckpointState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *createdCheckpointState) SetExited(status int) { - s.p.setExited(status) - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return nil, errors.Errorf("cannot exec in a created state") -} - -type runningState struct { - p *Init -} - -func (s *runningState) transition(name string) error { - switch name { - case "stopped": - s.p.initState = &stoppedState{p: s.p} - case "paused": - s.p.initState = &pausedState{p: s.p} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *runningState) Pause(ctx context.Context) error { - if err := s.p.runtime.Pause(ctx, s.p.id); err != nil { - return s.p.runtimeError(err, "OCI runtime pause failed") - } - - return s.transition("paused") -} - -func (s *runningState) Resume(ctx context.Context) error { - return errors.Errorf("cannot resume a running process") -} - -func (s *runningState) Update(ctx context.Context, r *google_protobuf.Any) error { - return s.p.update(ctx, r) -} - -func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return s.p.checkpoint(ctx, r) -} - -func (s *runningState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *runningState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a running process") -} - -func (s *runningState) Delete(ctx context.Context) error { - return errors.Errorf("cannot delete a running process") -} - -func (s *runningState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *runningState) SetExited(status int) { - s.p.setExited(status) - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return s.p.exec(ctx, path, r) -} - -type pausedState struct { - p *Init -} - -func (s *pausedState) transition(name string) error { - switch name { - case "running": - s.p.initState = &runningState{p: s.p} - case "stopped": - s.p.initState = &stoppedState{p: s.p} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *pausedState) Pause(ctx context.Context) error { - return errors.Errorf("cannot pause a paused container") -} - -func (s *pausedState) Resume(ctx context.Context) error { - if err := s.p.runtime.Resume(ctx, s.p.id); err != nil { - return s.p.runtimeError(err, "OCI runtime resume failed") - } - - return s.transition("running") -} - -func (s *pausedState) Update(ctx context.Context, r *google_protobuf.Any) error { - return s.p.update(ctx, r) -} - -func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return s.p.checkpoint(ctx, r) -} - -func (s *pausedState) Resize(ws console.WinSize) error { - return s.p.resize(ws) -} - -func (s *pausedState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a paused process") -} - -func (s *pausedState) Delete(ctx context.Context) error { - return errors.Errorf("cannot delete a paused process") -} - -func (s *pausedState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *pausedState) SetExited(status int) { - s.p.setExited(status) - - if err := s.p.runtime.Resume(context.Background(), s.p.id); err != nil { - logrus.WithError(err).Error("resuming exited container from paused state") - } - - if err := s.transition("stopped"); err != nil { - panic(err) - } -} - -func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return nil, errors.Errorf("cannot exec in a paused state") -} - -type stoppedState struct { - p *Init -} - -func (s *stoppedState) transition(name string) error { - switch name { - case "deleted": - s.p.initState = &deletedState{} - default: - return errors.Errorf("invalid state transition %q to %q", stateName(s), name) - } - return nil -} - -func (s *stoppedState) Pause(ctx context.Context) error { - return errors.Errorf("cannot pause a stopped container") -} - -func (s *stoppedState) Resume(ctx context.Context) error { - return errors.Errorf("cannot resume a stopped container") -} - -func (s *stoppedState) Update(ctx context.Context, r *google_protobuf.Any) error { - return errors.Errorf("cannot update a stopped container") -} - -func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error { - return errors.Errorf("cannot checkpoint a stopped container") -} - -func (s *stoppedState) Resize(ws console.WinSize) error { - return errors.Errorf("cannot resize a stopped container") -} - -func (s *stoppedState) Start(ctx context.Context) error { - return errors.Errorf("cannot start a stopped process") -} - -func (s *stoppedState) Delete(ctx context.Context) error { - if err := s.p.delete(ctx); err != nil { - return err - } - return s.transition("deleted") -} - -func (s *stoppedState) Kill(ctx context.Context, sig uint32, all bool) error { - return s.p.kill(ctx, sig, all) -} - -func (s *stoppedState) SetExited(status int) { - // no op -} - -func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) { - return nil, errors.Errorf("cannot exec in a stopped state") -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/io.go containerd-1.5.9/runtime/v1/linux/proc/io.go --- containerd-1.2.6/runtime/v1/linux/proc/io.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/io.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,168 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "context" - "fmt" - "io" - "os" - "sync" - "sync/atomic" - "syscall" - - "github.com/containerd/containerd/log" - "github.com/containerd/fifo" - runc "github.com/containerd/go-runc" -) - -var bufPool = sync.Pool{ - New: func() interface{} { - buffer := make([]byte, 32<<10) - return &buffer - }, -} - -func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error { - var sameFile *countingWriteCloser - for _, i := range []struct { - name string - dest func(wc io.WriteCloser, rc io.Closer) - }{ - { - name: stdout, - dest: func(wc io.WriteCloser, rc io.Closer) { - wg.Add(1) - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - if _, err := io.CopyBuffer(wc, rio.Stdout(), *p); err != nil { - log.G(ctx).Warn("error copying stdout") - } - wg.Done() - wc.Close() - if rc != nil { - rc.Close() - } - }() - }, - }, { - name: stderr, - dest: func(wc io.WriteCloser, rc io.Closer) { - wg.Add(1) - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - if _, err := io.CopyBuffer(wc, rio.Stderr(), *p); err != nil { - log.G(ctx).Warn("error copying stderr") - } - wg.Done() - wc.Close() - if rc != nil { - rc.Close() - } - }() - }, - }, - } { - ok, err := isFifo(i.name) - if err != nil { - return err - } - var ( - fw io.WriteCloser - fr io.Closer - ) - if ok { - if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil { - return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err) - } - if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil { - return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err) - } - } else { - if sameFile != nil { - sameFile.count++ - i.dest(sameFile, nil) - continue - } - if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil { - return fmt.Errorf("containerd-shim: opening %s failed: %s", i.name, err) - } - if stdout == stderr { - sameFile = &countingWriteCloser{ - WriteCloser: fw, - count: 1, - } - } - } - i.dest(fw, fr) - } - if stdin == "" { - return nil - } - f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) - if err != nil { - return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) - } - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - - io.CopyBuffer(rio.Stdin(), f, *p) - rio.Stdin().Close() - f.Close() - }() - return nil -} - -// countingWriteCloser masks io.Closer() until close has been invoked a certain number of times. -type countingWriteCloser struct { - io.WriteCloser - count int64 -} - -func (c *countingWriteCloser) Close() error { - if atomic.AddInt64(&c.count, -1) > 0 { - return nil - } - return c.WriteCloser.Close() -} - -// isFifo checks if a file is a fifo -// if the file does not exist then it returns false -func isFifo(path string) (bool, error) { - stat, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return false, nil - } - return false, err - } - if stat.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { - return true, nil - } - return false, nil -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/process.go containerd-1.5.9/runtime/v1/linux/proc/process.go --- containerd-1.2.6/runtime/v1/linux/proc/process.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/process.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "github.com/pkg/errors" -) - -// RuncRoot is the path to the root runc state directory -const RuncRoot = "/run/containerd/runc" - -func stateName(v interface{}) string { - switch v.(type) { - case *runningState, *execRunningState: - return "running" - case *createdState, *execCreatedState, *createdCheckpointState: - return "created" - case *pausedState: - return "paused" - case *deletedState: - return "deleted" - case *stoppedState: - return "stopped" - } - panic(errors.Errorf("invalid state %v", v)) -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/types.go containerd-1.5.9/runtime/v1/linux/proc/types.go --- containerd-1.2.6/runtime/v1/linux/proc/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/types.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - google_protobuf "github.com/gogo/protobuf/types" -) - -// Mount holds filesystem mount configuration -type Mount struct { - Type string - Source string - Target string - Options []string -} - -// CreateConfig hold task creation configuration -type CreateConfig struct { - ID string - Bundle string - Runtime string - Rootfs []Mount - Terminal bool - Stdin string - Stdout string - Stderr string - Checkpoint string - ParentCheckpoint string - Options *google_protobuf.Any -} - -// ExecConfig holds exec creation configuration -type ExecConfig struct { - ID string - Terminal bool - Stdin string - Stdout string - Stderr string - Spec *google_protobuf.Any -} - -// CheckpointConfig holds task checkpoint configuration -type CheckpointConfig struct { - Path string - Exit bool - AllowOpenTCP bool - AllowExternalUnixSockets bool - AllowTerminal bool - FileLocks bool - EmptyNamespaces []string -} diff -Nru containerd-1.2.6/runtime/v1/linux/proc/utils.go containerd-1.5.9/runtime/v1/linux/proc/utils.go --- containerd-1.2.6/runtime/v1/linux/proc/utils.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/proc/utils.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package proc - -import ( - "encoding/json" - "io" - "os" - "strings" - "sync" - "time" - - "github.com/containerd/containerd/errdefs" - runc "github.com/containerd/go-runc" - "github.com/pkg/errors" - "golang.org/x/sys/unix" -) - -// safePid is a thread safe wrapper for pid. -type safePid struct { - sync.Mutex - pid int -} - -func (s *safePid) get() int { - s.Lock() - defer s.Unlock() - return s.pid -} - -// TODO(mlaventure): move to runc package? -func getLastRuntimeError(r *runc.Runc) (string, error) { - if r.Log == "" { - return "", nil - } - - f, err := os.OpenFile(r.Log, os.O_RDONLY, 0400) - if err != nil { - return "", err - } - - var ( - errMsg string - log struct { - Level string - Msg string - Time time.Time - } - ) - - dec := json.NewDecoder(f) - for err = nil; err == nil; { - if err = dec.Decode(&log); err != nil && err != io.EOF { - return "", err - } - if log.Level == "error" { - errMsg = strings.TrimSpace(log.Msg) - } - } - - return errMsg, nil -} - -// criuError returns only the first line of the error message from criu -// it tries to add an invalid dump log location when returning the message -func criuError(err error) string { - parts := strings.Split(err.Error(), "\n") - return parts[0] -} - -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 checkKillError(err error) error { - if err == nil { - return nil - } - if strings.Contains(err.Error(), "os: process already finished") || - strings.Contains(err.Error(), "container not running") || - err == unix.ESRCH { - return errors.Wrapf(errdefs.ErrNotFound, "process already finished") - } - return errors.Wrapf(err, "unknown error after kill") -} - -func hasNoIO(r *CreateConfig) bool { - return r.Stdin == "" && r.Stdout == "" && r.Stderr == "" -} diff -Nru containerd-1.2.6/runtime/v1/linux/process.go containerd-1.5.9/runtime/v1/linux/process.go --- containerd-1.2.6/runtime/v1/linux/process.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/process.go 2022-01-05 17:30:58.000000000 +0000 @@ -62,7 +62,7 @@ ID: p.id, }) if err != nil { - if errors.Cause(err) != ttrpc.ErrClosed { + if !errors.Is(err, ttrpc.ErrClosed) { return runtime.State{}, errdefs.FromGRPC(err) } diff -Nru containerd-1.2.6/runtime/v1/linux/runtime.go containerd-1.5.9/runtime/v1/linux/runtime.go --- containerd-1.2.6/runtime/v1/linux/runtime.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/runtime.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ import ( "context" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -36,11 +37,12 @@ "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/process" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime/linux/runctypes" - "github.com/containerd/containerd/runtime/v1/linux/proc" + v1 "github.com/containerd/containerd/runtime/v1" shim "github.com/containerd/containerd/runtime/v1/shim/v1" runc "github.com/containerd/go-runc" "github.com/containerd/typeurl" @@ -48,7 +50,6 @@ ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" - bolt "go.etcd.io/bbolt" "golang.org/x/sys/unix" ) @@ -61,6 +62,9 @@ configFilename = "config.json" defaultRuntime = "runc" defaultShim = "containerd-shim" + + // cleanupTimeout is default timeout for cleanup operations + cleanupTimeout = 1 * time.Minute ) func init() { @@ -110,13 +114,13 @@ } cfg := ic.Config.(*Config) r := &Runtime{ - root: ic.Root, - state: ic.State, - tasks: runtime.NewTaskList(), - db: m.(*metadata.DB), - address: ic.Address, - events: ic.Events, - config: cfg, + root: ic.Root, + state: ic.State, + tasks: runtime.NewTaskList(), + containers: metadata.NewContainerStore(m.(*metadata.DB)), + address: ic.Address, + events: ic.Events, + config: cfg, } tasks, err := r.restoreTasks(ic.Context) if err != nil { @@ -136,9 +140,9 @@ state string address string - tasks *runtime.TaskList - db *metadata.DB - events *exchange.Exchange + tasks *runtime.TaskList + containers containers.Store + events *exchange.Exchange config *Config } @@ -189,18 +193,13 @@ } exitHandler := func() { log.G(ctx).WithField("id", id).Info("shim reaped") - t, err := r.tasks.Get(ctx, id) - if err != nil { + + if _, err := r.tasks.Get(ctx, id); err != nil { // Task was never started or was already successfully deleted return } - lc := t.(*Task) - log.G(ctx).WithFields(logrus.Fields{ - "id": id, - "namespace": namespace, - }).Warn("cleaning up after killed shim") - if err = r.cleanupAfterDeadShim(context.Background(), bundle, namespace, id, lc.pid); err != nil { + if err = r.cleanupAfterDeadShim(context.Background(), bundle, namespace, id); err != nil { log.G(ctx).WithError(err).WithFields(logrus.Fields{ "id": id, "namespace": namespace, @@ -216,8 +215,11 @@ } defer func() { if err != nil { - if kerr := s.KillShim(ctx); kerr != nil { - log.G(ctx).WithError(err).Error("failed to kill shim") + deferCtx, deferCancel := context.WithTimeout( + namespaces.WithNamespace(context.TODO(), namespace), cleanupTimeout) + defer deferCancel() + if kerr := s.KillShim(deferCtx); kerr != nil { + log.G(ctx).WithError(kerr).Error("failed to kill shim") } } }() @@ -288,6 +290,10 @@ continue } name := namespace.Name() + // skip hidden directories + if len(name) > 0 && name[0] == '.' { + continue + } log.G(ctx).WithField("namespace", name).Debug("loading tasks in namespace") tasks, err := r.loadTasks(ctx, name) if err != nil { @@ -324,16 +330,26 @@ continue } id := path.Name() + // skip hidden directories + if len(id) > 0 && id[0] == '.' { + continue + } bundle := loadBundle( id, filepath.Join(r.state, ns, id), filepath.Join(r.root, ns, id), ) ctx = namespaces.WithNamespace(ctx, ns) - pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, proc.InitPidFile)) + pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, process.InitPidFile)) + shimExit := make(chan struct{}) s, err := bundle.NewShimClient(ctx, ns, ShimConnect(r.config, func() { - err := r.cleanupAfterDeadShim(ctx, bundle, ns, id, pid) - if err != nil { + defer close(shimExit) + if _, err := r.tasks.Get(ctx, id); err != nil { + // Task was never started or was already successfully deleted + return + } + + if err := r.cleanupAfterDeadShim(ctx, bundle, ns, id); err != nil { log.G(ctx).WithError(err).WithField("bundle", bundle.path). Error("cleaning up after dead shim") } @@ -343,7 +359,7 @@ "id": id, "namespace": ns, }).Error("connecting to shim") - err := r.cleanupAfterDeadShim(ctx, bundle, ns, id, pid) + err := r.cleanupAfterDeadShim(ctx, bundle, ns, id) if err != nil { log.G(ctx).WithError(err).WithField("bundle", bundle.path). Error("cleaning up after dead shim") @@ -351,6 +367,50 @@ continue } + logDirPath := filepath.Join(r.root, ns, id) + + copyAndClose := func(dst io.Writer, src io.ReadWriteCloser) { + copyDone := make(chan struct{}) + go func() { + io.Copy(dst, src) + close(copyDone) + }() + select { + case <-shimExit: + case <-copyDone: + } + src.Close() + } + shimStdoutLog, err := v1.OpenShimStdoutLog(ctx, logDirPath) + if err != nil { + log.G(ctx).WithError(err).WithFields(logrus.Fields{ + "id": id, + "namespace": ns, + "logDirPath": logDirPath, + }).Error("opening shim stdout log pipe") + continue + } + if r.config.ShimDebug { + go copyAndClose(os.Stdout, shimStdoutLog) + } else { + go copyAndClose(ioutil.Discard, shimStdoutLog) + } + + shimStderrLog, err := v1.OpenShimStderrLog(ctx, logDirPath) + if err != nil { + log.G(ctx).WithError(err).WithFields(logrus.Fields{ + "id": id, + "namespace": ns, + "logDirPath": logDirPath, + }).Error("opening shim stderr log pipe") + continue + } + if r.config.ShimDebug { + go copyAndClose(os.Stderr, shimStderrLog) + } else { + go copyAndClose(ioutil.Discard, shimStderrLog) + } + t, err := newTask(id, ns, pid, s, r.events, r.tasks, bundle) if err != nil { log.G(ctx).WithError(err).Error("loading task type") @@ -361,7 +421,13 @@ return o, nil } -func (r *Runtime) cleanupAfterDeadShim(ctx context.Context, bundle *bundle, ns, id string, pid int) error { +func (r *Runtime) cleanupAfterDeadShim(ctx context.Context, bundle *bundle, ns, id string) error { + log.G(ctx).WithFields(logrus.Fields{ + "id": id, + "namespace": ns, + }).Warn("cleaning up after shim dead") + + pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, process.InitPidFile)) ctx = namespaces.WithNamespace(ctx, ns) if err := r.terminate(ctx, bundle, ns, id); err != nil { if r.config.ShimDebug { @@ -384,6 +450,10 @@ if err := bundle.Delete(); err != nil { log.G(ctx).WithError(err).Error("delete bundle") } + // kill shim + if shimPid, err := runc.ReadPidFile(filepath.Join(bundle.path, "shim.pid")); err == nil && shimPid > 0 { + unix.Kill(shimPid, unix.SIGKILL) + } r.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ ContainerID: id, @@ -422,7 +492,7 @@ var ( cmd = r.config.Runtime - root = proc.RuncRoot + root = process.RuncRoot ) if ropts != nil { if ropts.Runtime != "" { @@ -443,14 +513,8 @@ } func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runctypes.RuncOptions, error) { - var container containers.Container - - if err := r.db.View(func(tx *bolt.Tx) error { - store := metadata.NewContainerStore(tx) - var err error - container, err = store.Get(ctx, id) - return err - }); err != nil { + container, err := r.containers.Get(ctx, id) + if err != nil { return nil, err } diff -Nru containerd-1.2.6/runtime/v1/linux/task.go containerd-1.5.9/runtime/v1/linux/task.go --- containerd-1.2.6/runtime/v1/linux/task.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/linux/task.go 2022-01-05 17:30:58.000000000 +0000 @@ -84,11 +84,19 @@ return t.namespace } +// PID of the task +func (t *Task) PID() uint32 { + return uint32(t.pid) +} + // Delete the task and return the exit status func (t *Task) Delete(ctx context.Context) (*runtime.Exit, error) { - rsp, err := t.shim.Delete(ctx, empty) - if err != nil { - return nil, errdefs.FromGRPC(err) + rsp, shimErr := t.shim.Delete(ctx, empty) + if shimErr != nil { + shimErr = errdefs.FromGRPC(shimErr) + if !errdefs.IsNotFound(shimErr) { + return nil, shimErr + } } t.tasks.Delete(ctx, t.id) if err := t.shim.KillShim(ctx); err != nil { @@ -97,6 +105,9 @@ if err := t.bundle.Delete(); err != nil { log.G(ctx).WithError(err).Error("failed to delete bundle") } + if shimErr != nil { + return nil, shimErr + } t.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ ContainerID: t.id, ExitStatus: rsp.ExitStatus, @@ -124,11 +135,15 @@ t.pid = int(r.Pid) if !hasCgroup { cg, err := cgroups.Load(cgroups.V1, cgroups.PidPath(t.pid)) - if err != nil { + if err != nil && err != cgroups.ErrCgroupDeleted { return err } t.mu.Lock() - t.cg = cg + if err == cgroups.ErrCgroupDeleted { + t.cg = nil + } else { + t.cg = cg + } t.mu.Unlock() } t.events.Publish(ctx, runtime.TaskStartEventTopic, &eventstypes.TaskStart{ @@ -144,7 +159,7 @@ ID: t.id, }) if err != nil { - if errors.Cause(err) != ttrpc.ErrClosed { + if !errors.Is(err, ttrpc.ErrClosed) { return runtime.State{}, errdefs.FromGRPC(err) } return runtime.State{}, errdefs.ErrNotFound @@ -291,7 +306,7 @@ } // Update changes runtime information of a running task -func (t *Task) Update(ctx context.Context, resources *types.Any) error { +func (t *Task) Update(ctx context.Context, resources *types.Any, _ map[string]string) error { if _, err := t.shim.Update(ctx, &shim.UpdateTaskRequest{ Resources: resources, }); err != nil { diff -Nru containerd-1.2.6/runtime/v1/shim/client/client.go containerd-1.5.9/runtime/v1/shim/client/client.go --- containerd-1.2.6/runtime/v1/shim/client/client.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/client/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,10 +20,14 @@ import ( "context" + "fmt" "io" + "io/ioutil" "net" "os" "os/exec" + "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -37,6 +41,8 @@ "github.com/containerd/containerd/events" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/pkg/dialer" + v1 "github.com/containerd/containerd/runtime/v1" "github.com/containerd/containerd/runtime/v1/shim" shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" "github.com/containerd/containerd/sys" @@ -53,16 +59,43 @@ return func(ctx context.Context, config shim.Config) (_ shimapi.ShimService, _ io.Closer, err error) { socket, err := newSocket(address) if err != nil { - return nil, nil, err + if !eaddrinuse(err) { + return nil, nil, err + } + if err := RemoveSocket(address); err != nil { + return nil, nil, errors.Wrap(err, "remove already used socket") + } + if socket, err = newSocket(address); err != nil { + return nil, nil, err + } } - defer socket.Close() + f, err := socket.File() if err != nil { return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", address) } defer f.Close() - cmd, err := newCommand(binary, daemonAddress, debug, config, f) + stdoutCopy := ioutil.Discard + stderrCopy := ioutil.Discard + stdoutLog, err := v1.OpenShimStdoutLog(ctx, config.WorkDir) + if err != nil { + return nil, nil, errors.Wrapf(err, "failed to create stdout log") + } + + stderrLog, err := v1.OpenShimStderrLog(ctx, config.WorkDir) + if err != nil { + return nil, nil, errors.Wrapf(err, "failed to create stderr log") + } + if debug { + stdoutCopy = os.Stdout + stderrCopy = os.Stderr + } + + go io.Copy(stdoutCopy, stdoutLog) + go io.Copy(stderrCopy, stderrLog) + + cmd, err := newCommand(binary, daemonAddress, debug, config, f, stdoutLog, stderrLog) if err != nil { return nil, nil, err } @@ -77,12 +110,27 @@ go func() { cmd.Wait() exitHandler() + if stdoutLog != nil { + stdoutLog.Close() + } + if stderrLog != nil { + stderrLog.Close() + } + socket.Close() + RemoveSocket(address) }() log.G(ctx).WithFields(logrus.Fields{ "pid": cmd.Process.Pid, "address": address, "debug": debug, }).Infof("shim %s started", binary) + + if err := writeFile(filepath.Join(config.Path, "address"), address); err != nil { + return nil, nil, err + } + if err := writeFile(filepath.Join(config.Path, "shim.pid"), strconv.Itoa(cmd.Process.Pid)); err != nil { + return nil, nil, err + } // set shim in cgroup if it is provided if cgroup != "" { if err := setCgroup(cgroup, cmd); err != nil { @@ -93,8 +141,8 @@ "address": address, }).Infof("shim placed in cgroup %s", cgroup) } - if err = sys.SetOOMScore(cmd.Process.Pid, sys.OOMScoreMaxKillable); err != nil { - return nil, nil, errors.Wrap(err, "failed to set OOM Score on shim") + if err = setupOOMScore(cmd.Process.Pid); err != nil { + return nil, nil, err } c, clo, err := WithConnect(address, func() {})(ctx, config) if err != nil { @@ -104,7 +152,43 @@ } } -func newCommand(binary, daemonAddress string, debug bool, config shim.Config, socket *os.File) (*exec.Cmd, error) { +func eaddrinuse(err error) bool { + cause := errors.Cause(err) + netErr, ok := cause.(*net.OpError) + if !ok { + return false + } + if netErr.Op != "listen" { + return false + } + syscallErr, ok := netErr.Err.(*os.SyscallError) + if !ok { + return false + } + errno, ok := syscallErr.Err.(syscall.Errno) + if !ok { + return false + } + return errno == syscall.EADDRINUSE +} + +// setupOOMScore gets containerd's oom score and adds +1 to it +// to ensure a shim has a lower* score than the daemons +// if not already at the maximum OOM Score +func setupOOMScore(shimPid int) error { + pid := os.Getpid() + score, err := sys.GetOOMScoreAdj(pid) + if err != nil { + return errors.Wrap(err, "get daemon OOM score") + } + shimScore := score + 1 + if err := sys.AdjustOOMScore(shimPid, shimScore); err != nil { + return errors.Wrap(err, "set shim OOM score") + } + return nil +} + +func newCommand(binary, daemonAddress string, debug bool, config shim.Config, socket *os.File, stdout, stderr io.Writer) (*exec.Cmd, error) { selfExe, err := os.Executable() if err != nil { return nil, err @@ -137,43 +221,101 @@ cmd.SysProcAttr = getSysProcAttr() cmd.ExtraFiles = append(cmd.ExtraFiles, socket) cmd.Env = append(os.Environ(), "GOMAXPROCS=2") - if debug { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - } + cmd.Stdout = stdout + cmd.Stderr = stderr return cmd, nil } +// writeFile writes a address file atomically +func writeFile(path, address string) error { + path, err := filepath.Abs(path) + if err != nil { + return err + } + tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) + f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666) + if err != nil { + return err + } + _, err = f.WriteString(address) + f.Close() + if err != nil { + return err + } + return os.Rename(tempPath, path) +} + +const ( + abstractSocketPrefix = "\x00" + socketPathLimit = 106 +) + +type socket string + +func (s socket) isAbstract() bool { + return !strings.HasPrefix(string(s), "unix://") +} + +func (s socket) path() string { + path := strings.TrimPrefix(string(s), "unix://") + // if there was no trim performed, we assume an abstract socket + if len(path) == len(s) { + path = abstractSocketPrefix + path + } + return path +} + func newSocket(address string) (*net.UnixListener, error) { - if len(address) > 106 { - return nil, errors.Errorf("%q: unix socket path too long (> 106)", address) + if len(address) > socketPathLimit { + return nil, errors.Errorf("%q: unix socket path too long (> %d)", address, socketPathLimit) + } + var ( + sock = socket(address) + path = sock.path() + ) + if !sock.isAbstract() { + if err := os.MkdirAll(filepath.Dir(path), 0600); err != nil { + return nil, errors.Wrapf(err, "%s", path) + } } - l, err := net.Listen("unix", "\x00"+address) + l, err := net.Listen("unix", path) if err != nil { - return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address) + return nil, errors.Wrapf(err, "failed to listen to unix socket %q (abstract: %t)", address, sock.isAbstract()) + } + if err := os.Chmod(path, 0600); err != nil { + l.Close() + return nil, err } return l.(*net.UnixListener), nil } +// RemoveSocket removes the socket at the specified address if +// it exists on the filesystem +func RemoveSocket(address string) error { + sock := socket(address) + if !sock.isAbstract() { + return os.Remove(sock.path()) + } + return nil +} + func connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) { return d(address, 100*time.Second) } -func annonDialer(address string, timeout time.Duration) (net.Conn, error) { - address = strings.TrimPrefix(address, "unix://") - return net.DialTimeout("unix", "\x00"+address, timeout) +func anonDialer(address string, timeout time.Duration) (net.Conn, error) { + return dialer.Dialer(socket(address).path(), timeout) } // WithConnect connects to an existing shim func WithConnect(address string, onClose func()) Opt { return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) { - conn, err := connect(address, annonDialer) + conn, err := connect(address, anonDialer) if err != nil { return nil, nil, err } - client := ttrpc.NewClient(conn) - client.OnClose(onClose) + client := ttrpc.NewClient(conn, ttrpc.WithOnClose(onClose)) return shimapi.NewShimClient(client), conn, nil } } @@ -233,7 +375,7 @@ return c.signalShim(ctx, unix.SIGKILL) } -// Close the cient connection +// Close the client connection func (c *Client) Close() error { if c.c == nil { return nil @@ -258,21 +400,31 @@ select { case <-ctx.Done(): return ctx.Err() - case <-c.waitForExit(pid): + case <-c.waitForExit(ctx, pid): return nil } } -func (c *Client) waitForExit(pid int) <-chan struct{} { - c.exitOnce.Do(func() { +func (c *Client) waitForExit(ctx context.Context, pid int) <-chan struct{} { + go c.exitOnce.Do(func() { + defer close(c.exitCh) + + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + for { // use kill(pid, 0) here because the shim could have been reparented // and we are no longer able to waitpid(pid, ...) on the shim if err := unix.Kill(pid, 0); err == unix.ESRCH { - close(c.exitCh) return } - time.Sleep(10 * time.Millisecond) + + select { + case <-ticker.C: + case <-ctx.Done(): + log.G(ctx).WithField("pid", pid).Warn("timed out while waiting for shim to exit") + return + } } }) return c.exitCh diff -Nru containerd-1.2.6/runtime/v1/shim/reaper.go containerd-1.5.9/runtime/v1/shim/reaper.go --- containerd-1.2.6/runtime/v1/shim/reaper.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/reaper.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package shim - -import ( - "os/exec" - "sync" - "time" - - "github.com/containerd/containerd/sys" - runc "github.com/containerd/go-runc" - "github.com/pkg/errors" -) - -// ErrNoSuchProcess is returned when the process no longer exists -var ErrNoSuchProcess = errors.New("no such process") - -const bufferSize = 2048 - -// Reap should be called when the process receives an SIGCHLD. Reap will reap -// all exited processes and close their wait channels -func Reap() error { - now := time.Now() - exits, err := sys.Reap(false) - Default.Lock() - for c := range Default.subscribers { - for _, e := range exits { - c <- runc.Exit{ - Timestamp: now, - Pid: e.Pid, - Status: e.Status, - } - } - } - Default.Unlock() - return err -} - -// Default is the default monitor initialized for the package -var Default = &Monitor{ - subscribers: make(map[chan runc.Exit]struct{}), -} - -// Monitor monitors the underlying system for process status changes -type Monitor struct { - sync.Mutex - - subscribers map[chan runc.Exit]struct{} -} - -// Start starts the command a registers the process with the reaper -func (m *Monitor) Start(c *exec.Cmd) (chan runc.Exit, error) { - ec := m.Subscribe() - if err := c.Start(); err != nil { - m.Unsubscribe(ec) - return nil, err - } - return ec, nil -} - -// Wait blocks until a process is signal as dead. -// User should rely on the value of the exit status to determine if the -// command was successful or not. -func (m *Monitor) Wait(c *exec.Cmd, ec chan runc.Exit) (int, error) { - for e := range ec { - if e.Pid == c.Process.Pid { - // make sure we flush all IO - c.Wait() - m.Unsubscribe(ec) - return e.Status, nil - } - } - // return no such process if the ec channel is closed and no more exit - // events will be sent - return -1, ErrNoSuchProcess -} - -// Subscribe to process exit changes -func (m *Monitor) Subscribe() chan runc.Exit { - c := make(chan runc.Exit, bufferSize) - m.Lock() - m.subscribers[c] = struct{}{} - m.Unlock() - return c -} - -// Unsubscribe to process exit changes -func (m *Monitor) Unsubscribe(c chan runc.Exit) { - m.Lock() - delete(m.subscribers, c) - close(c) - m.Unlock() -} diff -Nru containerd-1.2.6/runtime/v1/shim/service.go containerd-1.5.9/runtime/v1/shim/service.go --- containerd-1.2.6/runtime/v1/shim/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -35,11 +35,12 @@ "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" - rproc "github.com/containerd/containerd/runtime/proc" - "github.com/containerd/containerd/runtime/v1/linux/proc" shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" + "github.com/containerd/containerd/sys/reaper" runc "github.com/containerd/go-runc" "github.com/containerd/typeurl" ptypes "github.com/gogo/protobuf/types" @@ -54,7 +55,7 @@ empty = &ptypes.Empty{} bufPool = sync.Pool{ New: func() interface{} { - buffer := make([]byte, 32<<10) + buffer := make([]byte, 4096) return &buffer }, } @@ -84,9 +85,9 @@ s := &Service{ config: config, context: ctx, - processes: make(map[string]rproc.Process), + processes: make(map[string]process.Process), events: make(chan interface{}, 128), - ec: Default.Subscribe(), + ec: reaper.Default.Subscribe(), } go s.processExits() if err := s.initPlatform(); err != nil { @@ -102,9 +103,9 @@ config Config context context.Context - processes map[string]rproc.Process + processes map[string]process.Process events chan interface{} - platform rproc.Platform + platform stdio.Platform ec chan runc.Exit // Filled by Create() @@ -114,9 +115,9 @@ // Create a new initial process and container with the underlying OCI runtime func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *shimapi.CreateTaskResponse, err error) { - var mounts []proc.Mount + var mounts []process.Mount for _, m := range r.Rootfs { - mounts = append(mounts, proc.Mount{ + mounts = append(mounts, process.Mount{ Type: m.Type, Source: m.Source, Target: m.Target, @@ -124,7 +125,15 @@ }) } - config := &proc.CreateConfig{ + rootfs := "" + if len(mounts) > 0 { + rootfs = filepath.Join(r.Bundle, "rootfs") + if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) { + return nil, err + } + } + + config := &process.CreateConfig{ ID: r.ID, Bundle: r.Bundle, Runtime: r.Runtime, @@ -137,7 +146,6 @@ ParentCheckpoint: r.ParentCheckpoint, Options: r.Options, } - rootfs := filepath.Join(r.Bundle, "rootfs") defer func() { if err != nil { if err2 := mount.UnmountAll(rootfs, 0); err2 != nil { @@ -169,6 +177,7 @@ s.config.SystemdCgroup, s.platform, config, + rootfs, ) if err != nil { return nil, errdefs.ToGRPC(err) @@ -208,7 +217,7 @@ return nil, err } if err := p.Delete(ctx); err != nil { - return nil, err + return nil, errdefs.ToGRPC(err) } s.mu.Lock() delete(s.processes, s.id) @@ -231,7 +240,7 @@ return nil, err } if err := p.Delete(ctx); err != nil { - return nil, err + return nil, errdefs.ToGRPC(err) } s.mu.Lock() delete(s.processes, r.ID) @@ -258,7 +267,7 @@ return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") } - process, err := p.(*proc.Init).Exec(ctx, s.config.Path, &proc.ExecConfig{ + process, err := p.(*process.Init).Exec(ctx, s.config.Path, &process.ExecConfig{ ID: r.ID, Terminal: r.Terminal, Stdin: r.Stdin, @@ -340,7 +349,7 @@ if err != nil { return nil, err } - if err := p.(*proc.Init).Pause(ctx); err != nil { + if err := p.(*process.Init).Pause(ctx); err != nil { return nil, err } return empty, nil @@ -352,7 +361,7 @@ if err != nil { return nil, err } - if err := p.(*proc.Init).Resume(ctx); err != nil { + if err := p.(*process.Init).Resume(ctx); err != nil { return nil, err } return empty, nil @@ -388,6 +397,9 @@ return nil, errdefs.ToGRPC(err) } var processes []*task.ProcessInfo + + s.mu.Lock() + defer s.mu.Unlock() for _, pid := range pids { pInfo := task.ProcessInfo{ Pid: pid, @@ -440,7 +452,7 @@ } options = *v.(*runctypes.CheckpointOptions) } - if err := p.(*proc.Init).Checkpoint(ctx, &proc.CheckpointConfig{ + if err := p.(*process.Init).Checkpoint(ctx, &process.CheckpointConfig{ Path: r.Path, Exit: options.Exit, AllowOpenTCP: options.OpenTcp, @@ -448,6 +460,7 @@ AllowTerminal: options.Terminal, FileLocks: options.FileLocks, EmptyNamespaces: options.EmptyNamespaces, + WorkDir: options.WorkPath, }); err != nil { return nil, errdefs.ToGRPC(err) } @@ -467,7 +480,7 @@ if err != nil { return nil, err } - if err := p.(*proc.Init).Update(ctx, r.Resources); err != nil { + if err := p.(*process.Init).Update(ctx, r.Resources); err != nil { return nil, errdefs.ToGRPC(err) } return empty, nil @@ -493,65 +506,59 @@ } } -func (s *Service) allProcesses() []rproc.Process { +func (s *Service) checkProcesses(e runc.Exit) { + var p process.Process s.mu.Lock() - defer s.mu.Unlock() - - res := make([]rproc.Process, 0, len(s.processes)) - for _, p := range s.processes { - res = append(res, p) + for _, proc := range s.processes { + if proc.Pid() == e.Pid { + p = proc + break + } } - return res -} - -func (s *Service) checkProcesses(e runc.Exit) { - shouldKillAll, err := shouldKillAllOnExit(s.bundle) - if err != nil { - log.G(s.context).WithError(err).Error("failed to check shouldKillAll") + s.mu.Unlock() + if p == nil { + log.G(s.context).Debugf("process with id:%d wasn't found", e.Pid) + return } - - for _, p := range s.allProcesses() { - if p.Pid() == e.Pid { - - if shouldKillAll { - 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") - } - } + if ip, ok := p.(*process.Init); ok { + // Ensure all children are killed + if shouldKillAllOnExit(s.context, s.bundle) { + if err := ip.KillAll(s.context); err != nil { + log.G(s.context).WithError(err).WithField("id", ip.ID()). + Error("failed to kill init's children") } - p.SetExited(e.Status) - s.events <- &eventstypes.TaskExit{ - ContainerID: s.id, - ID: p.ID(), - Pid: uint32(e.Pid), - ExitStatus: uint32(e.Status), - ExitedAt: p.ExitedAt(), - } - return } } + + p.SetExited(e.Status) + s.events <- &eventstypes.TaskExit{ + ContainerID: s.id, + ID: p.ID(), + Pid: uint32(e.Pid), + ExitStatus: uint32(e.Status), + ExitedAt: p.ExitedAt(), + } } -func shouldKillAllOnExit(bundlePath string) (bool, error) { +func shouldKillAllOnExit(ctx context.Context, bundlePath string) bool { var bundleSpec specs.Spec bundleConfigContents, err := ioutil.ReadFile(filepath.Join(bundlePath, "config.json")) if err != nil { - return false, err + log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to read config.json") + return true + } + if err := json.Unmarshal(bundleConfigContents, &bundleSpec); err != nil { + log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to unmarshal bundle json") + return true } - json.Unmarshal(bundleConfigContents, &bundleSpec) - if bundleSpec.Linux != nil { for _, ns := range bundleSpec.Linux.Namespaces { - if ns.Type == specs.PIDNamespace { - return false, nil + if ns.Type == specs.PIDNamespace && ns.Path == "" { + return false } } } - - return true, nil + return true } func (s *Service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { @@ -560,7 +567,7 @@ return nil, err } - ps, err := p.(*proc.Init).Runtime().Ps(ctx, id) + ps, err := p.(*process.Init).Runtime().Ps(ctx, id) if err != nil { return nil, err } @@ -580,7 +587,7 @@ } // getInitProcess returns initial process -func (s *Service) getInitProcess() (rproc.Process, error) { +func (s *Service) getInitProcess() (process.Process, error) { s.mu.Lock() defer s.mu.Unlock() @@ -592,7 +599,7 @@ } // getExecProcess returns exec process -func (s *Service) getExecProcess(id string) (rproc.Process, error) { +func (s *Service) getExecProcess(id string) (process.Process, error) { s.mu.Lock() defer s.mu.Unlock() @@ -631,7 +638,7 @@ return runtime.TaskUnknownTopic } -func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace, criu string, systemdCgroup bool, platform rproc.Platform, r *proc.CreateConfig) (*proc.Init, error) { +func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace, criu string, systemdCgroup bool, platform stdio.Platform, r *process.CreateConfig, rootfs string) (*process.Init, error) { var options runctypes.CreateOptions if r.Options != nil { v, err := typeurl.UnmarshalAny(r.Options) @@ -641,9 +648,8 @@ options = *v.(*runctypes.CreateOptions) } - rootfs := filepath.Join(path, "rootfs") - runtime := proc.NewRunc(runtimeRoot, path, namespace, r.Runtime, criu, systemdCgroup) - p := proc.New(r.ID, runtime, rproc.Stdio{ + runtime := process.NewRunc(runtimeRoot, path, namespace, r.Runtime, criu, systemdCgroup) + p := process.New(r.ID, runtime, stdio.Stdio{ Stdin: r.Stdin, Stdout: r.Stdout, Stderr: r.Stderr, @@ -657,5 +663,11 @@ p.IoGID = int(options.IoGid) p.NoPivotRoot = options.NoPivotRoot p.NoNewKeyring = options.NoNewKeyring + p.CriuWorkPath = options.CriuWorkPath + if p.CriuWorkPath == "" { + // if criu work path not set, use container WorkDir + p.CriuWorkPath = p.WorkDir + } + return p, nil } diff -Nru containerd-1.2.6/runtime/v1/shim/service_linux.go containerd-1.5.9/runtime/v1/shim/service_linux.go --- containerd-1.2.6/runtime/v1/shim/service_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/service_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,10 +19,14 @@ import ( "context" "io" + "net/url" + "os" "sync" "syscall" "github.com/containerd/console" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/process" "github.com/containerd/fifo" "github.com/pkg/errors" ) @@ -31,7 +35,7 @@ epoller *console.Epoller } -func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) (console.Console, error) { +func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { if p.epoller == nil { return nil, errors.New("uninitialized epoller") } @@ -40,6 +44,7 @@ if err != nil { return nil, err } + var cwg sync.WaitGroup if stdin != "" { in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0) @@ -54,29 +59,102 @@ io.CopyBuffer(epollConsole, in, *bp) // we need to shutdown epollConsole when pipe broken epollConsole.Shutdown(p.epoller.CloseConsole) + epollConsole.Close() }() } - outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + uri, err := url.Parse(stdout) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to parse stdout uri") } - outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) - if err != nil { - return nil, err + + switch uri.Scheme { + case "binary": + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + cmd := process.NewBinaryCmd(uri, id, ns) + + // In case of unexpected errors during logging binary start, close open pipes + var filesToClose []*os.File + + defer func() { + if retErr != nil { + process.CloseFiles(filesToClose...) + } + }() + + // Create pipe to be used by logging binary for Stdout + outR, outW, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stdout pipes") + } + filesToClose = append(filesToClose, outR) + + // Stderr is created for logging binary but unused when terminal is true + serrR, _, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stderr pipes") + } + filesToClose = append(filesToClose, serrR) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + filesToClose = append(filesToClose, r) + + cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) + + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + io.Copy(outW, epollConsole) + outW.Close() + wg.Done() + }() + + if err := cmd.Start(); err != nil { + return nil, errors.Wrap(err, "failed to start logging binary process") + } + + // Close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, errors.Wrap(err, "failed to close write pipe after start") + } + + // Wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, errors.Wrap(err, "failed to read from logging binary") + } + cwg.Wait() + + default: + outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + if err != nil { + return nil, err + } + outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + io.CopyBuffer(outw, epollConsole, *p) + outw.Close() + outr.Close() + wg.Done() + }() + cwg.Wait() } - wg.Add(1) - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - io.CopyBuffer(outw, epollConsole, *p) - epollConsole.Close() - outr.Close() - outw.Close() - wg.Done() - }() return epollConsole, nil } diff -Nru containerd-1.2.6/runtime/v1/shim/service_unix.go containerd-1.5.9/runtime/v1/shim/service_unix.go --- containerd-1.2.6/runtime/v1/shim/service_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/service_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,17 +21,23 @@ import ( "context" "io" + "net/url" + "os" "sync" "syscall" "github.com/containerd/console" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/process" "github.com/containerd/fifo" + "github.com/pkg/errors" ) type unixPlatform struct { } -func (p *unixPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) (console.Console, error) { +func (p *unixPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { + var cwg sync.WaitGroup if stdin != "" { in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0) if err != nil { @@ -46,27 +52,97 @@ io.CopyBuffer(console, in, *p) }() } - outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + uri, err := url.Parse(stdout) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to parse stdout uri") } - outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) - if err != nil { - return nil, err + + switch uri.Scheme { + case "binary": + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + cmd := process.NewBinaryCmd(uri, id, ns) + + // In case of unexpected errors during logging binary start, close open pipes + var filesToClose []*os.File + + defer func() { + if retErr != nil { + process.CloseFiles(filesToClose...) + } + }() + + // Create pipe to be used by logging binary for Stdout + outR, outW, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stdout pipes") + } + filesToClose = append(filesToClose, outR) + + // Stderr is created for logging binary but unused when terminal is true + serrR, _, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stderr pipes") + } + filesToClose = append(filesToClose, serrR) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + filesToClose = append(filesToClose, r) + + cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) + + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + io.Copy(outW, console) + outW.Close() + wg.Done() + }() + + if err := cmd.Start(); err != nil { + return nil, errors.Wrap(err, "failed to start logging binary process") + } + + // Close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, errors.Wrap(err, "failed to close write pipe after start") + } + + // Wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, errors.Wrap(err, "failed to read from logging binary") + } + cwg.Wait() + + default: + outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + if err != nil { + return nil, err + } + outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + io.CopyBuffer(outw, console, *p) + outw.Close() + outr.Close() + wg.Done() + }() + cwg.Wait() } - wg.Add(1) - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - - io.CopyBuffer(outw, console, *p) - console.Close() - outr.Close() - outw.Close() - wg.Done() - }() return console, nil } diff -Nru containerd-1.2.6/runtime/v1/shim/v1/shim.pb.go containerd-1.5.9/runtime/v1/shim/v1/shim.pb.go --- containerd-1.2.6/runtime/v1/shim/v1/shim.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/v1/shim.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,58 +1,24 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/runtime/v1/shim/v1/shim.proto -/* - Package shim is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/runtime/v1/shim/v1/shim.proto - - It has these top-level messages: - CreateTaskRequest - CreateTaskResponse - DeleteResponse - DeleteProcessRequest - ExecProcessRequest - ExecProcessResponse - ResizePtyRequest - StateRequest - StateResponse - KillRequest - CloseIORequest - ListPidsRequest - ListPidsResponse - CheckpointTaskRequest - ShimInfoResponse - UpdateTaskRequest - StartRequest - StartResponse - WaitRequest - WaitResponse -*/ package shim -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/types" -import google_protobuf1 "github.com/gogo/protobuf/types" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import _ "github.com/gogo/protobuf/types" -import containerd_types "github.com/containerd/containerd/api/types" -import containerd_v1_types "github.com/containerd/containerd/api/types/task" - -import time "time" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import context "context" -import ttrpc "github.com/containerd/ttrpc" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + task "github.com/containerd/containerd/api/types/task" + github_com_containerd_ttrpc "github.com/containerd/ttrpc" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types1 "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -64,200 +30,820 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type CreateTaskRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` - Runtime string `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"` - Rootfs []*containerd_types.Mount `protobuf:"bytes,4,rep,name=rootfs" json:"rootfs,omitempty"` - Terminal bool `protobuf:"varint,5,opt,name=terminal,proto3" json:"terminal,omitempty"` - Stdin string `protobuf:"bytes,6,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,7,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,8,opt,name=stderr,proto3" json:"stderr,omitempty"` - Checkpoint string `protobuf:"bytes,9,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` - ParentCheckpoint string `protobuf:"bytes,10,opt,name=parent_checkpoint,json=parentCheckpoint,proto3" json:"parent_checkpoint,omitempty"` - Options *google_protobuf.Any `protobuf:"bytes,11,opt,name=options" json:"options,omitempty"` -} - -func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } -func (*CreateTaskRequest) ProtoMessage() {} -func (*CreateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{0} } + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Runtime string `protobuf:"bytes,3,opt,name=runtime,proto3" json:"runtime,omitempty"` + Rootfs []*types.Mount `protobuf:"bytes,4,rep,name=rootfs,proto3" json:"rootfs,omitempty"` + Terminal bool `protobuf:"varint,5,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,6,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,7,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,8,opt,name=stderr,proto3" json:"stderr,omitempty"` + Checkpoint string `protobuf:"bytes,9,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + ParentCheckpoint string `protobuf:"bytes,10,opt,name=parent_checkpoint,json=parentCheckpoint,proto3" json:"parent_checkpoint,omitempty"` + Options *types1.Any `protobuf:"bytes,11,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } +func (*CreateTaskRequest) ProtoMessage() {} +func (*CreateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{0} +} +func (m *CreateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskRequest.Merge(m, src) +} +func (m *CreateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateTaskRequest proto.InternalMessageInfo type CreateTaskResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } +func (*CreateTaskResponse) ProtoMessage() {} +func (*CreateTaskResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{1} +} +func (m *CreateTaskResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskResponse.Merge(m, src) +} +func (m *CreateTaskResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskResponse.DiscardUnknown(m) } -func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } -func (*CreateTaskResponse) ProtoMessage() {} -func (*CreateTaskResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{1} } +var xxx_messageInfo_CreateTaskResponse proto.InternalMessageInfo type DeleteResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - ExitStatus uint32 `protobuf:"varint,2,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,3,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + ExitStatus uint32 `protobuf:"varint,2,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,3,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{2} +} +func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResponse.Merge(m, src) +} +func (m *DeleteResponse) XXX_Size() int { + return m.Size() +} +func (m *DeleteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResponse.DiscardUnknown(m) } -func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } -func (*DeleteResponse) ProtoMessage() {} -func (*DeleteResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{2} } +var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo type DeleteProcessRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteProcessRequest) Reset() { *m = DeleteProcessRequest{} } +func (*DeleteProcessRequest) ProtoMessage() {} +func (*DeleteProcessRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{3} +} +func (m *DeleteProcessRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteProcessRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteProcessRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteProcessRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteProcessRequest.Merge(m, src) +} +func (m *DeleteProcessRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteProcessRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteProcessRequest.DiscardUnknown(m) } -func (m *DeleteProcessRequest) Reset() { *m = DeleteProcessRequest{} } -func (*DeleteProcessRequest) ProtoMessage() {} -func (*DeleteProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{3} } +var xxx_messageInfo_DeleteProcessRequest proto.InternalMessageInfo type ExecProcessRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Terminal bool `protobuf:"varint,2,opt,name=terminal,proto3" json:"terminal,omitempty"` - Stdin string `protobuf:"bytes,3,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,4,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,5,opt,name=stderr,proto3" json:"stderr,omitempty"` - Spec *google_protobuf.Any `protobuf:"bytes,6,opt,name=spec" json:"spec,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Terminal bool `protobuf:"varint,2,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,3,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,4,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,5,opt,name=stderr,proto3" json:"stderr,omitempty"` + Spec *types1.Any `protobuf:"bytes,6,opt,name=spec,proto3" json:"spec,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } +func (*ExecProcessRequest) ProtoMessage() {} +func (*ExecProcessRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{4} +} +func (m *ExecProcessRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessRequest.Merge(m, src) +} +func (m *ExecProcessRequest) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessRequest.DiscardUnknown(m) } -func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } -func (*ExecProcessRequest) ProtoMessage() {} -func (*ExecProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{4} } +var xxx_messageInfo_ExecProcessRequest proto.InternalMessageInfo type ExecProcessResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } +func (*ExecProcessResponse) ProtoMessage() {} +func (*ExecProcessResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{5} +} +func (m *ExecProcessResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessResponse.Merge(m, src) +} +func (m *ExecProcessResponse) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessResponse.DiscardUnknown(m) } -func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } -func (*ExecProcessResponse) ProtoMessage() {} -func (*ExecProcessResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{5} } +var xxx_messageInfo_ExecProcessResponse proto.InternalMessageInfo type ResizePtyRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Width uint32 `protobuf:"varint,2,opt,name=width,proto3" json:"width,omitempty"` - Height uint32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Width uint32 `protobuf:"varint,2,opt,name=width,proto3" json:"width,omitempty"` + Height uint32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } +func (*ResizePtyRequest) ProtoMessage() {} +func (*ResizePtyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{6} +} +func (m *ResizePtyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResizePtyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResizePtyRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResizePtyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResizePtyRequest.Merge(m, src) +} +func (m *ResizePtyRequest) XXX_Size() int { + return m.Size() +} +func (m *ResizePtyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResizePtyRequest.DiscardUnknown(m) } -func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } -func (*ResizePtyRequest) ProtoMessage() {} -func (*ResizePtyRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{6} } +var xxx_messageInfo_ResizePtyRequest proto.InternalMessageInfo type StateRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StateRequest) Reset() { *m = StateRequest{} } +func (*StateRequest) ProtoMessage() {} +func (*StateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{7} +} +func (m *StateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StateRequest.Merge(m, src) +} +func (m *StateRequest) XXX_Size() int { + return m.Size() +} +func (m *StateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StateRequest.DiscardUnknown(m) } -func (m *StateRequest) Reset() { *m = StateRequest{} } -func (*StateRequest) ProtoMessage() {} -func (*StateRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{7} } +var xxx_messageInfo_StateRequest proto.InternalMessageInfo type StateResponse struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` - Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` - Status containerd_v1_types.Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` - Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` - Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` - ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + Status task.Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` + ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StateResponse) Reset() { *m = StateResponse{} } +func (*StateResponse) ProtoMessage() {} +func (*StateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{8} +} +func (m *StateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StateResponse.Merge(m, src) +} +func (m *StateResponse) XXX_Size() int { + return m.Size() +} +func (m *StateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StateResponse.DiscardUnknown(m) } -func (m *StateResponse) Reset() { *m = StateResponse{} } -func (*StateResponse) ProtoMessage() {} -func (*StateResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{8} } +var xxx_messageInfo_StateResponse proto.InternalMessageInfo type KillRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Signal uint32 `protobuf:"varint,2,opt,name=signal,proto3" json:"signal,omitempty"` - All bool `protobuf:"varint,3,opt,name=all,proto3" json:"all,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Signal uint32 `protobuf:"varint,2,opt,name=signal,proto3" json:"signal,omitempty"` + All bool `protobuf:"varint,3,opt,name=all,proto3" json:"all,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KillRequest) Reset() { *m = KillRequest{} } +func (*KillRequest) ProtoMessage() {} +func (*KillRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{9} +} +func (m *KillRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KillRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KillRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *KillRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_KillRequest.Merge(m, src) +} +func (m *KillRequest) XXX_Size() int { + return m.Size() +} +func (m *KillRequest) XXX_DiscardUnknown() { + xxx_messageInfo_KillRequest.DiscardUnknown(m) } -func (m *KillRequest) Reset() { *m = KillRequest{} } -func (*KillRequest) ProtoMessage() {} -func (*KillRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{9} } +var xxx_messageInfo_KillRequest proto.InternalMessageInfo type CloseIORequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Stdin bool `protobuf:"varint,2,opt,name=stdin,proto3" json:"stdin,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Stdin bool `protobuf:"varint,2,opt,name=stdin,proto3" json:"stdin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } +func (*CloseIORequest) ProtoMessage() {} +func (*CloseIORequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{10} +} +func (m *CloseIORequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CloseIORequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CloseIORequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CloseIORequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CloseIORequest.Merge(m, src) +} +func (m *CloseIORequest) XXX_Size() int { + return m.Size() +} +func (m *CloseIORequest) XXX_DiscardUnknown() { + xxx_messageInfo_CloseIORequest.DiscardUnknown(m) } -func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } -func (*CloseIORequest) ProtoMessage() {} -func (*CloseIORequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{10} } +var xxx_messageInfo_CloseIORequest proto.InternalMessageInfo type ListPidsRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListPidsRequest) Reset() { *m = ListPidsRequest{} } +func (*ListPidsRequest) ProtoMessage() {} +func (*ListPidsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{11} +} +func (m *ListPidsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListPidsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListPidsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListPidsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListPidsRequest.Merge(m, src) +} +func (m *ListPidsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListPidsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListPidsRequest.DiscardUnknown(m) } -func (m *ListPidsRequest) Reset() { *m = ListPidsRequest{} } -func (*ListPidsRequest) ProtoMessage() {} -func (*ListPidsRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{11} } +var xxx_messageInfo_ListPidsRequest proto.InternalMessageInfo type ListPidsResponse struct { - Processes []*containerd_v1_types.ProcessInfo `protobuf:"bytes,1,rep,name=processes" json:"processes,omitempty"` + Processes []*task.ProcessInfo `protobuf:"bytes,1,rep,name=processes,proto3" json:"processes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListPidsResponse) Reset() { *m = ListPidsResponse{} } +func (*ListPidsResponse) ProtoMessage() {} +func (*ListPidsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{12} +} +func (m *ListPidsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListPidsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListPidsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListPidsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListPidsResponse.Merge(m, src) +} +func (m *ListPidsResponse) XXX_Size() int { + return m.Size() +} +func (m *ListPidsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListPidsResponse.DiscardUnknown(m) } -func (m *ListPidsResponse) Reset() { *m = ListPidsResponse{} } -func (*ListPidsResponse) ProtoMessage() {} -func (*ListPidsResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{12} } +var xxx_messageInfo_ListPidsResponse proto.InternalMessageInfo type CheckpointTaskRequest struct { - Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` - Options *google_protobuf.Any `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Options *types1.Any `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } +func (*CheckpointTaskRequest) ProtoMessage() {} +func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{13} +} +func (m *CheckpointTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointTaskRequest.Merge(m, src) +} +func (m *CheckpointTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CheckpointTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointTaskRequest.DiscardUnknown(m) } -func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } -func (*CheckpointTaskRequest) ProtoMessage() {} -func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{13} } +var xxx_messageInfo_CheckpointTaskRequest proto.InternalMessageInfo type ShimInfoResponse struct { - ShimPid uint32 `protobuf:"varint,1,opt,name=shim_pid,json=shimPid,proto3" json:"shim_pid,omitempty"` + ShimPid uint32 `protobuf:"varint,1,opt,name=shim_pid,json=shimPid,proto3" json:"shim_pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ShimInfoResponse) Reset() { *m = ShimInfoResponse{} } +func (*ShimInfoResponse) ProtoMessage() {} +func (*ShimInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{14} +} +func (m *ShimInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ShimInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ShimInfoResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ShimInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShimInfoResponse.Merge(m, src) +} +func (m *ShimInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *ShimInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ShimInfoResponse.DiscardUnknown(m) } -func (m *ShimInfoResponse) Reset() { *m = ShimInfoResponse{} } -func (*ShimInfoResponse) ProtoMessage() {} -func (*ShimInfoResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{14} } +var xxx_messageInfo_ShimInfoResponse proto.InternalMessageInfo type UpdateTaskRequest struct { - Resources *google_protobuf.Any `protobuf:"bytes,1,opt,name=resources" json:"resources,omitempty"` + Resources *types1.Any `protobuf:"bytes,1,opt,name=resources,proto3" json:"resources,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } +func (*UpdateTaskRequest) ProtoMessage() {} +func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{15} +} +func (m *UpdateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateTaskRequest.Merge(m, src) +} +func (m *UpdateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateTaskRequest.DiscardUnknown(m) } -func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } -func (*UpdateTaskRequest) ProtoMessage() {} -func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{15} } +var xxx_messageInfo_UpdateTaskRequest proto.InternalMessageInfo type StartRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartRequest) Reset() { *m = StartRequest{} } +func (*StartRequest) ProtoMessage() {} +func (*StartRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{16} +} +func (m *StartRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartRequest.Merge(m, src) +} +func (m *StartRequest) XXX_Size() int { + return m.Size() +} +func (m *StartRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StartRequest.DiscardUnknown(m) } -func (m *StartRequest) Reset() { *m = StartRequest{} } -func (*StartRequest) ProtoMessage() {} -func (*StartRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{16} } +var xxx_messageInfo_StartRequest proto.InternalMessageInfo type StartResponse struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartResponse) Reset() { *m = StartResponse{} } +func (*StartResponse) ProtoMessage() {} +func (*StartResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{17} +} +func (m *StartResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartResponse.Merge(m, src) +} +func (m *StartResponse) XXX_Size() int { + return m.Size() +} +func (m *StartResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StartResponse.DiscardUnknown(m) } -func (m *StartResponse) Reset() { *m = StartResponse{} } -func (*StartResponse) ProtoMessage() {} -func (*StartResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{17} } +var xxx_messageInfo_StartResponse proto.InternalMessageInfo type WaitRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitRequest) Reset() { *m = WaitRequest{} } +func (*WaitRequest) ProtoMessage() {} +func (*WaitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{18} +} +func (m *WaitRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitRequest.Merge(m, src) +} +func (m *WaitRequest) XXX_Size() int { + return m.Size() +} +func (m *WaitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WaitRequest.DiscardUnknown(m) } -func (m *WaitRequest) Reset() { *m = WaitRequest{} } -func (*WaitRequest) ProtoMessage() {} -func (*WaitRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{18} } +var xxx_messageInfo_WaitRequest proto.InternalMessageInfo type WaitResponse struct { - ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitResponse) Reset() { *m = WaitResponse{} } +func (*WaitResponse) ProtoMessage() {} +func (*WaitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_be1b2ef30ea3b8ef, []int{19} +} +func (m *WaitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitResponse.Merge(m, src) +} +func (m *WaitResponse) XXX_Size() int { + return m.Size() +} +func (m *WaitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_WaitResponse.DiscardUnknown(m) } -func (m *WaitResponse) Reset() { *m = WaitResponse{} } -func (*WaitResponse) ProtoMessage() {} -func (*WaitResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{19} } +var xxx_messageInfo_WaitResponse proto.InternalMessageInfo func init() { proto.RegisterType((*CreateTaskRequest)(nil), "containerd.runtime.linux.shim.v1.CreateTaskRequest") @@ -281,10 +867,90 @@ proto.RegisterType((*WaitRequest)(nil), "containerd.runtime.linux.shim.v1.WaitRequest") proto.RegisterType((*WaitResponse)(nil), "containerd.runtime.linux.shim.v1.WaitResponse") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/runtime/v1/shim/v1/shim.proto", fileDescriptor_be1b2ef30ea3b8ef) +} + +var fileDescriptor_be1b2ef30ea3b8ef = []byte{ + // 1133 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x4f, 0x4f, 0x1b, 0x47, + 0x14, 0x67, 0x17, 0xff, 0x7d, 0x8e, 0x29, 0x4c, 0x09, 0xdd, 0x38, 0x92, 0xb1, 0x56, 0x6a, 0x44, + 0x55, 0x65, 0x5d, 0x4c, 0x95, 0xa4, 0xad, 0x84, 0x04, 0x24, 0xaa, 0x50, 0x1b, 0x05, 0x2d, 0xa4, + 0x89, 0x5a, 0x55, 0x68, 0xf1, 0x0e, 0xf6, 0x08, 0x7b, 0x67, 0xb3, 0x33, 0x4b, 0xa1, 0xa7, 0x9e, + 0x7a, 0xee, 0xc7, 0xe9, 0x47, 0xe0, 0x90, 0x43, 0x8f, 0x3d, 0xa5, 0x0d, 0xf7, 0x7e, 0x87, 0x6a, + 0xfe, 0x18, 0xaf, 0x6d, 0x36, 0xbb, 0x70, 0xc1, 0xfb, 0x66, 0x7e, 0x6f, 0xe6, 0xcd, 0xfb, 0xfd, + 0xe6, 0xbd, 0x01, 0x36, 0x7b, 0x84, 0xf7, 0xe3, 0x23, 0xa7, 0x4b, 0x87, 0xed, 0x2e, 0x0d, 0xb8, + 0x47, 0x02, 0x1c, 0xf9, 0xc9, 0xcf, 0x28, 0x0e, 0x38, 0x19, 0xe2, 0xf6, 0xe9, 0x7a, 0x9b, 0xf5, + 0xc9, 0x70, 0xf4, 0xeb, 0x84, 0x11, 0xe5, 0x14, 0xb5, 0xc6, 0x48, 0x47, 0x23, 0x9d, 0x01, 0x09, + 0xe2, 0x33, 0x47, 0x82, 0x4e, 0xd7, 0x1b, 0xf7, 0x7a, 0x94, 0xf6, 0x06, 0xb8, 0x2d, 0xf1, 0x47, + 0xf1, 0x71, 0xdb, 0x0b, 0xce, 0x95, 0x73, 0xe3, 0xfe, 0xf4, 0x14, 0x1e, 0x86, 0x7c, 0x34, 0xb9, + 0xdc, 0xa3, 0x3d, 0x2a, 0x3f, 0xdb, 0xe2, 0x4b, 0x8f, 0xae, 0x4e, 0xbb, 0x88, 0x1d, 0x19, 0xf7, + 0x86, 0xa1, 0x06, 0x3c, 0xca, 0x3c, 0x90, 0x17, 0x92, 0x36, 0x3f, 0x0f, 0x31, 0x6b, 0x0f, 0x69, + 0x1c, 0x70, 0xed, 0xf7, 0xf5, 0x0d, 0xfc, 0xb8, 0xc7, 0x4e, 0xe4, 0x1f, 0xe5, 0x6b, 0xff, 0x67, + 0xc2, 0xd2, 0x4e, 0x84, 0x3d, 0x8e, 0x0f, 0x3c, 0x76, 0xe2, 0xe2, 0x37, 0x31, 0x66, 0x1c, 0xad, + 0x80, 0x49, 0x7c, 0xcb, 0x68, 0x19, 0x6b, 0xd5, 0xed, 0xd2, 0xe5, 0xbb, 0x55, 0x73, 0xf7, 0xa9, + 0x6b, 0x12, 0x1f, 0xad, 0x40, 0xe9, 0x28, 0x0e, 0xfc, 0x01, 0xb6, 0x4c, 0x31, 0xe7, 0x6a, 0x0b, + 0x59, 0x50, 0xd6, 0x19, 0xb4, 0xe6, 0xe5, 0xc4, 0xc8, 0x44, 0x6d, 0x28, 0x45, 0x94, 0xf2, 0x63, + 0x66, 0x15, 0x5a, 0xf3, 0x6b, 0xb5, 0xce, 0x27, 0x4e, 0x22, 0xeb, 0x32, 0x24, 0xe7, 0xb9, 0x38, + 0x8a, 0xab, 0x61, 0xa8, 0x01, 0x15, 0x8e, 0xa3, 0x21, 0x09, 0xbc, 0x81, 0x55, 0x6c, 0x19, 0x6b, + 0x15, 0xf7, 0xca, 0x46, 0xcb, 0x50, 0x64, 0xdc, 0x27, 0x81, 0x55, 0x92, 0x9b, 0x28, 0x43, 0x04, + 0xc5, 0xb8, 0x4f, 0x63, 0x6e, 0x95, 0x55, 0x50, 0xca, 0xd2, 0xe3, 0x38, 0x8a, 0xac, 0xca, 0xd5, + 0x38, 0x8e, 0x22, 0xd4, 0x04, 0xe8, 0xf6, 0x71, 0xf7, 0x24, 0xa4, 0x24, 0xe0, 0x56, 0x55, 0xce, + 0x25, 0x46, 0xd0, 0xe7, 0xb0, 0x14, 0x7a, 0x11, 0x0e, 0xf8, 0x61, 0x02, 0x06, 0x12, 0xb6, 0xa8, + 0x26, 0x76, 0xc6, 0x60, 0x07, 0xca, 0x34, 0xe4, 0x84, 0x06, 0xcc, 0xaa, 0xb5, 0x8c, 0xb5, 0x5a, + 0x67, 0xd9, 0x51, 0x34, 0x3b, 0x23, 0x9a, 0x9d, 0xad, 0xe0, 0xdc, 0x1d, 0x81, 0xec, 0x07, 0x80, + 0x92, 0xe9, 0x66, 0x21, 0x0d, 0x18, 0x46, 0x8b, 0x30, 0x1f, 0xea, 0x84, 0xd7, 0x5d, 0xf1, 0x69, + 0xff, 0x6e, 0xc0, 0xc2, 0x53, 0x3c, 0xc0, 0x1c, 0xa7, 0x83, 0xd0, 0x2a, 0xd4, 0xf0, 0x19, 0xe1, + 0x87, 0x8c, 0x7b, 0x3c, 0x66, 0x92, 0x93, 0xba, 0x0b, 0x62, 0x68, 0x5f, 0x8e, 0xa0, 0x2d, 0xa8, + 0x0a, 0x0b, 0xfb, 0x87, 0x1e, 0x97, 0xcc, 0xd4, 0x3a, 0x8d, 0x99, 0xf8, 0x0e, 0x46, 0x32, 0xdc, + 0xae, 0x5c, 0xbc, 0x5b, 0x9d, 0xfb, 0xe3, 0x9f, 0x55, 0xc3, 0xad, 0x28, 0xb7, 0x2d, 0x6e, 0x3b, + 0xb0, 0xac, 0xe2, 0xd8, 0x8b, 0x68, 0x17, 0x33, 0x96, 0x21, 0x11, 0xfb, 0x4f, 0x03, 0xd0, 0xb3, + 0x33, 0xdc, 0xcd, 0x07, 0x9f, 0xa0, 0xdb, 0x4c, 0xa3, 0x7b, 0xfe, 0x7a, 0xba, 0x0b, 0x29, 0x74, + 0x17, 0x27, 0xe8, 0x5e, 0x83, 0x02, 0x0b, 0x71, 0x57, 0x6a, 0x26, 0x8d, 0x1e, 0x89, 0xb0, 0xef, + 0xc2, 0xc7, 0x13, 0x91, 0xab, 0xbc, 0xdb, 0xaf, 0x61, 0xd1, 0xc5, 0x8c, 0xfc, 0x8a, 0xf7, 0xf8, + 0x79, 0xd6, 0x71, 0x96, 0xa1, 0xf8, 0x0b, 0xf1, 0x79, 0x5f, 0x73, 0xa1, 0x0c, 0x11, 0x5a, 0x1f, + 0x93, 0x5e, 0x5f, 0x71, 0x50, 0x77, 0xb5, 0x65, 0x3f, 0x80, 0x3b, 0x82, 0x28, 0x9c, 0x95, 0xd3, + 0xb7, 0x26, 0xd4, 0x35, 0x50, 0x6b, 0xe1, 0xa6, 0x17, 0x54, 0x6b, 0x67, 0x7e, 0xac, 0x9d, 0x0d, + 0x91, 0x2e, 0x29, 0x1b, 0x91, 0xc6, 0x85, 0xce, 0xfd, 0xe4, 0xc5, 0x3c, 0x5d, 0xd7, 0x77, 0x53, + 0xe9, 0xc8, 0xd5, 0xd0, 0x31, 0x23, 0xc5, 0xeb, 0x19, 0x29, 0xa5, 0x30, 0x52, 0x9e, 0x60, 0x24, + 0xc9, 0x79, 0x65, 0x8a, 0xf3, 0x29, 0x49, 0x57, 0x3f, 0x2c, 0x69, 0xb8, 0x95, 0xa4, 0x5f, 0x40, + 0xed, 0x3b, 0x32, 0x18, 0xe4, 0x28, 0x76, 0x8c, 0xf4, 0x46, 0xc2, 0xac, 0xbb, 0xda, 0x12, 0xb9, + 0xf4, 0x06, 0x03, 0x99, 0xcb, 0x8a, 0x2b, 0x3e, 0xed, 0x4d, 0x58, 0xd8, 0x19, 0x50, 0x86, 0x77, + 0x5f, 0xe4, 0xd0, 0x87, 0x4a, 0xa0, 0xd2, 0xba, 0x32, 0xec, 0xcf, 0xe0, 0xa3, 0xef, 0x09, 0xe3, + 0x7b, 0xc4, 0xcf, 0xbc, 0x5e, 0x2e, 0x2c, 0x8e, 0xa1, 0x5a, 0x0c, 0x9b, 0x50, 0x0d, 0x95, 0x66, + 0x31, 0xb3, 0x0c, 0x59, 0x66, 0x5b, 0xd7, 0xb2, 0xa9, 0x95, 0xbd, 0x1b, 0x1c, 0x53, 0x77, 0xec, + 0x62, 0xff, 0x04, 0x77, 0xc7, 0x15, 0x2d, 0xd9, 0x06, 0x10, 0x14, 0x42, 0x8f, 0xf7, 0x55, 0x18, + 0xae, 0xfc, 0x4e, 0x16, 0x3c, 0x33, 0x4f, 0xc1, 0x7b, 0x08, 0x8b, 0xfb, 0x7d, 0x32, 0x94, 0x7b, + 0x8e, 0x02, 0xbe, 0x07, 0x15, 0xd1, 0x62, 0x0f, 0xc7, 0xe5, 0xac, 0x2c, 0xec, 0x3d, 0xe2, 0xdb, + 0xdf, 0xc2, 0xd2, 0xcb, 0xd0, 0x9f, 0x6a, 0x47, 0x1d, 0xa8, 0x46, 0x98, 0xd1, 0x38, 0xea, 0xca, + 0x03, 0xa6, 0xef, 0x3a, 0x86, 0xe9, 0xbb, 0x15, 0xf1, 0xac, 0x84, 0x7e, 0x25, 0xaf, 0x96, 0xc0, + 0x65, 0x5c, 0x2d, 0x7d, 0x85, 0xcc, 0x71, 0x8d, 0xfe, 0x14, 0x6a, 0xaf, 0x3c, 0x92, 0xb9, 0x43, + 0x04, 0x77, 0x14, 0x4c, 0x6f, 0x30, 0x25, 0x71, 0xe3, 0xc3, 0x12, 0x37, 0x6f, 0x23, 0xf1, 0xce, + 0xdb, 0x1a, 0x14, 0x44, 0xda, 0x51, 0x1f, 0x8a, 0xb2, 0x72, 0x20, 0xc7, 0xc9, 0x7a, 0xee, 0x38, + 0xc9, 0x5a, 0xd4, 0x68, 0xe7, 0xc6, 0xeb, 0x63, 0x31, 0x28, 0xa9, 0xce, 0x86, 0x36, 0xb2, 0x5d, + 0x67, 0x9e, 0x1c, 0x8d, 0x2f, 0x6f, 0xe6, 0xa4, 0x37, 0x55, 0xc7, 0x8b, 0x78, 0xce, 0xe3, 0x5d, + 0xc9, 0x21, 0xe7, 0xf1, 0x12, 0xb2, 0x70, 0xa1, 0xa4, 0xfa, 0x20, 0x5a, 0x99, 0xe1, 0xe2, 0x99, + 0x78, 0xfb, 0x35, 0xbe, 0xc8, 0x5e, 0x72, 0xaa, 0xa3, 0x9f, 0x43, 0x7d, 0xa2, 0xb7, 0xa2, 0x47, + 0x79, 0x97, 0x98, 0xec, 0xae, 0xb7, 0xd8, 0xfa, 0x0d, 0x54, 0x46, 0x75, 0x04, 0xad, 0x67, 0x7b, + 0x4f, 0x95, 0xa7, 0x46, 0xe7, 0x26, 0x2e, 0x7a, 0xcb, 0xc7, 0x50, 0xdc, 0xf3, 0x62, 0x96, 0x9e, + 0xc0, 0x94, 0x71, 0xf4, 0x04, 0x4a, 0x2e, 0x66, 0xf1, 0xf0, 0xe6, 0x9e, 0x3f, 0x03, 0x24, 0xde, + 0x6a, 0x8f, 0x73, 0x48, 0xec, 0xba, 0x3a, 0x98, 0xba, 0xfc, 0x73, 0x28, 0x88, 0x46, 0x82, 0x1e, + 0x66, 0x2f, 0x9c, 0x68, 0x38, 0xa9, 0xcb, 0x1d, 0x40, 0x41, 0xbc, 0x3f, 0x50, 0x8e, 0xab, 0x30, + 0xfb, 0xc2, 0x4a, 0x5d, 0xf5, 0x15, 0x54, 0xaf, 0x9e, 0x2f, 0x28, 0x07, 0x6f, 0xd3, 0x6f, 0x9d, + 0xd4, 0x85, 0xf7, 0xa1, 0xac, 0xbb, 0x1e, 0xca, 0xa1, 0xbf, 0xc9, 0x06, 0x99, 0xba, 0xe8, 0x0f, + 0x50, 0x19, 0xb5, 0x8b, 0x54, 0xb6, 0x73, 0x1c, 0x62, 0xa6, 0xe5, 0xbc, 0x84, 0x92, 0xea, 0x2b, + 0x79, 0xaa, 0xd3, 0x4c, 0x07, 0x4a, 0x0d, 0x17, 0x43, 0x41, 0xd4, 0xf6, 0x3c, 0x0a, 0x48, 0xb4, + 0x8a, 0x86, 0x93, 0x17, 0xae, 0xa2, 0xdf, 0x76, 0x2f, 0xde, 0x37, 0xe7, 0xfe, 0x7e, 0xdf, 0x9c, + 0xfb, 0xed, 0xb2, 0x69, 0x5c, 0x5c, 0x36, 0x8d, 0xbf, 0x2e, 0x9b, 0xc6, 0xbf, 0x97, 0x4d, 0xe3, + 0xc7, 0x27, 0xb7, 0xf8, 0x27, 0xf8, 0x1b, 0xf1, 0xfb, 0xda, 0x3c, 0x2a, 0xc9, 0xc3, 0x6c, 0xfc, + 0x1f, 0x00, 0x00, 0xff, 0xff, 0x64, 0x52, 0x86, 0xc0, 0x49, 0x0f, 0x00, 0x00, +} + func (m *CreateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -292,97 +958,118 @@ } func (m *CreateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if len(m.Bundle) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) - i += copy(dAtA[i:], m.Bundle) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Runtime) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Runtime))) - i += copy(dAtA[i:], m.Runtime) - } - if len(m.Rootfs) > 0 { - for _, msg := range m.Rootfs { - dAtA[i] = 0x22 - i++ - i = encodeVarintShim(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + if m.Options != nil { + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x5a + } + if len(m.ParentCheckpoint) > 0 { + i -= len(m.ParentCheckpoint) + copy(dAtA[i:], m.ParentCheckpoint) + i = encodeVarintShim(dAtA, i, uint64(len(m.ParentCheckpoint))) + i-- + dAtA[i] = 0x52 + } + if len(m.Checkpoint) > 0 { + i -= len(m.Checkpoint) + copy(dAtA[i:], m.Checkpoint) + i = encodeVarintShim(dAtA, i, uint64(len(m.Checkpoint))) + i-- + dAtA[i] = 0x4a + } + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x42 + } + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x3a + } + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x32 } if m.Terminal { - dAtA[i] = 0x28 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.Stdin) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + i-- + dAtA[i] = 0x28 } - if len(m.Stderr) > 0 { - dAtA[i] = 0x42 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if len(m.Rootfs) > 0 { + for iNdEx := len(m.Rootfs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rootfs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } } - if len(m.Checkpoint) > 0 { - dAtA[i] = 0x4a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Checkpoint))) - i += copy(dAtA[i:], m.Checkpoint) + if len(m.Runtime) > 0 { + i -= len(m.Runtime) + copy(dAtA[i:], m.Runtime) + i = encodeVarintShim(dAtA, i, uint64(len(m.Runtime))) + i-- + dAtA[i] = 0x1a } - if len(m.ParentCheckpoint) > 0 { - dAtA[i] = 0x52 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ParentCheckpoint))) - i += copy(dAtA[i:], m.ParentCheckpoint) + if len(m.Bundle) > 0 { + i -= len(m.Bundle) + copy(dAtA[i:], m.Bundle) + i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) + i-- + dAtA[i] = 0x12 } - if m.Options != nil { - dAtA[i] = 0x5a - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Options.Size())) - n1, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CreateTaskResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -390,22 +1077,31 @@ } func (m *CreateTaskResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Pid != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -413,35 +1109,44 @@ } func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Pid != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Pid)) - } + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintShim(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x1a if m.ExitStatus != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x10 } - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n2, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.Pid != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - i += n2 - return i, nil + return len(dAtA) - i, nil } func (m *DeleteProcessRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -449,23 +1154,33 @@ } func (m *DeleteProcessRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteProcessRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ExecProcessRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -473,61 +1188,76 @@ } func (m *ExecProcessRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if m.Terminal { - dAtA[i] = 0x10 - i++ - if m.Terminal { - dAtA[i] = 1 - } else { - dAtA[i] = 0 + if m.Spec != nil { + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i++ + i-- + dAtA[i] = 0x32 } - if len(m.Stdin) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x2a } if len(m.Stdout) > 0 { - dAtA[i] = 0x22 - i++ + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + i-- + dAtA[i] = 0x22 } - if len(m.Stderr) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x1a } - if m.Spec != nil { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Spec.Size())) - n3, err := m.Spec.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.Terminal { + i-- + if m.Terminal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } - i += n3 + i-- + dAtA[i] = 0x10 } - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ExecProcessResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -535,17 +1265,26 @@ } func (m *ExecProcessResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - return i, nil + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + return len(dAtA) - i, nil } func (m *ResizePtyRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -553,33 +1292,43 @@ } func (m *ResizePtyRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResizePtyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Height != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x18 } if m.Width != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Width)) + i-- + dAtA[i] = 0x10 } - if m.Height != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Height)) + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StateRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -587,23 +1336,33 @@ } func (m *StateRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StateResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -611,80 +1370,94 @@ } func (m *StateResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintShim(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0x52 + if m.ExitStatus != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x48 } - if len(m.Bundle) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) - i += copy(dAtA[i:], m.Bundle) + if m.Terminal { + i-- + if m.Terminal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 } - if m.Pid != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x3a } - if m.Status != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Status)) + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x32 } if len(m.Stdin) > 0 { - dAtA[i] = 0x2a - i++ + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + i-- + dAtA[i] = 0x2a } - if len(m.Stderr) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if m.Status != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x20 } - if m.Terminal { - dAtA[i] = 0x40 - i++ - if m.Terminal { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i++ + if m.Pid != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x18 } - if m.ExitStatus != 0 { - dAtA[i] = 0x48 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + if len(m.Bundle) > 0 { + i -= len(m.Bundle) + copy(dAtA[i:], m.Bundle) + i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) + i-- + dAtA[i] = 0x12 } - dAtA[i] = 0x52 - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n4, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - i += n4 - return i, nil + return len(dAtA) - i, nil } func (m *KillRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -692,38 +1465,48 @@ } func (m *KillRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KillRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if m.Signal != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Signal)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.All { - dAtA[i] = 0x18 - i++ + i-- if m.All { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 + } + if m.Signal != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Signal)) + i-- + dAtA[i] = 0x10 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CloseIORequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -731,33 +1514,43 @@ } func (m *CloseIORequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CloseIORequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Stdin { - dAtA[i] = 0x10 - i++ + i-- if m.Stdin { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListPidsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -765,23 +1558,33 @@ } func (m *ListPidsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListPidsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ListPidsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -789,29 +1592,40 @@ } func (m *ListPidsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListPidsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Processes) > 0 { - for _, msg := range m.Processes { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Processes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Processes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -819,33 +1633,45 @@ } func (m *CheckpointTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.Path) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Path))) - i += copy(dAtA[i:], m.Path) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Options != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Options.Size())) - n5, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n5 + i-- + dAtA[i] = 0x12 + } + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintShim(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ShimInfoResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -853,22 +1679,31 @@ } func (m *ShimInfoResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ShimInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.ShimPid != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.ShimPid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *UpdateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -876,27 +1711,38 @@ } func (m *UpdateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Resources != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Resources.Size())) - n6, err := m.Resources.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Resources.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n6 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -904,23 +1750,33 @@ } func (m *StartRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -928,28 +1784,38 @@ } func (m *StartResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i - var l int - _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Pid != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x10 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *WaitRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -957,23 +1823,33 @@ } func (m *WaitRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *WaitResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -981,36 +1857,50 @@ } func (m *WaitResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err7 != nil { + return 0, err7 + } + i -= n7 + i = encodeVarintShim(dAtA, i, uint64(n7)) + i-- + dAtA[i] = 0x12 if m.ExitStatus != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x8 } - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n7, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n7 - return i, nil + return len(dAtA) - i, nil } func encodeVarintShim(dAtA []byte, offset int, v uint64) int { + offset -= sovShim(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *CreateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1058,19 +1948,31 @@ l = m.Options.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateTaskResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { n += 1 + sovShim(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { @@ -1079,22 +1981,34 @@ if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteProcessRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1120,16 +2034,28 @@ l = m.Spec.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ResizePtyRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1142,20 +2068,32 @@ if m.Height != 0 { n += 1 + sovShim(uint64(m.Height)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StateRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StateResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1190,12 +2128,18 @@ if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *KillRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1208,10 +2152,16 @@ if m.All { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CloseIORequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1221,20 +2171,32 @@ if m.Stdin { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListPidsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ListPidsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Processes) > 0 { @@ -1243,10 +2205,16 @@ n += 1 + l + sovShim(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.Path) @@ -1257,39 +2225,63 @@ l = m.Options.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ShimInfoResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ShimPid != 0 { n += 1 + sovShim(uint64(m.ShimPid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Resources != nil { l = m.Resources.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1299,39 +2291,47 @@ if m.Pid != 0 { n += 1 + sovShim(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovShim(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozShim(x uint64) (n int) { return sovShim(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1340,18 +2340,24 @@ if this == nil { return "nil" } + repeatedStringForRootfs := "[]*Mount{" + for _, f := range this.Rootfs { + repeatedStringForRootfs += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForRootfs += "}" s := strings.Join([]string{`&CreateTaskRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Bundle:` + fmt.Sprintf("%v", this.Bundle) + `,`, `Runtime:` + fmt.Sprintf("%v", this.Runtime) + `,`, - `Rootfs:` + strings.Replace(fmt.Sprintf("%v", this.Rootfs), "Mount", "containerd_types.Mount", 1) + `,`, + `Rootfs:` + repeatedStringForRootfs + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Checkpoint:` + fmt.Sprintf("%v", this.Checkpoint) + `,`, `ParentCheckpoint:` + fmt.Sprintf("%v", this.ParentCheckpoint) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1362,6 +2368,7 @@ } s := strings.Join([]string{`&CreateTaskResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1373,7 +2380,8 @@ s := strings.Join([]string{`&DeleteResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1384,6 +2392,7 @@ } s := strings.Join([]string{`&DeleteProcessRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1398,7 +2407,8 @@ `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, - `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf.Any", 1) + `,`, + `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1408,6 +2418,7 @@ return "nil" } s := strings.Join([]string{`&ExecProcessResponse{`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1420,6 +2431,7 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Width:` + fmt.Sprintf("%v", this.Width) + `,`, `Height:` + fmt.Sprintf("%v", this.Height) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1430,6 +2442,7 @@ } s := strings.Join([]string{`&StateRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1448,7 +2461,8 @@ `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1461,6 +2475,7 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Signal:` + fmt.Sprintf("%v", this.Signal) + `,`, `All:` + fmt.Sprintf("%v", this.All) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1472,6 +2487,7 @@ s := strings.Join([]string{`&CloseIORequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1482,6 +2498,7 @@ } s := strings.Join([]string{`&ListPidsRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1490,8 +2507,14 @@ if this == nil { return "nil" } + repeatedStringForProcesses := "[]*ProcessInfo{" + for _, f := range this.Processes { + repeatedStringForProcesses += strings.Replace(fmt.Sprintf("%v", f), "ProcessInfo", "task.ProcessInfo", 1) + "," + } + repeatedStringForProcesses += "}" s := strings.Join([]string{`&ListPidsResponse{`, - `Processes:` + strings.Replace(fmt.Sprintf("%v", this.Processes), "ProcessInfo", "containerd_v1_types.ProcessInfo", 1) + `,`, + `Processes:` + repeatedStringForProcesses + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1502,7 +2525,8 @@ } s := strings.Join([]string{`&CheckpointTaskRequest{`, `Path:` + fmt.Sprintf("%v", this.Path) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1513,6 +2537,7 @@ } s := strings.Join([]string{`&ShimInfoResponse{`, `ShimPid:` + fmt.Sprintf("%v", this.ShimPid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1522,7 +2547,8 @@ return "nil" } s := strings.Join([]string{`&UpdateTaskRequest{`, - `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "google_protobuf.Any", 1) + `,`, + `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1533,6 +2559,7 @@ } s := strings.Join([]string{`&StartRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1544,6 +2571,7 @@ s := strings.Join([]string{`&StartResponse{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1554,6 +2582,7 @@ } s := strings.Join([]string{`&WaitRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1564,7 +2593,8 @@ } s := strings.Join([]string{`&WaitResponse{`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1582,23 +2612,23 @@ State(ctx context.Context, req *StateRequest) (*StateResponse, error) Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) - Delete(ctx context.Context, req *google_protobuf1.Empty) (*DeleteResponse, error) + Delete(ctx context.Context, req *types1.Empty) (*DeleteResponse, error) DeleteProcess(ctx context.Context, req *DeleteProcessRequest) (*DeleteResponse, error) ListPids(ctx context.Context, req *ListPidsRequest) (*ListPidsResponse, error) - Pause(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error) - Resume(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error) - Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) - Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) - Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) - ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) - CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) - ShimInfo(ctx context.Context, req *google_protobuf1.Empty) (*ShimInfoResponse, error) - Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) + Pause(ctx context.Context, req *types1.Empty) (*types1.Empty, error) + Resume(ctx context.Context, req *types1.Empty) (*types1.Empty, error) + Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*types1.Empty, error) + Kill(ctx context.Context, req *KillRequest) (*types1.Empty, error) + Exec(ctx context.Context, req *ExecProcessRequest) (*types1.Empty, error) + ResizePty(ctx context.Context, req *ResizePtyRequest) (*types1.Empty, error) + CloseIO(ctx context.Context, req *CloseIORequest) (*types1.Empty, error) + ShimInfo(ctx context.Context, req *types1.Empty) (*ShimInfoResponse, error) + Update(ctx context.Context, req *UpdateTaskRequest) (*types1.Empty, error) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) } -func RegisterShimService(srv *ttrpc.Server, svc ShimService) { - srv.Register("containerd.runtime.linux.shim.v1.Shim", map[string]ttrpc.Method{ +func RegisterShimService(srv *github_com_containerd_ttrpc.Server, svc ShimService) { + srv.Register("containerd.runtime.linux.shim.v1.Shim", map[string]github_com_containerd_ttrpc.Method{ "State": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { var req StateRequest if err := unmarshal(&req); err != nil { @@ -1621,7 +2651,7 @@ return svc.Start(ctx, &req) }, "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { - var req google_protobuf1.Empty + var req types1.Empty if err := unmarshal(&req); err != nil { return nil, err } @@ -1642,14 +2672,14 @@ return svc.ListPids(ctx, &req) }, "Pause": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { - var req google_protobuf1.Empty + var req types1.Empty if err := unmarshal(&req); err != nil { return nil, err } return svc.Pause(ctx, &req) }, "Resume": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { - var req google_protobuf1.Empty + var req types1.Empty if err := unmarshal(&req); err != nil { return nil, err } @@ -1691,7 +2721,7 @@ return svc.CloseIO(ctx, &req) }, "ShimInfo": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { - var req google_protobuf1.Empty + var req types1.Empty if err := unmarshal(&req); err != nil { return nil, err } @@ -1715,10 +2745,10 @@ } type shimClient struct { - client *ttrpc.Client + client *github_com_containerd_ttrpc.Client } -func NewShimClient(client *ttrpc.Client) ShimService { +func NewShimClient(client *github_com_containerd_ttrpc.Client) ShimService { return &shimClient{ client: client, } @@ -1748,7 +2778,7 @@ return &resp, nil } -func (c *shimClient) Delete(ctx context.Context, req *google_protobuf1.Empty) (*DeleteResponse, error) { +func (c *shimClient) Delete(ctx context.Context, req *types1.Empty) (*DeleteResponse, error) { var resp DeleteResponse if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Delete", req, &resp); err != nil { return nil, err @@ -1772,63 +2802,63 @@ return &resp, nil } -func (c *shimClient) Pause(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Pause(ctx context.Context, req *types1.Empty) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Pause", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) Resume(ctx context.Context, req *google_protobuf1.Empty) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Resume(ctx context.Context, req *types1.Empty) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Resume", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Checkpoint", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Kill(ctx context.Context, req *KillRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Kill", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Exec(ctx context.Context, req *ExecProcessRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Exec", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "ResizePty", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) CloseIO(ctx context.Context, req *CloseIORequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "CloseIO", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *shimClient) ShimInfo(ctx context.Context, req *google_protobuf1.Empty) (*ShimInfoResponse, error) { +func (c *shimClient) ShimInfo(ctx context.Context, req *types1.Empty) (*ShimInfoResponse, error) { var resp ShimInfoResponse if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "ShimInfo", req, &resp); err != nil { return nil, err @@ -1836,8 +2866,8 @@ return &resp, nil } -func (c *shimClient) Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *shimClient) Update(ctx context.Context, req *UpdateTaskRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Update", req, &resp); err != nil { return nil, err } @@ -1866,7 +2896,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1894,7 +2924,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1904,6 +2934,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1923,7 +2956,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1933,6 +2966,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1952,7 +2988,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -1962,6 +2998,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1981,7 +3020,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -1990,10 +3029,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Rootfs = append(m.Rootfs, &containerd_types.Mount{}) + m.Rootfs = append(m.Rootfs, &types.Mount{}) if err := m.Rootfs[len(m.Rootfs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2012,7 +3054,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2032,7 +3074,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2042,6 +3084,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2061,7 +3106,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2071,6 +3116,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2090,7 +3138,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2100,6 +3148,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2119,7 +3170,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2129,6 +3180,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2148,7 +3202,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2158,6 +3212,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2177,7 +3234,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2186,11 +3243,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2202,12 +3262,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2232,7 +3293,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2260,7 +3321,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2271,12 +3332,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2301,7 +3363,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2329,7 +3391,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2348,7 +3410,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2367,7 +3429,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2376,10 +3438,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2389,12 +3454,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2419,7 +3485,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2447,7 +3513,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2457,6 +3523,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2468,12 +3537,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2498,7 +3568,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2526,7 +3596,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2536,6 +3606,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2555,7 +3628,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2575,7 +3648,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2585,6 +3658,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2604,7 +3680,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2614,6 +3690,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2633,7 +3712,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2643,6 +3722,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2662,7 +3744,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2671,11 +3753,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Spec == nil { - m.Spec = &google_protobuf.Any{} + m.Spec = &types1.Any{} } if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2687,12 +3772,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2717,7 +3803,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2737,12 +3823,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2767,7 +3854,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2795,7 +3882,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2805,6 +3892,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2824,7 +3914,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Width |= (uint32(b) & 0x7F) << shift + m.Width |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2843,7 +3933,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Height |= (uint32(b) & 0x7F) << shift + m.Height |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2854,12 +3944,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2884,7 +3975,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2912,7 +4003,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2922,6 +4013,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2933,12 +4027,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2963,7 +4058,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2991,7 +4086,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3001,6 +4096,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3020,7 +4118,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3030,6 +4128,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3049,7 +4150,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3068,7 +4169,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Status |= (containerd_v1_types.Status(b) & 0x7F) << shift + m.Status |= task.Status(b&0x7F) << shift if b < 0x80 { break } @@ -3087,7 +4188,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3097,6 +4198,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3116,7 +4220,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3126,6 +4230,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3145,7 +4252,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3155,6 +4262,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3174,7 +4284,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3194,7 +4304,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3213,7 +4323,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3222,10 +4332,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -3235,12 +4348,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3265,7 +4379,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3293,7 +4407,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3303,6 +4417,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3322,7 +4439,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Signal |= (uint32(b) & 0x7F) << shift + m.Signal |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3341,7 +4458,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3353,12 +4470,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3383,7 +4501,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3411,7 +4529,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3421,6 +4539,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3440,7 +4561,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3452,12 +4573,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3482,7 +4604,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3510,7 +4632,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3520,6 +4642,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3531,12 +4656,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3561,7 +4687,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3589,7 +4715,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3598,10 +4724,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Processes = append(m.Processes, &containerd_v1_types.ProcessInfo{}) + m.Processes = append(m.Processes, &task.ProcessInfo{}) if err := m.Processes[len(m.Processes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -3612,12 +4741,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3642,7 +4772,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3670,7 +4800,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3680,6 +4810,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3699,7 +4832,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3708,11 +4841,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3724,12 +4860,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3754,7 +4891,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3782,7 +4919,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ShimPid |= (uint32(b) & 0x7F) << shift + m.ShimPid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3793,12 +4930,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3823,7 +4961,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3851,7 +4989,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3860,11 +4998,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Resources == nil { - m.Resources = &google_protobuf.Any{} + m.Resources = &types1.Any{} } if err := m.Resources.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3876,12 +5017,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3906,7 +5048,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3934,7 +5076,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3944,6 +5086,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3955,12 +5100,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3985,7 +5131,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4013,7 +5159,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4023,6 +5169,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4042,7 +5191,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4053,12 +5202,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4083,7 +5233,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4111,7 +5261,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4121,6 +5271,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4132,12 +5285,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4162,7 +5316,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4190,7 +5344,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4209,7 +5363,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4218,10 +5372,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4231,12 +5388,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4249,6 +5407,7 @@ func skipShim(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -4280,10 +5439,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -4300,132 +5457,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthShim } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShim - } - 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 := skipShim(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupShim + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthShim + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthShim = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowShim = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthShim = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowShim = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupShim = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/runtime/v1/shim/v1/shim.proto", fileDescriptorShim) -} - -var fileDescriptorShim = []byte{ - // 1133 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x4f, 0x4f, 0x1b, 0x47, - 0x14, 0x67, 0x17, 0xff, 0x7d, 0x8e, 0x29, 0x4c, 0x09, 0xdd, 0x38, 0x92, 0xb1, 0x56, 0x6a, 0x44, - 0x55, 0x65, 0x5d, 0x4c, 0x95, 0xa4, 0xad, 0x84, 0x04, 0x24, 0xaa, 0x50, 0x1b, 0x05, 0x2d, 0xa4, - 0x89, 0x5a, 0x55, 0x68, 0xf1, 0x0e, 0xf6, 0x08, 0x7b, 0x67, 0xb3, 0x33, 0x4b, 0xa1, 0xa7, 0x9e, - 0x7a, 0xee, 0xc7, 0xe9, 0x47, 0xe0, 0x90, 0x43, 0x8f, 0x3d, 0xa5, 0x0d, 0xf7, 0x7e, 0x87, 0x6a, - 0xfe, 0x18, 0xaf, 0x6d, 0x36, 0xbb, 0x70, 0xc1, 0xfb, 0x66, 0x7e, 0x6f, 0xe6, 0xcd, 0xfb, 0xfd, - 0xe6, 0xbd, 0x01, 0x36, 0x7b, 0x84, 0xf7, 0xe3, 0x23, 0xa7, 0x4b, 0x87, 0xed, 0x2e, 0x0d, 0xb8, - 0x47, 0x02, 0x1c, 0xf9, 0xc9, 0xcf, 0x28, 0x0e, 0x38, 0x19, 0xe2, 0xf6, 0xe9, 0x7a, 0x9b, 0xf5, - 0xc9, 0x70, 0xf4, 0xeb, 0x84, 0x11, 0xe5, 0x14, 0xb5, 0xc6, 0x48, 0x47, 0x23, 0x9d, 0x01, 0x09, - 0xe2, 0x33, 0x47, 0x82, 0x4e, 0xd7, 0x1b, 0xf7, 0x7a, 0x94, 0xf6, 0x06, 0xb8, 0x2d, 0xf1, 0x47, - 0xf1, 0x71, 0xdb, 0x0b, 0xce, 0x95, 0x73, 0xe3, 0xfe, 0xf4, 0x14, 0x1e, 0x86, 0x7c, 0x34, 0xb9, - 0xdc, 0xa3, 0x3d, 0x2a, 0x3f, 0xdb, 0xe2, 0x4b, 0x8f, 0xae, 0x4e, 0xbb, 0x88, 0x1d, 0x19, 0xf7, - 0x86, 0xa1, 0x06, 0x3c, 0xca, 0x3c, 0x90, 0x17, 0x92, 0x36, 0x3f, 0x0f, 0x31, 0x6b, 0x0f, 0x69, - 0x1c, 0x70, 0xed, 0xf7, 0xf5, 0x0d, 0xfc, 0xb8, 0xc7, 0x4e, 0xe4, 0x1f, 0xe5, 0x6b, 0xff, 0x67, - 0xc2, 0xd2, 0x4e, 0x84, 0x3d, 0x8e, 0x0f, 0x3c, 0x76, 0xe2, 0xe2, 0x37, 0x31, 0x66, 0x1c, 0xad, - 0x80, 0x49, 0x7c, 0xcb, 0x68, 0x19, 0x6b, 0xd5, 0xed, 0xd2, 0xe5, 0xbb, 0x55, 0x73, 0xf7, 0xa9, - 0x6b, 0x12, 0x1f, 0xad, 0x40, 0xe9, 0x28, 0x0e, 0xfc, 0x01, 0xb6, 0x4c, 0x31, 0xe7, 0x6a, 0x0b, - 0x59, 0x50, 0xd6, 0x19, 0xb4, 0xe6, 0xe5, 0xc4, 0xc8, 0x44, 0x6d, 0x28, 0x45, 0x94, 0xf2, 0x63, - 0x66, 0x15, 0x5a, 0xf3, 0x6b, 0xb5, 0xce, 0x27, 0x4e, 0x22, 0xeb, 0x32, 0x24, 0xe7, 0xb9, 0x38, - 0x8a, 0xab, 0x61, 0xa8, 0x01, 0x15, 0x8e, 0xa3, 0x21, 0x09, 0xbc, 0x81, 0x55, 0x6c, 0x19, 0x6b, - 0x15, 0xf7, 0xca, 0x46, 0xcb, 0x50, 0x64, 0xdc, 0x27, 0x81, 0x55, 0x92, 0x9b, 0x28, 0x43, 0x04, - 0xc5, 0xb8, 0x4f, 0x63, 0x6e, 0x95, 0x55, 0x50, 0xca, 0xd2, 0xe3, 0x38, 0x8a, 0xac, 0xca, 0xd5, - 0x38, 0x8e, 0x22, 0xd4, 0x04, 0xe8, 0xf6, 0x71, 0xf7, 0x24, 0xa4, 0x24, 0xe0, 0x56, 0x55, 0xce, - 0x25, 0x46, 0xd0, 0xe7, 0xb0, 0x14, 0x7a, 0x11, 0x0e, 0xf8, 0x61, 0x02, 0x06, 0x12, 0xb6, 0xa8, - 0x26, 0x76, 0xc6, 0x60, 0x07, 0xca, 0x34, 0xe4, 0x84, 0x06, 0xcc, 0xaa, 0xb5, 0x8c, 0xb5, 0x5a, - 0x67, 0xd9, 0x51, 0x34, 0x3b, 0x23, 0x9a, 0x9d, 0xad, 0xe0, 0xdc, 0x1d, 0x81, 0xec, 0x07, 0x80, - 0x92, 0xe9, 0x66, 0x21, 0x0d, 0x18, 0x46, 0x8b, 0x30, 0x1f, 0xea, 0x84, 0xd7, 0x5d, 0xf1, 0x69, - 0xff, 0x6e, 0xc0, 0xc2, 0x53, 0x3c, 0xc0, 0x1c, 0xa7, 0x83, 0xd0, 0x2a, 0xd4, 0xf0, 0x19, 0xe1, - 0x87, 0x8c, 0x7b, 0x3c, 0x66, 0x92, 0x93, 0xba, 0x0b, 0x62, 0x68, 0x5f, 0x8e, 0xa0, 0x2d, 0xa8, - 0x0a, 0x0b, 0xfb, 0x87, 0x1e, 0x97, 0xcc, 0xd4, 0x3a, 0x8d, 0x99, 0xf8, 0x0e, 0x46, 0x32, 0xdc, - 0xae, 0x5c, 0xbc, 0x5b, 0x9d, 0xfb, 0xe3, 0x9f, 0x55, 0xc3, 0xad, 0x28, 0xb7, 0x2d, 0x6e, 0x3b, - 0xb0, 0xac, 0xe2, 0xd8, 0x8b, 0x68, 0x17, 0x33, 0x96, 0x21, 0x11, 0xfb, 0x4f, 0x03, 0xd0, 0xb3, - 0x33, 0xdc, 0xcd, 0x07, 0x9f, 0xa0, 0xdb, 0x4c, 0xa3, 0x7b, 0xfe, 0x7a, 0xba, 0x0b, 0x29, 0x74, - 0x17, 0x27, 0xe8, 0x5e, 0x83, 0x02, 0x0b, 0x71, 0x57, 0x6a, 0x26, 0x8d, 0x1e, 0x89, 0xb0, 0xef, - 0xc2, 0xc7, 0x13, 0x91, 0xab, 0xbc, 0xdb, 0xaf, 0x61, 0xd1, 0xc5, 0x8c, 0xfc, 0x8a, 0xf7, 0xf8, - 0x79, 0xd6, 0x71, 0x96, 0xa1, 0xf8, 0x0b, 0xf1, 0x79, 0x5f, 0x73, 0xa1, 0x0c, 0x11, 0x5a, 0x1f, - 0x93, 0x5e, 0x5f, 0x71, 0x50, 0x77, 0xb5, 0x65, 0x3f, 0x80, 0x3b, 0x82, 0x28, 0x9c, 0x95, 0xd3, - 0xb7, 0x26, 0xd4, 0x35, 0x50, 0x6b, 0xe1, 0xa6, 0x17, 0x54, 0x6b, 0x67, 0x7e, 0xac, 0x9d, 0x0d, - 0x91, 0x2e, 0x29, 0x1b, 0x91, 0xc6, 0x85, 0xce, 0xfd, 0xe4, 0xc5, 0x3c, 0x5d, 0xd7, 0x77, 0x53, - 0xe9, 0xc8, 0xd5, 0xd0, 0x31, 0x23, 0xc5, 0xeb, 0x19, 0x29, 0xa5, 0x30, 0x52, 0x9e, 0x60, 0x24, - 0xc9, 0x79, 0x65, 0x8a, 0xf3, 0x29, 0x49, 0x57, 0x3f, 0x2c, 0x69, 0xb8, 0x95, 0xa4, 0x5f, 0x40, - 0xed, 0x3b, 0x32, 0x18, 0xe4, 0x28, 0x76, 0x8c, 0xf4, 0x46, 0xc2, 0xac, 0xbb, 0xda, 0x12, 0xb9, - 0xf4, 0x06, 0x03, 0x99, 0xcb, 0x8a, 0x2b, 0x3e, 0xed, 0x4d, 0x58, 0xd8, 0x19, 0x50, 0x86, 0x77, - 0x5f, 0xe4, 0xd0, 0x87, 0x4a, 0xa0, 0xd2, 0xba, 0x32, 0xec, 0xcf, 0xe0, 0xa3, 0xef, 0x09, 0xe3, - 0x7b, 0xc4, 0xcf, 0xbc, 0x5e, 0x2e, 0x2c, 0x8e, 0xa1, 0x5a, 0x0c, 0x9b, 0x50, 0x0d, 0x95, 0x66, - 0x31, 0xb3, 0x0c, 0x59, 0x66, 0x5b, 0xd7, 0xb2, 0xa9, 0x95, 0xbd, 0x1b, 0x1c, 0x53, 0x77, 0xec, - 0x62, 0xff, 0x04, 0x77, 0xc7, 0x15, 0x2d, 0xd9, 0x06, 0x10, 0x14, 0x42, 0x8f, 0xf7, 0x55, 0x18, - 0xae, 0xfc, 0x4e, 0x16, 0x3c, 0x33, 0x4f, 0xc1, 0x7b, 0x08, 0x8b, 0xfb, 0x7d, 0x32, 0x94, 0x7b, - 0x8e, 0x02, 0xbe, 0x07, 0x15, 0xd1, 0x62, 0x0f, 0xc7, 0xe5, 0xac, 0x2c, 0xec, 0x3d, 0xe2, 0xdb, - 0xdf, 0xc2, 0xd2, 0xcb, 0xd0, 0x9f, 0x6a, 0x47, 0x1d, 0xa8, 0x46, 0x98, 0xd1, 0x38, 0xea, 0xca, - 0x03, 0xa6, 0xef, 0x3a, 0x86, 0xe9, 0xbb, 0x15, 0xf1, 0xac, 0x84, 0x7e, 0x25, 0xaf, 0x96, 0xc0, - 0x65, 0x5c, 0x2d, 0x7d, 0x85, 0xcc, 0x71, 0x8d, 0xfe, 0x14, 0x6a, 0xaf, 0x3c, 0x92, 0xb9, 0x43, - 0x04, 0x77, 0x14, 0x4c, 0x6f, 0x30, 0x25, 0x71, 0xe3, 0xc3, 0x12, 0x37, 0x6f, 0x23, 0xf1, 0xce, - 0xdb, 0x1a, 0x14, 0x44, 0xda, 0x51, 0x1f, 0x8a, 0xb2, 0x72, 0x20, 0xc7, 0xc9, 0x7a, 0xee, 0x38, - 0xc9, 0x5a, 0xd4, 0x68, 0xe7, 0xc6, 0xeb, 0x63, 0x31, 0x28, 0xa9, 0xce, 0x86, 0x36, 0xb2, 0x5d, - 0x67, 0x9e, 0x1c, 0x8d, 0x2f, 0x6f, 0xe6, 0xa4, 0x37, 0x55, 0xc7, 0x8b, 0x78, 0xce, 0xe3, 0x5d, - 0xc9, 0x21, 0xe7, 0xf1, 0x12, 0xb2, 0x70, 0xa1, 0xa4, 0xfa, 0x20, 0x5a, 0x99, 0xe1, 0xe2, 0x99, - 0x78, 0xfb, 0x35, 0xbe, 0xc8, 0x5e, 0x72, 0xaa, 0xa3, 0x9f, 0x43, 0x7d, 0xa2, 0xb7, 0xa2, 0x47, - 0x79, 0x97, 0x98, 0xec, 0xae, 0xb7, 0xd8, 0xfa, 0x0d, 0x54, 0x46, 0x75, 0x04, 0xad, 0x67, 0x7b, - 0x4f, 0x95, 0xa7, 0x46, 0xe7, 0x26, 0x2e, 0x7a, 0xcb, 0xc7, 0x50, 0xdc, 0xf3, 0x62, 0x96, 0x9e, - 0xc0, 0x94, 0x71, 0xf4, 0x04, 0x4a, 0x2e, 0x66, 0xf1, 0xf0, 0xe6, 0x9e, 0x3f, 0x03, 0x24, 0xde, - 0x6a, 0x8f, 0x73, 0x48, 0xec, 0xba, 0x3a, 0x98, 0xba, 0xfc, 0x73, 0x28, 0x88, 0x46, 0x82, 0x1e, - 0x66, 0x2f, 0x9c, 0x68, 0x38, 0xa9, 0xcb, 0x1d, 0x40, 0x41, 0xbc, 0x3f, 0x50, 0x8e, 0xab, 0x30, - 0xfb, 0xc2, 0x4a, 0x5d, 0xf5, 0x15, 0x54, 0xaf, 0x9e, 0x2f, 0x28, 0x07, 0x6f, 0xd3, 0x6f, 0x9d, - 0xd4, 0x85, 0xf7, 0xa1, 0xac, 0xbb, 0x1e, 0xca, 0xa1, 0xbf, 0xc9, 0x06, 0x99, 0xba, 0xe8, 0x0f, - 0x50, 0x19, 0xb5, 0x8b, 0x54, 0xb6, 0x73, 0x1c, 0x62, 0xa6, 0xe5, 0xbc, 0x84, 0x92, 0xea, 0x2b, - 0x79, 0xaa, 0xd3, 0x4c, 0x07, 0x4a, 0x0d, 0x17, 0x43, 0x41, 0xd4, 0xf6, 0x3c, 0x0a, 0x48, 0xb4, - 0x8a, 0x86, 0x93, 0x17, 0xae, 0xa2, 0xdf, 0x76, 0x2f, 0xde, 0x37, 0xe7, 0xfe, 0x7e, 0xdf, 0x9c, - 0xfb, 0xed, 0xb2, 0x69, 0x5c, 0x5c, 0x36, 0x8d, 0xbf, 0x2e, 0x9b, 0xc6, 0xbf, 0x97, 0x4d, 0xe3, - 0xc7, 0x27, 0xb7, 0xf8, 0x27, 0xf8, 0x1b, 0xf1, 0xfb, 0xda, 0x3c, 0x2a, 0xc9, 0xc3, 0x6c, 0xfc, - 0x1f, 0x00, 0x00, 0xff, 0xff, 0x64, 0x52, 0x86, 0xc0, 0x49, 0x0f, 0x00, 0x00, -} diff -Nru containerd-1.2.6/runtime/v1/shim/v1/shim.proto containerd-1.5.9/runtime/v1/shim/v1/shim.proto --- containerd-1.2.6/runtime/v1/shim/v1/shim.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim/v1/shim.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.runtime.linux.shim.v1; diff -Nru containerd-1.2.6/runtime/v1/shim.go containerd-1.5.9/runtime/v1/shim.go --- containerd-1.2.6/runtime/v1/shim.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v1/shim.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "context" + "io" + "path/filepath" + + "github.com/containerd/fifo" + "golang.org/x/sys/unix" +) + +// OpenShimStdoutLog opens the shim log for reading +func OpenShimStdoutLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) { + return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stdout.log"), unix.O_RDWR|unix.O_CREAT, 0700) +} + +// OpenShimStderrLog opens the shim log +func OpenShimStderrLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) { + return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stderr.log"), unix.O_RDWR|unix.O_CREAT, 0700) +} diff -Nru containerd-1.2.6/runtime/v2/binary.go containerd-1.5.9/runtime/v2/binary.go --- containerd-1.2.6/runtime/v2/binary.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/binary.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,36 +24,39 @@ gruntime "runtime" "strings" - eventstypes "github.com/containerd/containerd/api/events" "github.com/containerd/containerd/events/exchange" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/runtime" client "github.com/containerd/containerd/runtime/v2/shim" "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/ttrpc" + "github.com/gogo/protobuf/types" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary { +func shimBinary(ctx context.Context, bundle *Bundle, runtime, containerdAddress string, containerdTTRPCAddress string, events *exchange.Exchange, rt *runtime.TaskList) *binary { return &binary{ - bundle: bundle, - runtime: runtime, - containerdAddress: containerdAddress, - events: events, - rtTasks: rt, + bundle: bundle, + runtime: runtime, + containerdAddress: containerdAddress, + containerdTTRPCAddress: containerdTTRPCAddress, + events: events, + rtTasks: rt, } } type binary struct { - runtime string - containerdAddress string - bundle *Bundle - events *exchange.Exchange - rtTasks *runtime.TaskList + runtime string + containerdAddress string + containerdTTRPCAddress string + bundle *Bundle + events *exchange.Exchange + rtTasks *runtime.TaskList } -func (b *binary) Start(ctx context.Context) (_ *shim, err error) { +func (b *binary) Start(ctx context.Context, opts *types.Any, onClose func()) (_ *shim, err error) { args := []string{"-id", b.bundle.ID} if logrus.GetLevel() == logrus.DebugLevel { args = append(args, "-debug") @@ -64,13 +67,23 @@ ctx, b.runtime, b.containerdAddress, + b.containerdTTRPCAddress, b.bundle.Path, + opts, args..., ) if err != nil { return nil, err } - f, err := openShimLog(ctx, b.bundle) + // Windows needs a namespace when openShimLog + ns, _ := namespaces.Namespace(ctx) + shimCtx, cancelShimLog := context.WithCancel(namespaces.WithNamespace(context.Background(), ns)) + defer func() { + if err != nil { + cancelShimLog() + } + }() + f, err := openShimLog(shimCtx, b.bundle, client.AnonDialer) if err != nil { return nil, errors.Wrap(err, "open shim log pipe") } @@ -84,7 +97,12 @@ // copy the shim's logs to containerd's output go func() { defer f.Close() - if _, err := io.Copy(os.Stderr, f); err != nil { + _, err := io.Copy(os.Stderr, f) + // To prevent flood of error messages, the expected error + // should be reset, like os.ErrClosed or os.ErrNotExist, which + // depends on platform. + err = checkCopyShimLogError(ctx, err) + if err != nil { log.G(ctx).WithError(err).Error("copy shim log") } }() @@ -97,8 +115,12 @@ if err != nil { return nil, err } - client := ttrpc.NewClient(conn) - client.OnClose(func() { conn.Close() }) + onCloseWithShimLog := func() { + onClose() + cancelShimLog() + f.Close() + } + client := ttrpc.NewClient(conn, ttrpc.WithOnClose(onCloseWithShimLog)) return &shim{ bundle: b.bundle, client: client, @@ -111,18 +133,22 @@ func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) { log.G(ctx).Info("cleaning up dead shim") - // Windows cannot delete the current working directory while an - // executable is in use with it. For the cleanup case we invoke with the - // default work dir and forward the bundle path on the cmdline. + // On Windows and FreeBSD, the current working directory of the shim should + // not be the bundle path during the delete operation. Instead, we invoke + // with the default work dir and forward the bundle path on the cmdline. + // Windows cannot delete the current working directory while an executable + // is in use with it. On FreeBSD, fork/exec can fail. var bundlePath string - if gruntime.GOOS != "windows" { + if gruntime.GOOS != "windows" && gruntime.GOOS != "freebsd" { bundlePath = b.bundle.Path } cmd, err := client.Command(ctx, b.runtime, b.containerdAddress, + b.containerdTTRPCAddress, bundlePath, + nil, "-id", b.bundle.ID, "-bundle", b.bundle.Path, "delete") @@ -136,6 +162,7 @@ cmd.Stdout = out cmd.Stderr = errb if err := cmd.Run(); err != nil { + log.G(ctx).WithField("cmd", cmd).WithError(err).Error("failed to delete") return nil, errors.Wrapf(err, "%s", errb.String()) } s := errb.String() @@ -149,16 +176,6 @@ if err := b.bundle.Delete(); err != nil { return nil, err } - // remove self from the runtime task list - // this seems dirty but it cleans up the API across runtimes, tasks, and the service - b.rtTasks.Delete(ctx, b.bundle.ID) - // shim will send the exit event - b.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ - ContainerID: b.bundle.ID, - ExitStatus: response.ExitStatus, - ExitedAt: response.ExitedAt, - Pid: response.Pid, - }) return &runtime.Exit{ Status: response.ExitStatus, Timestamp: response.ExitedAt, diff -Nru containerd-1.2.6/runtime/v2/bundle_default.go containerd-1.5.9/runtime/v2/bundle_default.go --- containerd-1.2.6/runtime/v2/bundle_default.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/bundle_default.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,24 @@ +//go:build !linux +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +// prepareBundleDirectoryPermissions prepares the permissions of the bundle +// directory according to the needs of the current platform. +func prepareBundleDirectoryPermissions(path string, spec []byte) error { return nil } diff -Nru containerd-1.2.6/runtime/v2/bundle.go containerd-1.5.9/runtime/v2/bundle.go --- containerd-1.2.6/runtime/v2/bundle.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/bundle.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,11 +18,13 @@ import ( "context" + "fmt" "io/ioutil" "os" "path/filepath" "github.com/containerd/containerd/identifiers" + "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" "github.com/pkg/errors" ) @@ -70,7 +72,10 @@ if err := os.MkdirAll(filepath.Dir(b.Path), 0711); err != nil { return nil, err } - if err := os.Mkdir(b.Path, 0711); err != nil { + if err := os.Mkdir(b.Path, 0700); err != nil { + return nil, err + } + if err := prepareBundleDirectoryPermissions(b.Path, spec); err != nil { return nil, err } paths = append(paths, b.Path) @@ -78,6 +83,11 @@ if err := os.MkdirAll(filepath.Dir(work), 0711); err != nil { return nil, err } + rootfs := filepath.Join(b.Path, "rootfs") + if err := os.MkdirAll(rootfs, 0711); err != nil { + return nil, err + } + paths = append(paths, rootfs) if err := os.Mkdir(work, 0711); err != nil { if !os.IsExist(err) { return nil, err @@ -88,10 +98,6 @@ } } paths = append(paths, work) - // create rootfs dir - if err := os.Mkdir(filepath.Join(b.Path, "rootfs"), 0711); err != nil { - return nil, err - } // symlink workdir if err := os.Symlink(work, filepath.Join(b.Path, "work")); err != nil { return nil, err @@ -114,20 +120,40 @@ // Delete a bundle atomically func (b *Bundle) Delete() error { work, werr := os.Readlink(filepath.Join(b.Path, "work")) - err := os.RemoveAll(b.Path) + rootfs := filepath.Join(b.Path, "rootfs") + if err := mount.UnmountAll(rootfs, 0); err != nil { + return errors.Wrapf(err, "unmount rootfs %s", rootfs) + } + if err := os.Remove(rootfs); err != nil && !os.IsNotExist(err) { + return errors.Wrap(err, "failed to remove bundle rootfs") + } + err := atomicDelete(b.Path) if err == nil { if werr == nil { - return os.RemoveAll(work) + return atomicDelete(work) } return nil } // error removing the bundle path; still attempt removing work dir var err2 error if werr == nil { - err2 = os.RemoveAll(work) + err2 = atomicDelete(work) if err2 == nil { return err } } return errors.Wrapf(err, "failed to remove both bundle and workdir locations: %v", err2) } + +// atomicDelete renames the path to a hidden file before removal +func atomicDelete(path string) error { + // create a hidden dir for an atomic removal + atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) + if err := os.Rename(path, atomicPath); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + return os.RemoveAll(atomicPath) +} diff -Nru containerd-1.2.6/runtime/v2/bundle_linux.go containerd-1.5.9/runtime/v2/bundle_linux.go --- containerd-1.2.6/runtime/v2/bundle_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/bundle_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,74 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "encoding/json" + "os" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// prepareBundleDirectoryPermissions prepares the permissions of the bundle +// directory according to the needs of the current platform. +// On Linux when user namespaces are enabled, the permissions are modified to +// allow the remapped root GID to access the bundle. +func prepareBundleDirectoryPermissions(path string, spec []byte) error { + gid, err := remappedGID(spec) + if err != nil { + return err + } + if gid == 0 { + return nil + } + if err := os.Chown(path, -1, int(gid)); err != nil { + return err + } + return os.Chmod(path, 0710) +} + +// ociSpecUserNS is a subset of specs.Spec used to reduce garbage during +// unmarshal. +type ociSpecUserNS struct { + Linux *linuxSpecUserNS +} + +// linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during +// unmarshal. +type linuxSpecUserNS struct { + GIDMappings []specs.LinuxIDMapping +} + +// remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If +// there is no remapping, remappedGID returns 0. If the spec cannot be parsed, +// remappedGID returns an error. +func remappedGID(spec []byte) (uint32, error) { + var ociSpec ociSpecUserNS + err := json.Unmarshal(spec, &ociSpec) + if err != nil { + return 0, err + } + if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 { + return 0, nil + } + for _, mapping := range ociSpec.Linux.GIDMappings { + if mapping.ContainerID == 0 { + return mapping.HostID, nil + } + } + return 0, nil +} diff -Nru containerd-1.2.6/runtime/v2/bundle_linux_test.go containerd-1.5.9/runtime/v2/bundle_linux_test.go --- containerd-1.2.6/runtime/v2/bundle_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/bundle_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,145 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "syscall" + "testing" + + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/testutil" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewBundle(t *testing.T) { + testutil.RequiresRoot(t) + tests := []struct { + userns bool + }{{ + userns: false, + }, { + userns: true, + }} + const usernsGID = 4200 + + for i, tc := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + dir, err := ioutil.TempDir("", "test-new-bundle") + require.NoError(t, err, "failed to create test directory") + defer os.RemoveAll(dir) + work := filepath.Join(dir, "work") + state := filepath.Join(dir, "state") + id := fmt.Sprintf("new-bundle-%d", i) + spec := oci.Spec{} + if tc.userns { + spec.Linux = &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}}, + } + } + specBytes, err := json.Marshal(&spec) + require.NoError(t, err, "failed to marshal spec") + + ctx := namespaces.WithNamespace(context.TODO(), namespaces.Default) + b, err := NewBundle(ctx, work, state, id, specBytes) + require.NoError(t, err, "NewBundle should succeed") + require.NotNil(t, b, "bundle should not be nil") + + fi, err := os.Stat(b.Path) + assert.NoError(t, err, "should be able to stat bundle path") + if tc.userns { + assert.Equal(t, os.ModeDir|0710, fi.Mode(), "bundle path should be a directory with perm 0710") + } else { + assert.Equal(t, os.ModeDir|0700, fi.Mode(), "bundle path should be a directory with perm 0700") + } + stat, ok := fi.Sys().(*syscall.Stat_t) + require.True(t, ok, "should assert to *syscall.Stat_t") + expectedGID := uint32(0) + if tc.userns { + expectedGID = usernsGID + } + assert.Equal(t, expectedGID, stat.Gid, "gid should match") + + }) + } +} + +func TestRemappedGID(t *testing.T) { + tests := []struct { + spec oci.Spec + gid uint32 + }{{ + // empty spec + spec: oci.Spec{}, + gid: 0, + }, { + // empty Linux section + spec: oci.Spec{ + Linux: &specs.Linux{}, + }, + gid: 0, + }, { + // empty ID mappings + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: make([]specs.LinuxIDMapping, 0), + }, + }, + gid: 0, + }, { + // valid ID mapping + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ + ContainerID: 0, + HostID: 1000, + }}, + }, + }, + gid: 1000, + }, { + // missing ID mapping + spec: oci.Spec{ + Linux: &specs.Linux{ + GIDMappings: []specs.LinuxIDMapping{{ + ContainerID: 100, + HostID: 1000, + }}, + }, + }, + gid: 0, + }} + + for i, tc := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + s, err := json.Marshal(tc.spec) + require.NoError(t, err, "failed to marshal spec") + gid, err := remappedGID(s) + assert.NoError(t, err, "should unmarshal successfully") + assert.Equal(t, tc.gid, gid, "expected GID to match") + }) + } +} diff -Nru containerd-1.2.6/runtime/v2/bundle_test.go containerd-1.5.9/runtime/v2/bundle_test.go --- containerd-1.2.6/runtime/v2/bundle_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/bundle_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + // When testutil is imported for one platform (bundle_linux_test.go) it + // should be imported for all platforms. + _ "github.com/containerd/containerd/pkg/testutil" +) diff -Nru containerd-1.2.6/runtime/v2/example/cmd/main.go containerd-1.5.9/runtime/v2/example/cmd/main.go --- containerd-1.2.6/runtime/v2/example/cmd/main.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/example/cmd/main.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "github.com/containerd/containerd/runtime/v2/example" + "github.com/containerd/containerd/runtime/v2/shim" +) + +func main() { + // init and execute the shim + shim.Run("io.containerd.example.v1", example.New) +} diff -Nru containerd-1.2.6/runtime/v2/example/example.go containerd-1.5.9/runtime/v2/example/example.go --- containerd-1.2.6/runtime/v2/example/example.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/example/example.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,138 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package example + +import ( + "context" + "os" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/runtime/v2/shim" + taskAPI "github.com/containerd/containerd/runtime/v2/task" + ptypes "github.com/gogo/protobuf/types" +) + +var ( + // check to make sure the *service implements the GRPC API + _ = (taskAPI.TaskService)(&service{}) +) + +// New returns a new shim service +func New(ctx context.Context, id string, publisher shim.Publisher, shutdown func()) (shim.Shim, error) { + return &service{}, nil +} + +type service struct { +} + +// StartShim is a binary call that executes a new shim returning the address +func (s *service) StartShim(ctx context.Context, opts shim.StartOpts) (string, error) { + return "", nil +} + +// Cleanup is a binary call that cleans up any resources used by the shim when the service crashes +func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Create a new container +func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { + return nil, errdefs.ErrNotImplemented +} + +// Start the primary user process inside the container +func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Delete a process or container +func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Exec an additional process inside the container +func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// ResizePty of a process +func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// State returns runtime state of a process +func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Pause the container +func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Resume the container +func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Kill a process +func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Pids returns all pids inside the container +func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// CloseIO of a process +func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Checkpoint the container +func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Connect returns shim information of the underlying service +func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Shutdown is called after the underlying resources of the shim are cleaned up and the service can be stopped +func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { + os.Exit(0) + return &ptypes.Empty{}, nil +} + +// Stats returns container level system stats for a container and its processes +func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + return nil, errdefs.ErrNotImplemented +} + +// Update the live container +func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { + return nil, errdefs.ErrNotImplemented +} + +// Wait for a process to exit +func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + return nil, errdefs.ErrNotImplemented +} diff -Nru containerd-1.2.6/runtime/v2/example/README.md containerd-1.5.9/runtime/v2/example/README.md --- containerd-1.2.6/runtime/v2/example/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/example/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,6 @@ +# Example Shim + +This directory provides skeleton code as the starting point for creating a Runtime v2 shim. +This allows runtime authors to quickly bootstrap new shim implementations. + +For full documentation on building a shim for containerd, see the [Shim Documentation](../README.md) file. diff -Nru containerd-1.2.6/runtime/v2/logging/logging.go containerd-1.5.9/runtime/v2/logging/logging.go --- containerd-1.2.6/runtime/v2/logging/logging.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/logging/logging.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logging + +import ( + "context" + "io" +) + +// Config of the container logs +type Config struct { + ID string + Namespace string + Stdout io.Reader + Stderr io.Reader +} + +// LoggerFunc is implemented by custom v2 logging binaries +type LoggerFunc func(context.Context, *Config, func() error) error diff -Nru containerd-1.2.6/runtime/v2/logging/logging_unix.go containerd-1.5.9/runtime/v2/logging/logging_unix.go --- containerd-1.2.6/runtime/v2/logging/logging_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/logging/logging_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,64 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logging + +import ( + "context" + "fmt" + "os" + "os/signal" + + "golang.org/x/sys/unix" +) + +// Run the logging driver +func Run(fn LoggerFunc) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + config := &Config{ + ID: os.Getenv("CONTAINER_ID"), + Namespace: os.Getenv("CONTAINER_NAMESPACE"), + Stdout: os.NewFile(3, "CONTAINER_STDOUT"), + Stderr: os.NewFile(4, "CONTAINER_STDERR"), + } + var ( + sigCh = make(chan os.Signal, 32) + errCh = make(chan error, 1) + wait = os.NewFile(5, "CONTAINER_WAIT") + ) + signal.Notify(sigCh, unix.SIGTERM) + + go func() { + errCh <- fn(ctx, config, wait.Close) + }() + + for { + select { + case <-sigCh: + cancel() + case err := <-errCh: + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(0) + } + } +} diff -Nru containerd-1.2.6/runtime/v2/logging/logging_windows.go containerd-1.5.9/runtime/v2/logging/logging_windows.go --- containerd-1.2.6/runtime/v2/logging/logging_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/logging/logging_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,99 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package logging + +import ( + "context" + "fmt" + "net" + "os" + "os/signal" + "syscall" + + "github.com/Microsoft/go-winio" + "github.com/pkg/errors" +) + +// Run the logging driver +func Run(fn LoggerFunc) { + err := runInternal(fn) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(0) +} + +func runInternal(fn LoggerFunc) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var ( + soutPipe, serrPipe, waitPipe string + sout, serr, wait net.Conn + ok bool + err error + ) + + if soutPipe, ok = os.LookupEnv("CONTAINER_STDOUT"); !ok { + return errors.New("'CONTAINER_STDOUT' environment variable missing") + } + if sout, err = winio.DialPipeContext(ctx, soutPipe); err != nil { + return errors.Wrap(err, "unable to dial stdout pipe") + } + + if serrPipe, ok = os.LookupEnv("CONTAINER_STDERR"); !ok { + return errors.New("'CONTAINER_STDERR' environment variable missing") + } + if serr, err = winio.DialPipeContext(ctx, serrPipe); err != nil { + return errors.Wrap(err, "unable to dial stderr pipe") + } + + waitPipe = os.Getenv("CONTAINER_WAIT") + if wait, err = winio.DialPipeContext(ctx, waitPipe); err != nil { + return errors.Wrap(err, "unable to dial wait pipe") + } + + config := &Config{ + ID: os.Getenv("CONTAINER_ID"), + Namespace: os.Getenv("CONTAINER_NAMESPACE"), + Stdout: sout, + Stderr: serr, + } + + var ( + sigCh = make(chan os.Signal, 2) + errCh = make(chan error, 1) + ) + + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + + go func() { + errCh <- fn(ctx, config, wait.Close) + }() + + for { + select { + case <-sigCh: + cancel() + case err = <-errCh: + return err + } + } +} diff -Nru containerd-1.2.6/runtime/v2/manager.go containerd-1.5.9/runtime/v2/manager.go --- containerd-1.2.6/runtime/v2/manager.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/manager.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,16 +24,26 @@ "path/filepath" "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/events/exchange" "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/timeout" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime" - bolt "go.etcd.io/bbolt" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" ) +// Config for the v2 runtime +type Config struct { + // Supported platforms + Platforms []string `toml:"platforms"` +} + func init() { plugin.Register(&plugin.Registration{ Type: plugin.RuntimePluginV2, @@ -41,8 +51,16 @@ Requires: []plugin.Type{ plugin.MetadataPlugin, }, + Config: &Config{ + Platforms: defaultPlatforms(), + }, InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = supportedPlatforms() + supportedPlatforms, err := parsePlatforms(ic.Config.(*Config).Platforms) + if err != nil { + return nil, err + } + + ic.Meta.Platforms = supportedPlatforms if err := os.MkdirAll(ic.Root, 0711); err != nil { return nil, err } @@ -53,25 +71,28 @@ if err != nil { return nil, err } - return New(ic.Context, ic.Root, ic.State, ic.Address, ic.Events, m.(*metadata.DB)) + cs := metadata.NewContainerStore(m.(*metadata.DB)) + + return New(ic.Context, ic.Root, ic.State, ic.Address, ic.TTRPCAddress, ic.Events, cs) }, }) } // New task manager for v2 shims -func New(ctx context.Context, root, state, containerdAddress string, events *exchange.Exchange, db *metadata.DB) (*TaskManager, error) { +func New(ctx context.Context, root, state, containerdAddress, containerdTTRPCAddress string, events *exchange.Exchange, cs containers.Store) (*TaskManager, error) { for _, d := range []string{root, state} { if err := os.MkdirAll(d, 0711); err != nil { return nil, err } } m := &TaskManager{ - root: root, - state: state, - containerdAddress: containerdAddress, - tasks: runtime.NewTaskList(), - events: events, - db: db, + root: root, + state: state, + containerdAddress: containerdAddress, + containerdTTRPCAddress: containerdTTRPCAddress, + tasks: runtime.NewTaskList(), + events: events, + containers: cs, } if err := m.loadExistingTasks(ctx); err != nil { return nil, err @@ -81,13 +102,14 @@ // TaskManager manages v2 shim's and their tasks type TaskManager struct { - root string - state string - containerdAddress string - - tasks *runtime.TaskList - events *exchange.Exchange - db *metadata.DB + root string + state string + containerdAddress string + containerdTTRPCAddress string + + tasks *runtime.TaskList + events *exchange.Exchange + containers containers.Store } // ID of the task manager @@ -96,35 +118,84 @@ } // Create a new task -func (m *TaskManager) Create(ctx context.Context, id string, opts runtime.CreateOpts) (_ runtime.Task, err error) { +func (m *TaskManager) Create(ctx context.Context, id string, opts runtime.CreateOpts) (_ runtime.Task, retErr error) { bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec.Value) if err != nil { return nil, err } defer func() { - if err != nil { + if retErr != nil { bundle.Delete() } }() - b := shimBinary(ctx, bundle, opts.Runtime, m.containerdAddress, m.events, m.tasks) - shim, err := b.Start(ctx) + + shim, err := m.startShim(ctx, bundle, id, opts) if err != nil { return nil, err } defer func() { - if err != nil { - shim.Shutdown(ctx) - shim.Close() + if retErr != nil { + m.deleteShim(shim) } }() + t, err := shim.Create(ctx, opts) if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to create shim") } - m.tasks.Add(ctx, t) + + if err := m.tasks.Add(ctx, t); err != nil { + return nil, errors.Wrap(err, "failed to add task") + } + return t, nil } +func (m *TaskManager) startShim(ctx context.Context, bundle *Bundle, id string, opts runtime.CreateOpts) (*shim, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + topts := opts.TaskOptions + if topts == nil { + topts = opts.RuntimeOptions + } + + b := shimBinary(ctx, bundle, opts.Runtime, m.containerdAddress, m.containerdTTRPCAddress, m.events, m.tasks) + shim, err := b.Start(ctx, topts, func() { + log.G(ctx).WithField("id", id).Info("shim disconnected") + + cleanupAfterDeadShim(context.Background(), id, ns, m.tasks, m.events, b) + // Remove self from the runtime task list. Even though the cleanupAfterDeadShim() + // would publish taskExit event, but the shim.Delete() would always failed with ttrpc + // disconnect and there is no chance to remove this dead task from runtime task lists. + // Thus it's better to delete it here. + m.tasks.Delete(ctx, id) + }) + if err != nil { + return nil, errors.Wrap(err, "start failed") + } + + return shim, nil +} + +// deleteShim attempts to properly delete and cleanup shim after error +func (m *TaskManager) deleteShim(shim *shim) { + dctx, cancel := timeout.WithContext(context.Background(), cleanupTimeout) + defer cancel() + + _, errShim := shim.Delete(dctx) + if errShim != nil { + if errdefs.IsDeadlineExceeded(errShim) { + dctx, cancel = timeout.WithContext(context.Background(), cleanupTimeout) + defer cancel() + } + shim.Shutdown(dctx) + shim.Close() + } +} + // Get a specific task func (m *TaskManager) Get(ctx context.Context, id string) (runtime.Task, error) { return m.tasks.Get(ctx, id) @@ -155,6 +226,10 @@ continue } ns := nsd.Name() + // skip hidden directories + if len(ns) > 0 && ns[0] == '.' { + continue + } log.G(ctx).WithField("namespace", ns).Debug("loading tasks in namespace") if err := m.loadTasks(namespaces.WithNamespace(ctx, ns)); err != nil { log.G(ctx).WithField("namespace", ns).WithError(err).Error("loading tasks in namespace") @@ -182,6 +257,10 @@ continue } id := sd.Name() + // skip hidden directories + if len(id) > 0 && id[0] == '.' { + continue + } bundle, err := LoadBundle(ctx, m.state, id) if err != nil { // fine to return error here, it is a programmer error if the context @@ -199,23 +278,25 @@ bundle.Delete() continue } - shim, err := loadShim(ctx, bundle, m.events, m.tasks) + container, err := m.container(ctx, id) if err != nil { - log.G(ctx).WithError(err).Errorf("cleanup dead shim %s", id) - container, err := m.container(ctx, id) - if err != nil { - log.G(ctx).WithError(err).Errorf("loading dead container %s", id) - if err := mount.UnmountAll(filepath.Join(bundle.Path, "rootfs"), 0); err != nil { - log.G(ctx).WithError(err).Errorf("forceful unmount of rootfs %s", id) - } - bundle.Delete() - continue - } - binaryCall := shimBinary(ctx, bundle, container.Runtime.Name, m.containerdAddress, m.events, m.tasks) - if _, err := binaryCall.Delete(ctx); err != nil { - log.G(ctx).WithError(err).Errorf("binary call to delete for %s", id) - continue + log.G(ctx).WithError(err).Errorf("loading container %s", id) + if err := mount.UnmountAll(filepath.Join(bundle.Path, "rootfs"), 0); err != nil { + log.G(ctx).WithError(err).Errorf("forceful unmount of rootfs %s", id) } + bundle.Delete() + continue + } + binaryCall := shimBinary(ctx, bundle, container.Runtime.Name, m.containerdAddress, m.containerdTTRPCAddress, m.events, m.tasks) + shim, err := loadShim(ctx, bundle, m.events, m.tasks, func() { + log.G(ctx).WithField("id", id).Info("shim disconnected") + + cleanupAfterDeadShim(context.Background(), id, ns, m.tasks, m.events, binaryCall) + // Remove self from the runtime task list. + m.tasks.Delete(ctx, id) + }) + if err != nil { + cleanupAfterDeadShim(ctx, id, ns, m.tasks, m.events, binaryCall) continue } m.tasks.Add(ctx, shim) @@ -224,13 +305,8 @@ } func (m *TaskManager) container(ctx context.Context, id string) (*containers.Container, error) { - var container containers.Container - if err := m.db.View(func(tx *bolt.Tx) error { - store := metadata.NewContainerStore(tx) - var err error - container, err = store.Get(ctx, id) - return err - }); err != nil { + container, err := m.containers.Get(ctx, id) + if err != nil { return nil, err } return &container, nil @@ -258,3 +334,15 @@ } return nil } + +func parsePlatforms(platformStr []string) ([]ocispec.Platform, error) { + p := make([]ocispec.Platform, len(platformStr)) + for i, v := range platformStr { + parsed, err := platforms.Parse(v) + if err != nil { + return nil, err + } + p[i] = parsed + } + return p, nil +} diff -Nru containerd-1.2.6/runtime/v2/manager_unix.go containerd-1.5.9/runtime/v2/manager_unix.go --- containerd-1.2.6/runtime/v2/manager_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/manager_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,9 +20,8 @@ import ( "github.com/containerd/containerd/platforms" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -func supportedPlatforms() []ocispec.Platform { - return []ocispec.Platform{platforms.DefaultSpec()} +func defaultPlatforms() []string { + return []string{platforms.DefaultString()} } diff -Nru containerd-1.2.6/runtime/v2/manager_windows.go containerd-1.5.9/runtime/v2/manager_windows.go --- containerd-1.2.6/runtime/v2/manager_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/manager_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,15 +20,11 @@ import ( "github.com/containerd/containerd/platforms" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -func supportedPlatforms() []ocispec.Platform { - return []ocispec.Platform{ - platforms.DefaultSpec(), - { - OS: "linux", - Architecture: "amd64", - }, +func defaultPlatforms() []string { + return []string{ + platforms.DefaultString(), + "linux/amd64", } } diff -Nru containerd-1.2.6/runtime/v2/process.go containerd-1.5.9/runtime/v2/process.go --- containerd-1.2.6/runtime/v2/process.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/process.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,6 @@ import ( "context" - eventstypes "github.com/containerd/containerd/api/events" tasktypes "github.com/containerd/containerd/api/types/task" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/runtime" @@ -55,7 +54,7 @@ ExecID: p.id, }) if err != nil { - if errors.Cause(err) != ttrpc.ErrClosed { + if !errors.Is(err, ttrpc.ErrClosed) { return runtime.State{}, errdefs.FromGRPC(err) } return runtime.State{}, errdefs.ErrNotFound @@ -114,18 +113,13 @@ // Start the process func (p *process) Start(ctx context.Context) error { - response, err := p.shim.task.Start(ctx, &task.StartRequest{ + _, err := p.shim.task.Start(ctx, &task.StartRequest{ ID: p.shim.ID(), ExecID: p.id, }) if err != nil { return errdefs.FromGRPC(err) } - p.shim.events.Publish(ctx, runtime.TaskExecStartedEventTopic, &eventstypes.TaskExecStarted{ - ContainerID: p.shim.ID(), - Pid: response.Pid, - ExecID: p.id, - }) return nil } diff -Nru containerd-1.2.6/runtime/v2/README.md containerd-1.5.9/runtime/v2/README.md --- containerd-1.2.6/runtime/v2/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -36,9 +36,9 @@ The start command MUST accept the following flags: * `-namespace` the namespace for the container -* `-id` the id of the container * `-address` the address of the containerd's main socket * `-publish-binary` the binary path to publish events back to containerd +* `-id` the id of the container The start command, as well as all binary calls to the shim, has the bundle for the container set as the `cwd`. @@ -58,11 +58,12 @@ The delete command MUST accept the following flags: * `-namespace` the namespace for the container -* `-id` the id of the container * `-address` the address of the containerd's main socket * `-publish-binary` the binary path to publish events back to containerd +* `-id` the id of the container +* `-bundle` the path to the bundle to delete. On non-Windows platforms this will match `cwd` -The delete command will be executed in the container's bundle as its `cwd`. +The delete command will be executed in the container's bundle as its `cwd` except for on the Windows platform. ### Host Level Shim Configuration @@ -148,8 +149,88 @@ ### Events -The shim MUST publish a `runtime.TaskExitEventTopic` when the container exits. -If the shim collects Out of Memory events, it SHOULD also publish a `runtime.TaskOOMEventTopic`. +The Runtime v2 supports an async event model. In order for the an upstream caller (such as Docker) to get these events in the correct order a Runtime v2 shim MUST implement the following events where `Compliance=MUST`. This avoids race conditions between the shim and shim client where for example a call to `Start` can signal a `TaskExitEventTopic` before even returning the results from the `Start` call. With these guarantees of a Runtime v2 shim a call to `Start` is required to have published the async event `TaskStartEventTopic` before the shim can publish the `TaskExitEventTopic`. + +#### Tasks + +| Topic | Compliance | Description | +| ----- | ---------- | ----------- | +| `runtime.TaskCreateEventTopic` | MUST | When a task is successfully created | +| `runtime.TaskStartEventTopic` | MUST (follow `TaskCreateEventTopic`) | When a task is successfully started | +| `runtime.TaskExitEventTopic` | MUST (follow `TaskStartEventTopic`) | When a task exits expected or unexpected | +| `runtime.TaskDeleteEventTopic` | MUST (follow `TaskExitEventTopic` or `TaskCreateEventTopic` if never started) | When a task is removed from a shim | +| `runtime.TaskPausedEventTopic` | SHOULD | When a task is successfully paused | +| `runtime.TaskResumedEventTopic` | SHOULD (follow `TaskPausedEventTopic`) | When a task is successfully resumed | +| `runtime.TaskCheckpointedEventTopic` | SHOULD | When a task is checkpointed | +| `runtime.TaskOOMEventTopic` | SHOULD | If the shim collects Out of Memory events | + +#### Execs + +| Topic | Compliance | Description | +| ----- | ---------- | ----------- | +| `runtime.TaskExecAddedEventTopic` | MUST (follow `TaskCreateEventTopic` ) | When an exec is successfully added | +| `runtime.TaskExecStartedEventTopic` | MUST (follow `TaskExecAddedEventTopic`) | When an exec is successfully started | +| `runtime.TaskExitEventTopic` | MUST (follow `TaskExecStartedEventTopic`) | When an exec (other than the init exec) exits expected or unexpected | +| `runtime.TaskDeleteEventTopic` | SHOULD (follow `TaskExitEventTopic` or `TaskExecAddedEventTopic` if never started) | When an exec is removed from a shim | + +#### Logging + +Shims may support pluggable logging via STDIO URIs. +Current supported schemes for logging are: + +* fifo - Linux +* binary - Linux & Windows +* file - Linux & Windows +* npipe - Windows + +Binary logging has the ability to forward a container's STDIO to an external binary for consumption. +A sample logging driver that forwards the container's STDOUT and STDERR to `journald` is: + +```go +package main + +import ( + "bufio" + "context" + "fmt" + "io" + "sync" + + "github.com/containerd/containerd/runtime/v2/logging" + "github.com/coreos/go-systemd/journal" +) + +func main() { + logging.Run(log) +} + +func log(ctx context.Context, config *logging.Config, ready func() error) error { + // construct any log metadata for the container + vars := map[string]string{ + "SYSLOG_IDENTIFIER": fmt.Sprintf("%s:%s", config.Namespace, config.ID), + } + var wg sync.WaitGroup + wg.Add(2) + // forward both stdout and stderr to the journal + go copy(&wg, config.Stdout, journal.PriInfo, vars) + go copy(&wg, config.Stderr, journal.PriErr, vars) + + // signal that we are ready and setup for the container to be started + if err := ready(); err != nil { + return err + } + wg.Wait() + return nil +} + +func copy(wg *sync.WaitGroup, r io.Reader, pri journal.Priority, vars map[string]string) { + defer wg.Done() + s := bufio.NewScanner(r) + for s.Scan() { + journal.Send(s.Text(), pri, vars) + } +} +``` ### Other diff -Nru containerd-1.2.6/runtime/v2/runc/container.go containerd-1.5.9/runtime/v2/runc/container.go --- containerd-1.2.6/runtime/v2/runc/container.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/container.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,508 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "github.com/containerd/cgroups" + cgroupsv2 "github.com/containerd/cgroups/v2" + "github.com/containerd/console" + "github.com/containerd/containerd/errdefs" + "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/v2/runc/options" + "github.com/containerd/containerd/runtime/v2/task" + "github.com/containerd/typeurl" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// NewContainer returns a new runc container +func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTaskRequest) (_ *Container, retErr error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, errors.Wrap(err, "create namespace") + } + + var opts options.Options + if r.Options != nil && r.Options.GetTypeUrl() != "" { + v, err := typeurl.UnmarshalAny(r.Options) + if err != nil { + return nil, err + } + opts = *v.(*options.Options) + } + + var mounts []process.Mount + for _, m := range r.Rootfs { + mounts = append(mounts, process.Mount{ + Type: m.Type, + Source: m.Source, + Target: m.Target, + Options: m.Options, + }) + } + + rootfs := "" + if len(mounts) > 0 { + rootfs = filepath.Join(r.Bundle, "rootfs") + if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) { + return nil, err + } + } + + config := &process.CreateConfig{ + ID: r.ID, + Bundle: r.Bundle, + Runtime: opts.BinaryName, + Rootfs: mounts, + Terminal: r.Terminal, + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Checkpoint: r.Checkpoint, + ParentCheckpoint: r.ParentCheckpoint, + Options: r.Options, + } + + if err := WriteOptions(r.Bundle, opts); err != nil { + return nil, err + } + // For historical reason, we write opts.BinaryName as well as the entire opts + if err := WriteRuntime(r.Bundle, opts.BinaryName); err != nil { + return nil, err + } + defer func() { + if retErr != nil { + if err := mount.UnmountAll(rootfs, 0); err != nil { + logrus.WithError(err).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, errors.Wrapf(err, "failed to mount rootfs component %v", m) + } + } + + p, err := newInit( + ctx, + r.Bundle, + filepath.Join(r.Bundle, "work"), + ns, + platform, + config, + &opts, + rootfs, + ) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + if err := p.Create(ctx, config); err != nil { + return nil, errdefs.ToGRPC(err) + } + container := &Container{ + ID: r.ID, + Bundle: r.Bundle, + process: p, + processes: make(map[string]process.Process), + reservedProcess: make(map[string]struct{}), + } + pid := p.Pid() + if pid > 0 { + var cg interface{} + if cgroups.Mode() == cgroups.Unified { + g, err := cgroupsv2.PidGroupPath(pid) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup2 for %d", pid) + return container, nil + } + cg, err = cgroupsv2.LoadManager("/sys/fs/cgroup", g) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup2 for %d", pid) + } + } else { + cg, err = cgroups.Load(cgroups.V1, cgroups.PidPath(pid)) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup for %d", pid) + } + } + container.cgroup = cg + } + return container, nil +} + +const optionsFilename = "options.json" + +// ReadOptions reads the option information from the path. +// When the file does not exist, ReadOptions returns nil without an error. +func ReadOptions(path string) (*options.Options, error) { + filePath := filepath.Join(path, optionsFilename) + if _, err := os.Stat(filePath); err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + data, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, err + } + var opts options.Options + if err := json.Unmarshal(data, &opts); err != nil { + return nil, err + } + return &opts, nil +} + +// WriteOptions writes the options information into the path +func WriteOptions(path string, opts options.Options) error { + data, err := json.Marshal(opts) + if err != nil { + return err + } + return ioutil.WriteFile(filepath.Join(path, optionsFilename), data, 0600) +} + +// ReadRuntime reads the runtime information from the path +func ReadRuntime(path string) (string, error) { + data, err := ioutil.ReadFile(filepath.Join(path, "runtime")) + if err != nil { + return "", err + } + return string(data), nil +} + +// WriteRuntime writes the runtime information into the path +func WriteRuntime(path, runtime string) error { + return ioutil.WriteFile(filepath.Join(path, "runtime"), []byte(runtime), 0600) +} + +func newInit(ctx context.Context, path, workDir, namespace string, platform stdio.Platform, + r *process.CreateConfig, options *options.Options, rootfs string) (*process.Init, error) { + runtime := process.NewRunc(options.Root, path, namespace, options.BinaryName, options.CriuPath, options.SystemdCgroup) + p := process.New(r.ID, runtime, stdio.Stdio{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }) + p.Bundle = r.Bundle + p.Platform = platform + p.Rootfs = rootfs + p.WorkDir = workDir + p.IoUID = int(options.IoUid) + p.IoGID = int(options.IoGid) + p.NoPivotRoot = options.NoPivotRoot + p.NoNewKeyring = options.NoNewKeyring + p.CriuWorkPath = options.CriuWorkPath + if p.CriuWorkPath == "" { + // if criu work path not set, use container WorkDir + p.CriuWorkPath = p.WorkDir + } + return p, nil +} + +// Container for operating on a runc container and its processes +type Container struct { + mu sync.Mutex + + // ID of the container + ID string + // Bundle path + Bundle string + + // cgroup is either cgroups.Cgroup or *cgroupsv2.Manager + cgroup interface{} + process process.Process + processes map[string]process.Process + reservedProcess map[string]struct{} +} + +// All processes in the container +func (c *Container) All() (o []process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + + for _, p := range c.processes { + o = append(o, p) + } + if c.process != nil { + o = append(o, c.process) + } + return o +} + +// ExecdProcesses added to the container +func (c *Container) ExecdProcesses() (o []process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + for _, p := range c.processes { + o = append(o, p) + } + return o +} + +// Pid of the main process of a container +func (c *Container) Pid() int { + c.mu.Lock() + defer c.mu.Unlock() + return c.process.Pid() +} + +// Cgroup of the container +func (c *Container) Cgroup() interface{} { + c.mu.Lock() + defer c.mu.Unlock() + return c.cgroup +} + +// CgroupSet sets the cgroup to the container +func (c *Container) CgroupSet(cg interface{}) { + c.mu.Lock() + c.cgroup = cg + c.mu.Unlock() +} + +// Process returns the process by id +func (c *Container) Process(id string) (process.Process, error) { + c.mu.Lock() + defer c.mu.Unlock() + if id == "" { + if c.process == nil { + return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "container must be created") + } + return c.process, nil + } + p, ok := c.processes[id] + if !ok { + return nil, errors.Wrapf(errdefs.ErrNotFound, "process does not exist %s", id) + } + return p, nil +} + +// ReserveProcess checks for the existence of an id and atomically +// reserves the process id if it does not already exist +// +// Returns true if the process id was successfully reserved and a +// cancel func to release the reservation +func (c *Container) ReserveProcess(id string) (bool, func()) { + c.mu.Lock() + defer c.mu.Unlock() + + if _, ok := c.processes[id]; ok { + return false, nil + } + if _, ok := c.reservedProcess[id]; ok { + return false, nil + } + c.reservedProcess[id] = struct{}{} + return true, func() { + c.mu.Lock() + defer c.mu.Unlock() + delete(c.reservedProcess, id) + } +} + +// ProcessAdd adds a new process to the container +func (c *Container) ProcessAdd(process process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + + delete(c.reservedProcess, process.ID()) + c.processes[process.ID()] = process +} + +// ProcessRemove removes the process by id from the container +func (c *Container) ProcessRemove(id string) { + c.mu.Lock() + defer c.mu.Unlock() + delete(c.processes, id) +} + +// Start a container process +func (c *Container) Start(ctx context.Context, r *task.StartRequest) (process.Process, error) { + p, err := c.Process(r.ExecID) + if err != nil { + return nil, err + } + if err := p.Start(ctx); err != nil { + return nil, err + } + if c.Cgroup() == nil && p.Pid() > 0 { + var cg interface{} + if cgroups.Mode() == cgroups.Unified { + g, err := cgroupsv2.PidGroupPath(p.Pid()) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup2 for %d", p.Pid()) + } + cg, err = cgroupsv2.LoadManager("/sys/fs/cgroup", g) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup2 for %d", p.Pid()) + } + } else { + cg, err = cgroups.Load(cgroups.V1, cgroups.PidPath(p.Pid())) + if err != nil { + logrus.WithError(err).Errorf("loading cgroup for %d", p.Pid()) + } + } + c.cgroup = cg + } + return p, nil +} + +// Delete the container or a process by id +func (c *Container) Delete(ctx context.Context, r *task.DeleteRequest) (process.Process, error) { + p, err := c.Process(r.ExecID) + if err != nil { + return nil, err + } + if err := p.Delete(ctx); err != nil { + return nil, err + } + if r.ExecID != "" { + c.ProcessRemove(r.ExecID) + } + return p, nil +} + +// Exec an additional process +func (c *Container) Exec(ctx context.Context, r *task.ExecProcessRequest) (process.Process, error) { + process, err := c.process.(*process.Init).Exec(ctx, c.Bundle, &process.ExecConfig{ + ID: r.ExecID, + Terminal: r.Terminal, + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Spec: r.Spec, + }) + if err != nil { + return nil, err + } + c.ProcessAdd(process) + return process, nil +} + +// Pause the container +func (c *Container) Pause(ctx context.Context) error { + return c.process.(*process.Init).Pause(ctx) +} + +// Resume the container +func (c *Container) Resume(ctx context.Context) error { + return c.process.(*process.Init).Resume(ctx) +} + +// ResizePty of a process +func (c *Container) ResizePty(ctx context.Context, r *task.ResizePtyRequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + ws := console.WinSize{ + Width: uint16(r.Width), + Height: uint16(r.Height), + } + return p.Resize(ws) +} + +// Kill a process +func (c *Container) Kill(ctx context.Context, r *task.KillRequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + return p.Kill(ctx, r.Signal, r.All) +} + +// CloseIO of a process +func (c *Container) CloseIO(ctx context.Context, r *task.CloseIORequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + if stdin := p.Stdin(); stdin != nil { + if err := stdin.Close(); err != nil { + return errors.Wrap(err, "close stdin") + } + } + return nil +} + +// Checkpoint the container +func (c *Container) Checkpoint(ctx context.Context, r *task.CheckpointTaskRequest) error { + p, err := c.Process("") + if err != nil { + return err + } + var opts options.CheckpointOptions + if r.Options != nil { + v, err := typeurl.UnmarshalAny(r.Options) + if err != nil { + return err + } + opts = *v.(*options.CheckpointOptions) + } + return p.(*process.Init).Checkpoint(ctx, &process.CheckpointConfig{ + Path: r.Path, + Exit: opts.Exit, + AllowOpenTCP: opts.OpenTcp, + AllowExternalUnixSockets: opts.ExternalUnixSockets, + AllowTerminal: opts.Terminal, + FileLocks: opts.FileLocks, + EmptyNamespaces: opts.EmptyNamespaces, + WorkDir: opts.WorkPath, + }) +} + +// Update the resource information of a running container +func (c *Container) Update(ctx context.Context, r *task.UpdateTaskRequest) error { + p, err := c.Process("") + if err != nil { + return err + } + return p.(*process.Init).Update(ctx, r.Resources) +} + +// HasPid returns true if the container owns a specific pid +func (c *Container) HasPid(pid int) bool { + if c.Pid() == pid { + return true + } + for _, p := range c.All() { + if p.Pid() == pid { + return true + } + } + return false +} diff -Nru containerd-1.2.6/runtime/v2/runc/epoll.go containerd-1.5.9/runtime/v2/runc/epoll.go --- containerd-1.2.6/runtime/v2/runc/epoll.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/epoll.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runc - -import ( - "context" - "sync" - - "github.com/containerd/cgroups" - eventstypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/runtime" - "github.com/sirupsen/logrus" - "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 { - continue - } - logrus.WithError(err).Error("cgroups: epoll wait") - } - 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, &eventstypes.TaskOOM{ - ContainerID: i.id, - }); err != nil { - logrus.WithError(err).Error("publish OOM event") - } -} - -func flush(fd uintptr) error { - var buf [8]byte - _, err := unix.Read(int(fd), buf[:]) - return err -} diff -Nru containerd-1.2.6/runtime/v2/runc/options/next.pb.txt containerd-1.5.9/runtime/v2/runc/options/next.pb.txt --- containerd-1.2.6/runtime/v2/runc/options/next.pb.txt 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/options/next.pb.txt 2022-01-05 17:30:58.000000000 +0000 @@ -67,6 +67,20 @@ type: TYPE_BOOL json_name: "systemdCgroup" } + field { + name: "criu_image_path" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuImagePath" + } + field { + name: "criu_work_path" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuWorkPath" + } } message_type { name: "CheckpointOptions" @@ -119,6 +133,20 @@ type: TYPE_STRING json_name: "cgroupsMode" } + field { + name: "image_path" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "imagePath" + } + field { + name: "work_path" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "workPath" + } } message_type { name: "ProcessDetails" diff -Nru containerd-1.2.6/runtime/v2/runc/options/oci.pb.go containerd-1.5.9/runtime/v2/runc/options/oci.pb.go --- containerd-1.2.6/runtime/v2/runc/options/oci.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/options/oci.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,29 +1,17 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/runtime/v2/runc/options/oci.proto -/* - Package options is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/runtime/v2/runc/options/oci.proto - - It has these top-level messages: - Options - CheckpointOptions - ProcessDetails -*/ package options -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -34,7 +22,7 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Options struct { // disable pivot root when creating a container @@ -55,11 +43,46 @@ CriuPath string `protobuf:"bytes,8,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"` // enable systemd cgroups SystemdCgroup bool `protobuf:"varint,9,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` + // criu image path + CriuImagePath string `protobuf:"bytes,10,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"` + // criu work path + CriuWorkPath string `protobuf:"bytes,11,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Options) Reset() { *m = Options{} } -func (*Options) ProtoMessage() {} -func (*Options) Descriptor() ([]byte, []int) { return fileDescriptorOci, []int{0} } +func (m *Options) Reset() { *m = Options{} } +func (*Options) ProtoMessage() {} +func (*Options) Descriptor() ([]byte, []int) { + return fileDescriptor_4e5440d739e9a863, []int{0} +} +func (m *Options) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Options) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Options.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Options) XXX_Merge(src proto.Message) { + xxx_messageInfo_Options.Merge(m, src) +} +func (m *Options) XXX_Size() int { + return m.Size() +} +func (m *Options) XXX_DiscardUnknown() { + xxx_messageInfo_Options.DiscardUnknown(m) +} + +var xxx_messageInfo_Options proto.InternalMessageInfo type CheckpointOptions struct { // exit the container after a checkpoint @@ -73,33 +96,145 @@ // allow checkpointing of file locks FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` // restore provided namespaces as empty namespaces - EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"` + EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces,proto3" json:"empty_namespaces,omitempty"` // set the cgroups mode, soft, full, strict CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` + // checkpoint image path + ImagePath string `protobuf:"bytes,8,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"` + // checkpoint work path + WorkPath string `protobuf:"bytes,9,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} } -func (*CheckpointOptions) ProtoMessage() {} -func (*CheckpointOptions) Descriptor() ([]byte, []int) { return fileDescriptorOci, []int{1} } +func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} } +func (*CheckpointOptions) ProtoMessage() {} +func (*CheckpointOptions) Descriptor() ([]byte, []int) { + return fileDescriptor_4e5440d739e9a863, []int{1} +} +func (m *CheckpointOptions) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointOptions.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointOptions) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointOptions.Merge(m, src) +} +func (m *CheckpointOptions) XXX_Size() int { + return m.Size() +} +func (m *CheckpointOptions) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointOptions.DiscardUnknown(m) +} + +var xxx_messageInfo_CheckpointOptions proto.InternalMessageInfo type ProcessDetails struct { // exec process id if the process is managed by a shim - ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ProcessDetails) Reset() { *m = ProcessDetails{} } +func (*ProcessDetails) ProtoMessage() {} +func (*ProcessDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_4e5440d739e9a863, []int{2} +} +func (m *ProcessDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ProcessDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ProcessDetails.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ProcessDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProcessDetails.Merge(m, src) +} +func (m *ProcessDetails) XXX_Size() int { + return m.Size() +} +func (m *ProcessDetails) XXX_DiscardUnknown() { + xxx_messageInfo_ProcessDetails.DiscardUnknown(m) } -func (m *ProcessDetails) Reset() { *m = ProcessDetails{} } -func (*ProcessDetails) ProtoMessage() {} -func (*ProcessDetails) Descriptor() ([]byte, []int) { return fileDescriptorOci, []int{2} } +var xxx_messageInfo_ProcessDetails proto.InternalMessageInfo func init() { proto.RegisterType((*Options)(nil), "containerd.runc.v1.Options") proto.RegisterType((*CheckpointOptions)(nil), "containerd.runc.v1.CheckpointOptions") proto.RegisterType((*ProcessDetails)(nil), "containerd.runc.v1.ProcessDetails") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/runtime/v2/runc/options/oci.proto", fileDescriptor_4e5440d739e9a863) +} + +var fileDescriptor_4e5440d739e9a863 = []byte{ + // 587 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0x87, 0xeb, 0xfe, 0x49, 0xec, 0x4d, 0x93, 0xc2, 0x42, 0x25, 0xd3, 0x8a, 0x34, 0x94, 0x82, + 0xc2, 0x25, 0x11, 0x45, 0x9c, 0xb8, 0xa0, 0xb6, 0x08, 0x55, 0x40, 0xa9, 0x0c, 0x15, 0xa8, 0x97, + 0x95, 0xbb, 0x1e, 0x9c, 0x51, 0xe2, 0x1d, 0xcb, 0xbb, 0x69, 0xd2, 0x1b, 0xef, 0xc5, 0x0b, 0xf4, + 0xc8, 0x91, 0x13, 0xa2, 0xb9, 0xf1, 0x16, 0x68, 0xd7, 0x4e, 0xdb, 0x33, 0x27, 0xcf, 0x7e, 0xf3, + 0xf3, 0x78, 0xfd, 0xad, 0x96, 0xed, 0xa5, 0x68, 0x06, 0xe3, 0xb3, 0x9e, 0xa4, 0xac, 0x2f, 0x49, + 0x99, 0x18, 0x15, 0x14, 0xc9, 0xed, 0xb2, 0x18, 0x2b, 0x83, 0x19, 0xf4, 0xcf, 0x77, 0x6d, 0x29, + 0xfb, 0x94, 0x1b, 0x24, 0xa5, 0xfb, 0x24, 0xb1, 0x97, 0x17, 0x64, 0x88, 0xf3, 0x9b, 0x74, 0xcf, + 0x46, 0x7a, 0xe7, 0xcf, 0x37, 0xee, 0xa7, 0x94, 0x92, 0x6b, 0xf7, 0x6d, 0x55, 0x26, 0xb7, 0xff, + 0x2e, 0xb2, 0xfa, 0xc7, 0xf2, 0x7d, 0xbe, 0xcd, 0x9a, 0x8a, 0x44, 0x8e, 0xe7, 0x64, 0x44, 0x41, + 0x64, 0x42, 0xaf, 0xe3, 0x75, 0xfd, 0xa8, 0xa1, 0xe8, 0xd8, 0xb2, 0x88, 0xc8, 0xf0, 0x1d, 0xd6, + 0x52, 0x24, 0x14, 0x4c, 0xc4, 0x10, 0x2e, 0x0a, 0x54, 0x69, 0xb8, 0xe8, 0x42, 0xab, 0x8a, 0x8e, + 0x60, 0xf2, 0xae, 0x64, 0x7c, 0x8b, 0x35, 0xf4, 0x00, 0x33, 0x21, 0xd3, 0x82, 0xc6, 0x79, 0xb8, + 0xd4, 0xf1, 0xba, 0x41, 0xc4, 0x2c, 0xda, 0x77, 0x84, 0xaf, 0xb3, 0x1a, 0x92, 0x18, 0x63, 0x12, + 0x2e, 0x77, 0xbc, 0x6e, 0x33, 0x5a, 0x41, 0x3a, 0xc1, 0xa4, 0xc2, 0x29, 0x26, 0xe1, 0xca, 0x1c, + 0xbf, 0xc5, 0xc4, 0x8e, 0x3b, 0x43, 0x15, 0x17, 0x17, 0x42, 0xc5, 0x19, 0x84, 0xb5, 0x72, 0x5c, + 0x89, 0x8e, 0xe2, 0x0c, 0x38, 0x67, 0xcb, 0x6e, 0xc3, 0x75, 0xd7, 0x71, 0x35, 0xdf, 0x64, 0x81, + 0x2c, 0x70, 0x2c, 0xf2, 0xd8, 0x0c, 0x42, 0xdf, 0x35, 0x7c, 0x0b, 0x8e, 0x63, 0x33, 0xe0, 0x4f, + 0x58, 0x4b, 0x5f, 0x68, 0x03, 0x59, 0x32, 0xdf, 0x63, 0xe0, 0x7e, 0xa3, 0x59, 0xd1, 0x6a, 0x9b, + 0x4f, 0xd9, 0x9a, 0x9b, 0x81, 0x59, 0x9c, 0x42, 0x39, 0x89, 0xb9, 0x49, 0x4d, 0x8b, 0x0f, 0x2d, + 0x75, 0xe3, 0x76, 0x58, 0xcb, 0xe5, 0x26, 0x54, 0x0c, 0xcb, 0x58, 0xc3, 0xc5, 0x56, 0x2d, 0xfd, + 0x42, 0xc5, 0xd0, 0xa6, 0xb6, 0x7f, 0x2c, 0xb2, 0xbb, 0xfb, 0x03, 0x90, 0xc3, 0x9c, 0x50, 0x99, + 0xb9, 0x75, 0xce, 0x96, 0x61, 0x8a, 0x73, 0xd9, 0xae, 0xe6, 0x0f, 0x98, 0x4f, 0x39, 0x28, 0x61, + 0x64, 0x5e, 0xf9, 0xad, 0xdb, 0xf5, 0x67, 0x99, 0xf3, 0x5d, 0xb6, 0x0e, 0x53, 0x03, 0x85, 0x8a, + 0x47, 0x62, 0xac, 0x70, 0x2a, 0x34, 0xc9, 0x21, 0x18, 0xed, 0x24, 0xfb, 0xd1, 0xbd, 0x79, 0xf3, + 0x44, 0xe1, 0xf4, 0x53, 0xd9, 0xe2, 0x1b, 0xcc, 0x37, 0x50, 0x64, 0xa8, 0xe2, 0x91, 0xf3, 0xed, + 0x47, 0xd7, 0x6b, 0xfe, 0x90, 0xb1, 0x6f, 0x38, 0x02, 0x31, 0x22, 0x39, 0xd4, 0x4e, 0xbb, 0x1f, + 0x05, 0x96, 0xbc, 0xb7, 0x80, 0x3f, 0x63, 0x77, 0x20, 0xcb, 0x4d, 0x69, 0x5e, 0xe7, 0xb1, 0x04, + 0x1d, 0xd6, 0x3a, 0x4b, 0xdd, 0x20, 0x5a, 0x73, 0xfc, 0xe8, 0x1a, 0xf3, 0x47, 0x6c, 0xb5, 0x74, + 0xa9, 0x45, 0x46, 0x09, 0x54, 0x87, 0xd1, 0xa8, 0xd8, 0x07, 0x4a, 0xc0, 0x7e, 0xec, 0x96, 0xca, + 0xf2, 0x50, 0x02, 0xbc, 0xd6, 0xb8, 0xc9, 0x82, 0x1b, 0x83, 0x41, 0x79, 0x64, 0x93, 0xb9, 0xbd, + 0x97, 0xac, 0x75, 0x5c, 0x90, 0x04, 0xad, 0x0f, 0xc0, 0xc4, 0x38, 0xd2, 0xfc, 0x31, 0xab, 0xc3, + 0x14, 0xa4, 0xc0, 0xc4, 0xc9, 0x0b, 0xf6, 0xd8, 0xec, 0xf7, 0x56, 0xed, 0xcd, 0x14, 0xe4, 0xe1, + 0x41, 0x54, 0xb3, 0xad, 0xc3, 0x64, 0xef, 0xf4, 0xf2, 0xaa, 0xbd, 0xf0, 0xeb, 0xaa, 0xbd, 0xf0, + 0x7d, 0xd6, 0xf6, 0x2e, 0x67, 0x6d, 0xef, 0xe7, 0xac, 0xed, 0xfd, 0x99, 0xb5, 0xbd, 0xd3, 0xd7, + 0xff, 0x7b, 0xd1, 0x5e, 0x55, 0xcf, 0xaf, 0x0b, 0x67, 0x35, 0x77, 0x8b, 0x5e, 0xfc, 0x0b, 0x00, + 0x00, 0xff, 0xff, 0x90, 0x50, 0x79, 0xf2, 0xb5, 0x03, 0x00, 0x00, +} + func (m *Options) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -107,81 +242,108 @@ } func (m *Options) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Options) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.NoPivotRoot { - dAtA[i] = 0x8 - i++ - if m.NoPivotRoot { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i++ + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.CriuWorkPath) > 0 { + i -= len(m.CriuWorkPath) + copy(dAtA[i:], m.CriuWorkPath) + i = encodeVarintOci(dAtA, i, uint64(len(m.CriuWorkPath))) + i-- + dAtA[i] = 0x5a + } + if len(m.CriuImagePath) > 0 { + i -= len(m.CriuImagePath) + copy(dAtA[i:], m.CriuImagePath) + i = encodeVarintOci(dAtA, i, uint64(len(m.CriuImagePath))) + i-- + dAtA[i] = 0x52 } - if m.NoNewKeyring { - dAtA[i] = 0x10 - i++ - if m.NoNewKeyring { + if m.SystemdCgroup { + i-- + if m.SystemdCgroup { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x48 } - if len(m.ShimCgroup) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintOci(dAtA, i, uint64(len(m.ShimCgroup))) - i += copy(dAtA[i:], m.ShimCgroup) + if len(m.CriuPath) > 0 { + i -= len(m.CriuPath) + copy(dAtA[i:], m.CriuPath) + i = encodeVarintOci(dAtA, i, uint64(len(m.CriuPath))) + i-- + dAtA[i] = 0x42 } - if m.IoUid != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintOci(dAtA, i, uint64(m.IoUid)) + if len(m.Root) > 0 { + i -= len(m.Root) + copy(dAtA[i:], m.Root) + i = encodeVarintOci(dAtA, i, uint64(len(m.Root))) + i-- + dAtA[i] = 0x3a + } + if len(m.BinaryName) > 0 { + i -= len(m.BinaryName) + copy(dAtA[i:], m.BinaryName) + i = encodeVarintOci(dAtA, i, uint64(len(m.BinaryName))) + i-- + dAtA[i] = 0x32 } if m.IoGid != 0 { - dAtA[i] = 0x28 - i++ i = encodeVarintOci(dAtA, i, uint64(m.IoGid)) + i-- + dAtA[i] = 0x28 } - if len(m.BinaryName) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintOci(dAtA, i, uint64(len(m.BinaryName))) - i += copy(dAtA[i:], m.BinaryName) + if m.IoUid != 0 { + i = encodeVarintOci(dAtA, i, uint64(m.IoUid)) + i-- + dAtA[i] = 0x20 } - if len(m.Root) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintOci(dAtA, i, uint64(len(m.Root))) - i += copy(dAtA[i:], m.Root) + if len(m.ShimCgroup) > 0 { + i -= len(m.ShimCgroup) + copy(dAtA[i:], m.ShimCgroup) + i = encodeVarintOci(dAtA, i, uint64(len(m.ShimCgroup))) + i-- + dAtA[i] = 0x1a } - if len(m.CriuPath) > 0 { - dAtA[i] = 0x42 - i++ - i = encodeVarintOci(dAtA, i, uint64(len(m.CriuPath))) - i += copy(dAtA[i:], m.CriuPath) + if m.NoNewKeyring { + i-- + if m.NoNewKeyring { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 } - if m.SystemdCgroup { - dAtA[i] = 0x48 - i++ - if m.SystemdCgroup { + if m.NoPivotRoot { + i-- + if m.NoPivotRoot { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointOptions) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -189,88 +351,106 @@ } func (m *CheckpointOptions) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Exit { - dAtA[i] = 0x8 - i++ - if m.Exit { + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.WorkPath) > 0 { + i -= len(m.WorkPath) + copy(dAtA[i:], m.WorkPath) + i = encodeVarintOci(dAtA, i, uint64(len(m.WorkPath))) + i-- + dAtA[i] = 0x4a + } + if len(m.ImagePath) > 0 { + i -= len(m.ImagePath) + copy(dAtA[i:], m.ImagePath) + i = encodeVarintOci(dAtA, i, uint64(len(m.ImagePath))) + i-- + dAtA[i] = 0x42 + } + if len(m.CgroupsMode) > 0 { + i -= len(m.CgroupsMode) + copy(dAtA[i:], m.CgroupsMode) + i = encodeVarintOci(dAtA, i, uint64(len(m.CgroupsMode))) + i-- + dAtA[i] = 0x3a + } + if len(m.EmptyNamespaces) > 0 { + for iNdEx := len(m.EmptyNamespaces) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EmptyNamespaces[iNdEx]) + copy(dAtA[i:], m.EmptyNamespaces[iNdEx]) + i = encodeVarintOci(dAtA, i, uint64(len(m.EmptyNamespaces[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if m.FileLocks { + i-- + if m.FileLocks { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x28 } - if m.OpenTcp { - dAtA[i] = 0x10 - i++ - if m.OpenTcp { + if m.Terminal { + i-- + if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 } if m.ExternalUnixSockets { - dAtA[i] = 0x18 - i++ + i-- if m.ExternalUnixSockets { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 } - if m.Terminal { - dAtA[i] = 0x20 - i++ - if m.Terminal { + if m.OpenTcp { + i-- + if m.OpenTcp { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 } - if m.FileLocks { - dAtA[i] = 0x28 - i++ - if m.FileLocks { + if m.Exit { + i-- + if m.Exit { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.EmptyNamespaces) > 0 { - for _, s := range m.EmptyNamespaces { - dAtA[i] = 0x32 - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } - } - if len(m.CgroupsMode) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintOci(dAtA, i, uint64(len(m.CgroupsMode))) - i += copy(dAtA[i:], m.CgroupsMode) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *ProcessDetails) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -278,29 +458,44 @@ } func (m *ProcessDetails) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ProcessDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ExecID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintOci(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintOci(dAtA []byte, offset int, v uint64) int { + offset -= sovOci(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *Options) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.NoPivotRoot { @@ -334,10 +529,24 @@ if m.SystemdCgroup { n += 2 } + l = len(m.CriuImagePath) + if l > 0 { + n += 1 + l + sovOci(uint64(l)) + } + l = len(m.CriuWorkPath) + if l > 0 { + n += 1 + l + sovOci(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointOptions) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Exit { @@ -365,28 +574,38 @@ if l > 0 { n += 1 + l + sovOci(uint64(l)) } + l = len(m.ImagePath) + if l > 0 { + n += 1 + l + sovOci(uint64(l)) + } + l = len(m.WorkPath) + if l > 0 { + n += 1 + l + sovOci(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ProcessDetails) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ExecID) if l > 0 { n += 1 + l + sovOci(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovOci(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozOci(x uint64) (n int) { return sovOci(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -405,6 +624,9 @@ `Root:` + fmt.Sprintf("%v", this.Root) + `,`, `CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`, `SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`, + `CriuImagePath:` + fmt.Sprintf("%v", this.CriuImagePath) + `,`, + `CriuWorkPath:` + fmt.Sprintf("%v", this.CriuWorkPath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -421,6 +643,9 @@ `FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`, `EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`, `CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`, + `ImagePath:` + fmt.Sprintf("%v", this.ImagePath) + `,`, + `WorkPath:` + fmt.Sprintf("%v", this.WorkPath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -431,6 +656,7 @@ } s := strings.Join([]string{`&ProcessDetails{`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -458,7 +684,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -486,7 +712,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -506,7 +732,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -526,7 +752,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -536,6 +762,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -555,7 +784,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.IoUid |= (uint32(b) & 0x7F) << shift + m.IoUid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -574,7 +803,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.IoGid |= (uint32(b) & 0x7F) << shift + m.IoGid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -593,7 +822,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -603,6 +832,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -622,7 +854,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -632,6 +864,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -651,7 +886,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -661,6 +896,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -680,24 +918,89 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } m.SystemdCgroup = bool(v != 0) + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CriuImagePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOci + } + 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 ErrInvalidLengthOci + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CriuImagePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CriuWorkPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOci + } + 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 ErrInvalidLengthOci + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CriuWorkPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipOci(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthOci } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -722,7 +1025,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -750,7 +1053,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -770,7 +1073,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -790,7 +1093,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -810,7 +1113,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -830,7 +1133,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -850,7 +1153,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -860,6 +1163,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -879,7 +1185,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -889,23 +1195,91 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } m.CgroupsMode = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ImagePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOci + } + 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 ErrInvalidLengthOci + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ImagePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WorkPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOci + } + 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 ErrInvalidLengthOci + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WorkPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipOci(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthOci } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -930,7 +1304,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -958,7 +1332,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -968,6 +1342,9 @@ return ErrInvalidLengthOci } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOci + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -979,12 +1356,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthOci } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -997,6 +1375,7 @@ func skipOci(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1028,10 +1407,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -1048,95 +1425,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthOci } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowOci - } - 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 := skipOci(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupOci + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthOci + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthOci = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowOci = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthOci = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowOci = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupOci = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/runtime/v2/runc/options/oci.proto", fileDescriptorOci) -} - -var fileDescriptorOci = []byte{ - // 529 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0x86, 0xeb, 0xfe, 0x38, 0xf6, 0xf4, 0xe7, 0xfb, 0x18, 0xa8, 0x64, 0x8a, 0x70, 0x43, 0x00, - 0x29, 0x6c, 0x12, 0x51, 0xc4, 0x8a, 0x0d, 0x6a, 0x8b, 0x50, 0x05, 0x94, 0xca, 0x50, 0x09, 0x75, - 0x33, 0x72, 0xc6, 0x07, 0xe7, 0x28, 0xf1, 0x1c, 0xcb, 0x33, 0x4e, 0x9d, 0x1d, 0xf7, 0xc1, 0x0d, - 0x75, 0xc9, 0x92, 0x15, 0xa2, 0xb9, 0x11, 0x90, 0xc7, 0x4e, 0x61, 0xcd, 0xca, 0xef, 0x3c, 0xef, - 0xf1, 0x68, 0xe6, 0xd1, 0xb0, 0xc3, 0x14, 0xcd, 0xb8, 0x1c, 0x0d, 0x24, 0x65, 0x43, 0x49, 0xca, - 0xc4, 0xa8, 0xa0, 0x48, 0xfe, 0x8e, 0x45, 0xa9, 0x0c, 0x66, 0x30, 0x9c, 0x1d, 0xd4, 0x51, 0x0e, - 0x29, 0x37, 0x48, 0x4a, 0x0f, 0x49, 0xe2, 0x20, 0x2f, 0xc8, 0x10, 0xe7, 0x7f, 0xa6, 0x07, 0xf5, - 0xc8, 0x60, 0xf6, 0x74, 0xef, 0x4e, 0x4a, 0x29, 0xd9, 0x7a, 0x58, 0xa7, 0x66, 0xb2, 0xf7, 0x75, - 0x95, 0x75, 0xde, 0x37, 0xff, 0xf3, 0x1e, 0xdb, 0x56, 0x24, 0x72, 0x9c, 0x91, 0x11, 0x05, 0x91, - 0x09, 0x9c, 0xae, 0xd3, 0xf7, 0xa2, 0x4d, 0x45, 0x67, 0x35, 0x8b, 0x88, 0x0c, 0x7f, 0xc4, 0x76, - 0x14, 0x09, 0x05, 0x97, 0x62, 0x02, 0xf3, 0x02, 0x55, 0x1a, 0xac, 0xda, 0xa1, 0x2d, 0x45, 0xa7, - 0x70, 0xf9, 0xa6, 0x61, 0x7c, 0x9f, 0x6d, 0xea, 0x31, 0x66, 0x42, 0xa6, 0x05, 0x95, 0x79, 0xb0, - 0xd6, 0x75, 0xfa, 0x7e, 0xc4, 0x6a, 0x74, 0x64, 0x09, 0xdf, 0x65, 0x2e, 0x92, 0x28, 0x31, 0x09, - 0xd6, 0xbb, 0x4e, 0x7f, 0x3b, 0xda, 0x40, 0x3a, 0xc7, 0xa4, 0xc5, 0x29, 0x26, 0xc1, 0xc6, 0x12, - 0xbf, 0xc6, 0xa4, 0xde, 0x6e, 0x84, 0x2a, 0x2e, 0xe6, 0x42, 0xc5, 0x19, 0x04, 0x6e, 0xb3, 0x5d, - 0x83, 0x4e, 0xe3, 0x0c, 0x38, 0x67, 0xeb, 0xf6, 0xc0, 0x1d, 0xdb, 0xd8, 0xcc, 0xef, 0x31, 0x5f, - 0x16, 0x58, 0x8a, 0x3c, 0x36, 0xe3, 0xc0, 0xb3, 0x85, 0x57, 0x83, 0xb3, 0xd8, 0x8c, 0xf9, 0x63, - 0xb6, 0xa3, 0xe7, 0xda, 0x40, 0x96, 0x2c, 0xcf, 0xe8, 0xdb, 0x6b, 0x6c, 0xb7, 0xb4, 0x39, 0x66, - 0xef, 0x97, 0xc3, 0x6e, 0x1d, 0x8d, 0x41, 0x4e, 0x72, 0x42, 0x65, 0x96, 0x9e, 0x38, 0x5b, 0x87, - 0x0a, 0x97, 0x7a, 0x6c, 0xe6, 0x77, 0x99, 0x47, 0x39, 0x28, 0x61, 0x64, 0xde, 0x1a, 0xe9, 0xd4, - 0xeb, 0x8f, 0x32, 0xe7, 0x07, 0x6c, 0x17, 0x2a, 0x03, 0x85, 0x8a, 0xa7, 0xa2, 0x54, 0x58, 0x09, - 0x4d, 0x72, 0x02, 0x46, 0x5b, 0x2d, 0x5e, 0x74, 0x7b, 0x59, 0x9e, 0x2b, 0xac, 0x3e, 0x34, 0x15, - 0xdf, 0x63, 0x9e, 0x81, 0x22, 0x43, 0x15, 0x4f, 0xad, 0x21, 0x2f, 0xba, 0x59, 0xf3, 0xfb, 0x8c, - 0x7d, 0xc6, 0x29, 0x88, 0x29, 0xc9, 0x89, 0xb6, 0xa2, 0xbc, 0xc8, 0xaf, 0xc9, 0xdb, 0x1a, 0xf0, - 0x27, 0xec, 0x7f, 0xc8, 0x72, 0xd3, 0xb8, 0xd2, 0x79, 0x2c, 0x41, 0x07, 0x6e, 0x77, 0xad, 0xef, - 0x47, 0xff, 0x59, 0x7e, 0x7a, 0x83, 0xf9, 0x03, 0xb6, 0xd5, 0xdc, 0x5e, 0x8b, 0x8c, 0x12, 0x68, - 0xf5, 0x6d, 0xb6, 0xec, 0x1d, 0x25, 0xd0, 0x7b, 0xce, 0x76, 0xce, 0x0a, 0x92, 0xa0, 0xf5, 0x31, - 0x98, 0x18, 0xa7, 0x9a, 0x3f, 0x64, 0x1d, 0xa8, 0x40, 0x0a, 0x4c, 0xac, 0x00, 0xff, 0x90, 0x2d, - 0x7e, 0xec, 0xbb, 0xaf, 0x2a, 0x90, 0x27, 0xc7, 0x91, 0x5b, 0x57, 0x27, 0xc9, 0xe1, 0xc5, 0xd5, - 0x75, 0xb8, 0xf2, 0xfd, 0x3a, 0x5c, 0xf9, 0xb2, 0x08, 0x9d, 0xab, 0x45, 0xe8, 0x7c, 0x5b, 0x84, - 0xce, 0xcf, 0x45, 0xe8, 0x5c, 0xbc, 0xfc, 0xd7, 0xe7, 0xfd, 0xa2, 0xfd, 0x7e, 0x5a, 0x19, 0xb9, - 0xf6, 0xed, 0x3e, 0xfb, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x78, 0xf4, 0x16, 0x4e, 0x2b, 0x03, 0x00, - 0x00, -} diff -Nru containerd-1.2.6/runtime/v2/runc/options/oci.proto containerd-1.5.9/runtime/v2/runc/options/oci.proto --- containerd-1.2.6/runtime/v2/runc/options/oci.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/options/oci.proto 2022-01-05 17:30:58.000000000 +0000 @@ -25,6 +25,10 @@ string criu_path = 8; // enable systemd cgroups bool systemd_cgroup = 9; + // criu image path + string criu_image_path = 10; + // criu work path + string criu_work_path = 11; } message CheckpointOptions { @@ -42,6 +46,10 @@ repeated string empty_namespaces = 6; // set the cgroups mode, soft, full, strict string cgroups_mode = 7; + // checkpoint image path + string image_path = 8; + // checkpoint work path + string work_path = 9; } message ProcessDetails { diff -Nru containerd-1.2.6/runtime/v2/runc/platform.go containerd-1.5.9/runtime/v2/runc/platform.go --- containerd-1.2.6/runtime/v2/runc/platform.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/platform.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,200 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "io" + "net/url" + "os" + "sync" + "syscall" + + "github.com/containerd/console" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/process" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/fifo" + "github.com/pkg/errors" +) + +var bufPool = sync.Pool{ + New: func() interface{} { + // setting to 4096 to align with PIPE_BUF + // http://man7.org/linux/man-pages/man7/pipe.7.html + buffer := make([]byte, 4096) + return &buffer + }, +} + +// NewPlatform returns a linux platform for use with I/O operations +func NewPlatform() (stdio.Platform, error) { + epoller, err := console.NewEpoller() + if err != nil { + return nil, errors.Wrap(err, "failed to initialize epoller") + } + go epoller.Wait() + return &linuxPlatform{ + epoller: epoller, + }, nil +} + +type linuxPlatform struct { + epoller *console.Epoller +} + +func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { + if p.epoller == nil { + return nil, errors.New("uninitialized epoller") + } + + epollConsole, err := p.epoller.Add(console) + if err != nil { + return nil, err + } + + var cwg sync.WaitGroup + if stdin != "" { + in, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return nil, err + } + cwg.Add(1) + go func() { + cwg.Done() + bp := bufPool.Get().(*[]byte) + defer bufPool.Put(bp) + io.CopyBuffer(epollConsole, in, *bp) + // we need to shutdown epollConsole when pipe broken + epollConsole.Shutdown(p.epoller.CloseConsole) + epollConsole.Close() + }() + } + + uri, err := url.Parse(stdout) + if err != nil { + return nil, errors.Wrap(err, "unable to parse stdout uri") + } + + switch uri.Scheme { + case "binary": + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + cmd := process.NewBinaryCmd(uri, id, ns) + + // In case of unexpected errors during logging binary start, close open pipes + var filesToClose []*os.File + + defer func() { + if retErr != nil { + process.CloseFiles(filesToClose...) + } + }() + + // Create pipe to be used by logging binary for Stdout + outR, outW, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stdout pipes") + } + filesToClose = append(filesToClose, outR) + + // Stderr is created for logging binary but unused when terminal is true + serrR, _, err := os.Pipe() + if err != nil { + return nil, errors.Wrap(err, "failed to create stderr pipes") + } + filesToClose = append(filesToClose, serrR) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + filesToClose = append(filesToClose, r) + + cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) + + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + io.Copy(outW, epollConsole) + outW.Close() + wg.Done() + }() + + if err := cmd.Start(); err != nil { + return nil, errors.Wrap(err, "failed to start logging binary process") + } + + // Close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, errors.Wrap(err, "failed to close write pipe after start") + } + + // Wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, errors.Wrap(err, "failed to read from logging binary") + } + cwg.Wait() + + default: + outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + if err != nil { + return nil, err + } + outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + buf := bufPool.Get().(*[]byte) + defer bufPool.Put(buf) + io.CopyBuffer(outw, epollConsole, *buf) + + outw.Close() + outr.Close() + wg.Done() + }() + cwg.Wait() + } + + return epollConsole, nil +} + +func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { + if p.epoller == nil { + return errors.New("uninitialized epoller") + } + epollConsole, ok := cons.(*console.EpollConsole) + if !ok { + return errors.Errorf("expected EpollConsole, got %#v", cons) + } + return epollConsole.Shutdown(p.epoller.CloseConsole) +} + +func (p *linuxPlatform) Close() error { + return p.epoller.Close() +} diff -Nru containerd-1.2.6/runtime/v2/runc/service.go containerd-1.5.9/runtime/v2/runc/service.go --- containerd-1.2.6/runtime/v2/runc/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/service.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,809 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runc - -import ( - "context" - "encoding/json" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "sync" - "syscall" - "time" - - "github.com/containerd/cgroups" - "github.com/containerd/console" - eventstypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/api/types/task" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/runtime" - rproc "github.com/containerd/containerd/runtime/proc" - "github.com/containerd/containerd/runtime/v1/linux/proc" - "github.com/containerd/containerd/runtime/v2/runc/options" - "github.com/containerd/containerd/runtime/v2/shim" - taskAPI "github.com/containerd/containerd/runtime/v2/task" - runcC "github.com/containerd/go-runc" - "github.com/containerd/typeurl" - ptypes "github.com/gogo/protobuf/types" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sys/unix" -) - -var ( - empty = &ptypes.Empty{} - bufPool = sync.Pool{ - New: func() interface{} { - buffer := make([]byte, 32<<10) - return &buffer - }, - } -) - -var _ = (taskAPI.TaskService)(&service{}) - -// New returns a new shim service that can be used via GRPC -func New(ctx context.Context, id string, publisher events.Publisher) (shim.Shim, error) { - ep, err := newOOMEpoller(publisher) - if err != nil { - return nil, err - } - ctx, cancel := context.WithCancel(ctx) - go ep.run(ctx) - s := &service{ - id: id, - context: ctx, - processes: make(map[string]rproc.Process), - events: make(chan interface{}, 128), - ec: shim.Default.Subscribe(), - ep: ep, - cancel: cancel, - } - go s.processExits() - runcC.Monitor = shim.Default - if err := s.initPlatform(); err != nil { - cancel() - return nil, errors.Wrap(err, "failed to initialized platform behavior") - } - go s.forward(publisher) - return s, nil -} - -// service is the shim implementation of a remote shim over GRPC -type service struct { - mu sync.Mutex - - context context.Context - task rproc.Process - processes map[string]rproc.Process - events chan interface{} - platform rproc.Platform - ec chan runcC.Exit - ep *epoller - - id string - bundle string - cg cgroups.Cgroup - cancel func() -} - -func 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, - } - 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 string) (string, error) { - cmd, err := newCommand(ctx, containerdBinary, containerdAddress) - if err != nil { - return "", err - } - address, err := shim.SocketAddress(ctx, id) - if err != nil { - return "", err - } - socket, err := shim.NewSocket(address) - if err != nil { - return "", err - } - defer socket.Close() - f, err := socket.File() - if err != nil { - return "", err - } - defer f.Close() - - cmd.ExtraFiles = append(cmd.ExtraFiles, f) - - if err := cmd.Start(); err != nil { - return "", err - } - defer func() { - if err != nil { - cmd.Process.Kill() - } - }() - // make sure to wait after start - go cmd.Wait() - if err := shim.WritePidFile("shim.pid", cmd.Process.Pid); err != nil { - return "", err - } - if err := shim.WriteAddress("address", address); err != nil { - return "", err - } - if err := shim.SetScore(cmd.Process.Pid); err != nil { - return "", errors.Wrap(err, "failed to set OOM Score on shim") - } - return address, nil -} - -func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, 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 - } - r := proc.NewRunc(proc.RuncRoot, path, ns, runtime, "", false) - if err := r.Delete(ctx, s.id, &runcC.DeleteOpts{ - Force: true, - }); err != nil { - logrus.WithError(err).Warn("failed to remove runc container") - } - if err := mount.UnmountAll(filepath.Join(path, "rootfs"), 0); err != nil { - logrus.WithError(err).Warn("failed to cleanup rootfs mount") - } - return &taskAPI.DeleteResponse{ - ExitedAt: time.Now(), - ExitStatus: 128 + uint32(unix.SIGKILL), - }, 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 a new initial process and container with the underlying OCI runtime -func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { - s.mu.Lock() - defer s.mu.Unlock() - - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return nil, errors.Wrap(err, "create namespace") - } - - var opts options.Options - if r.Options != nil { - v, err := typeurl.UnmarshalAny(r.Options) - if err != nil { - return nil, err - } - opts = *v.(*options.Options) - } - - 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, - }) - } - config := &proc.CreateConfig{ - ID: r.ID, - Bundle: r.Bundle, - Runtime: opts.BinaryName, - Rootfs: mounts, - Terminal: r.Terminal, - Stdin: r.Stdin, - Stdout: r.Stdout, - Stderr: r.Stderr, - Checkpoint: r.Checkpoint, - ParentCheckpoint: r.ParentCheckpoint, - Options: r.Options, - } - if err := s.writeRuntime(r.Bundle, opts.BinaryName); err != nil { - return nil, err - } - rootfs := filepath.Join(r.Bundle, "rootfs") - defer func() { - if err != nil { - if err2 := mount.UnmountAll(rootfs, 0); err2 != nil { - logrus.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, errors.Wrapf(err, "failed to mount rootfs component %v", m) - } - } - process, err := newInit( - ctx, - r.Bundle, - filepath.Join(r.Bundle, "work"), - ns, - s.platform, - config, - &opts, - ) - if err != nil { - return nil, errdefs.ToGRPC(err) - } - if err := process.Create(ctx, config); err != nil { - return nil, errdefs.ToGRPC(err) - } - // save the main task id and bundle to the shim for additional requests - s.id = r.ID - s.bundle = r.Bundle - pid := process.Pid() - if pid > 0 { - cg, err := cgroups.Load(cgroups.V1, cgroups.PidPath(pid)) - if err != nil { - logrus.WithError(err).Errorf("loading cgroup for %d", pid) - } - s.cg = cg - } - s.task = process - return &taskAPI.CreateTaskResponse{ - Pid: uint32(pid), - }, nil - -} - -// Start a process -func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { - p, err := s.getProcess(r.ExecID) - if err != nil { - return nil, err - } - if err := p.Start(ctx); err != nil { - return nil, err - } - // case for restore - if s.getCgroup() == nil && p.Pid() > 0 { - cg, err := cgroups.Load(cgroups.V1, cgroups.PidPath(p.Pid())) - if err != nil { - logrus.WithError(err).Errorf("loading cgroup for %d", p.Pid()) - } - s.setCgroup(cg) - } - return &taskAPI.StartResponse{ - Pid: uint32(p.Pid()), - }, nil -} - -// Delete the initial process and container -func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { - 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 - } - isTask := r.ExecID == "" - if !isTask { - s.mu.Lock() - delete(s.processes, r.ExecID) - s.mu.Unlock() - } - if isTask && s.platform != nil { - s.platform.Close() - } - return &taskAPI.DeleteResponse{ - ExitStatus: uint32(p.ExitStatus()), - ExitedAt: p.ExitedAt(), - Pid: uint32(p.Pid()), - }, nil -} - -// Exec an additional process inside the container -func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { - 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 { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - process, err := p.(*proc.Init).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 of a process -func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { - 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) { - 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 - case "paused": - status = task.StatusPaused - case "pausing": - status = task.StatusPausing - } - 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) (*ptypes.Empty, error) { - s.mu.Lock() - p := s.task - s.mu.Unlock() - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - if err := p.(*proc.Init).Pause(ctx); err != nil { - return nil, err - } - return empty, nil -} - -// Resume the container -func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { - s.mu.Lock() - p := s.task - s.mu.Unlock() - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - if err := p.(*proc.Init).Resume(ctx); err != nil { - return nil, err - } - return empty, nil -} - -// Kill a process with the provided signal -func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { - 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) { - 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 := &options.ProcessDetails{ - ExecID: p.ID(), - } - a, err := typeurl.MarshalAny(d) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal process %d info", pid) - } - pInfo.Info = a - break - } - } - processes = append(processes, &pInfo) - } - return &taskAPI.PidsResponse{ - Processes: processes, - }, nil -} - -// CloseIO of a process -func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { - 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, errors.Wrap(err, "close stdin") - } - } - return empty, nil -} - -// Checkpoint the container -func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { - s.mu.Lock() - p := s.task - s.mu.Unlock() - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - var opts options.CheckpointOptions - if r.Options != nil { - v, err := typeurl.UnmarshalAny(r.Options) - if err != nil { - return nil, err - } - opts = *v.(*options.CheckpointOptions) - } - if err := p.(*proc.Init).Checkpoint(ctx, &proc.CheckpointConfig{ - Path: r.Path, - Exit: opts.Exit, - AllowOpenTCP: opts.OpenTcp, - AllowExternalUnixSockets: opts.ExternalUnixSockets, - AllowTerminal: opts.Terminal, - FileLocks: opts.FileLocks, - EmptyNamespaces: opts.EmptyNamespaces, - }); err != nil { - return nil, errdefs.ToGRPC(err) - } - return empty, nil -} - -// Connect returns shim information such as the shim's pid -func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { - var pid int - if s.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) (*ptypes.Empty, error) { - s.cancel() - os.Exit(0) - return empty, nil -} - -func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { - cg := s.getCgroup() - if cg == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") - } - stats, err := cg.Stat(cgroups.IgnoreNotExist) - if err != nil { - return nil, err - } - data, err := typeurl.MarshalAny(stats) - if err != nil { - return nil, err - } - return &taskAPI.StatsResponse{ - Stats: data, - }, nil -} - -// Update a running container -func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { - s.mu.Lock() - p := s.task - s.mu.Unlock() - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - if err := p.(*proc.Init).Update(ctx, r.Resources); err != nil { - return nil, errdefs.ToGRPC(err) - } - return empty, nil -} - -// Wait for a process to exit -func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { - 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() { - for e := range s.ec { - s.checkProcesses(e) - } -} - -func (s *service) checkProcesses(e runcC.Exit) { - shouldKillAll, err := shouldKillAllOnExit(s.bundle) - if err != nil { - log.G(s.context).WithError(err).Error("failed to check shouldKillAll") - } - - for _, p := range s.allProcesses() { - if p.Pid() == e.Pid { - if shouldKillAll { - if ip, ok := p.(*proc.Init); ok { - // Ensure all children are killed - if err := ip.KillAll(s.context); err != nil { - logrus.WithError(err).WithField("id", ip.ID()). - Error("failed to kill init's children") - } - } - } - p.SetExited(e.Status) - s.events <- &eventstypes.TaskExit{ - ContainerID: s.id, - ID: p.ID(), - Pid: uint32(e.Pid), - ExitStatus: uint32(e.Status), - ExitedAt: p.ExitedAt(), - } - return - } - } -} - -func shouldKillAllOnExit(bundlePath string) (bool, error) { - var bundleSpec specs.Spec - bundleConfigContents, err := ioutil.ReadFile(filepath.Join(bundlePath, "config.json")) - if err != nil { - return false, err - } - json.Unmarshal(bundleConfigContents, &bundleSpec) - - if bundleSpec.Linux != nil { - for _, ns := range bundleSpec.Linux.Namespaces { - if ns.Type == specs.PIDNamespace { - return false, nil - } - } - } - - return true, nil -} - -func (s *service) allProcesses() (o []rproc.Process) { - s.mu.Lock() - defer s.mu.Unlock() - - o = make([]rproc.Process, 0, len(s.processes)+1) - 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, errors.Wrapf(errdefs.ErrFailedPrecondition, "container must be created") - } - 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 { - ctx, cancel := context.WithTimeout(s.context, 5*time.Second) - err := publisher.Publish(ctx, getTopic(e), e) - cancel() - if err != nil { - logrus.WithError(err).Error("post event") - } - } -} - -func (s *service) getProcess(execID string) (rproc.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 (s *service) getCgroup() cgroups.Cgroup { - s.mu.Lock() - defer s.mu.Unlock() - return s.cg -} - -func (s *service) setCgroup(cg cgroups.Cgroup) { - s.mu.Lock() - s.cg = cg - s.mu.Unlock() - if err := s.ep.add(s.id, cg); err != nil { - logrus.WithError(err).Error("add cg to OOM monitor") - } -} - -func getTopic(e interface{}) string { - switch e.(type) { - case *eventstypes.TaskCreate: - return runtime.TaskCreateEventTopic - case *eventstypes.TaskStart: - return runtime.TaskStartEventTopic - case *eventstypes.TaskOOM: - return runtime.TaskOOMEventTopic - case *eventstypes.TaskExit: - return runtime.TaskExitEventTopic - case *eventstypes.TaskDelete: - return runtime.TaskDeleteEventTopic - case *eventstypes.TaskExecAdded: - return runtime.TaskExecAddedEventTopic - case *eventstypes.TaskExecStarted: - return runtime.TaskExecStartedEventTopic - case *eventstypes.TaskPaused: - return runtime.TaskPausedEventTopic - case *eventstypes.TaskResumed: - return runtime.TaskResumedEventTopic - case *eventstypes.TaskCheckpointed: - return runtime.TaskCheckpointedEventTopic - default: - logrus.Warnf("no topic for type %#v", e) - } - return runtime.TaskUnknownTopic -} - -func newInit(ctx context.Context, path, workDir, namespace string, platform rproc.Platform, r *proc.CreateConfig, options *options.Options) (*proc.Init, error) { - rootfs := filepath.Join(path, "rootfs") - runtime := proc.NewRunc(options.Root, path, namespace, options.BinaryName, options.CriuPath, options.SystemdCgroup) - p := proc.New(r.ID, runtime, rproc.Stdio{ - Stdin: r.Stdin, - Stdout: r.Stdout, - Stderr: r.Stderr, - Terminal: r.Terminal, - }) - p.Bundle = r.Bundle - p.Platform = platform - p.Rootfs = rootfs - p.WorkDir = workDir - p.IoUID = int(options.IoUid) - p.IoGID = int(options.IoGid) - p.NoPivotRoot = options.NoPivotRoot - p.NoNewKeyring = options.NoNewKeyring - return p, nil -} diff -Nru containerd-1.2.6/runtime/v2/runc/service_linux.go containerd-1.5.9/runtime/v2/runc/service_linux.go --- containerd-1.2.6/runtime/v2/runc/service_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/service_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runc - -import ( - "context" - "io" - "sync" - "syscall" - - "github.com/containerd/console" - "github.com/containerd/fifo" - "github.com/pkg/errors" -) - -type linuxPlatform struct { - epoller *console.Epoller -} - -func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) (console.Console, error) { - if p.epoller == nil { - return nil, errors.New("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 - } - cwg.Add(1) - go func() { - cwg.Done() - bp := bufPool.Get().(*[]byte) - defer bufPool.Put(bp) - io.CopyBuffer(epollConsole, in, *bp) - // we need to shutdown epollConsole when pipe broken - epollConsole.Shutdown(p.epoller.CloseConsole) - }() - } - - outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) - if err != nil { - return nil, err - } - outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) - if err != nil { - return nil, err - } - wg.Add(1) - cwg.Add(1) - go func() { - cwg.Done() - p := bufPool.Get().(*[]byte) - defer bufPool.Put(p) - io.CopyBuffer(outw, epollConsole, *p) - 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 errors.New("uninitialized epoller") - } - epollConsole, ok := cons.(*console.EpollConsole) - if !ok { - return errors.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 errors.Wrap(err, "failed to initialize epoller") - } - s.platform = &linuxPlatform{ - epoller: epoller, - } - go epoller.Wait() - return nil -} diff -Nru containerd-1.2.6/runtime/v2/runc/util.go containerd-1.5.9/runtime/v2/runc/util.go --- containerd-1.2.6/runtime/v2/runc/util.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/util.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,85 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "encoding/json" + "io/ioutil" + "path/filepath" + + "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/runtime" + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" +) + +// GetTopic converts an event from an interface type to the specific +// event topic id +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 + case *events.TaskPaused: + return runtime.TaskPausedEventTopic + case *events.TaskResumed: + return runtime.TaskResumedEventTopic + case *events.TaskCheckpointed: + return runtime.TaskCheckpointedEventTopic + default: + logrus.Warnf("no topic for type %#v", e) + } + return runtime.TaskUnknownTopic +} + +// ShouldKillAllOnExit reads the bundle's OCI spec and returns true if +// there is an error reading the spec or if the container has a private PID namespace +func ShouldKillAllOnExit(ctx context.Context, bundlePath string) bool { + var bundleSpec specs.Spec + bundleConfigContents, err := ioutil.ReadFile(filepath.Join(bundlePath, "config.json")) + if err != nil { + log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to read config.json") + return true + } + if err := json.Unmarshal(bundleConfigContents, &bundleSpec); err != nil { + log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to unmarshal bundle json") + return true + } + if bundleSpec.Linux != nil { + for _, ns := range bundleSpec.Linux.Namespaces { + if ns.Type == specs.PIDNamespace && ns.Path == "" { + return false + } + } + } + return true +} diff -Nru containerd-1.2.6/runtime/v2/runc/v1/service.go containerd-1.5.9/runtime/v2/runc/v1/service.go --- containerd-1.2.6/runtime/v2/runc/v1/service.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/v1/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,715 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "context" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sync" + "syscall" + "time" + + "github.com/containerd/cgroups" + eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/api/types/task" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/oom" + oomv1 "github.com/containerd/containerd/pkg/oom/v1" + "github.com/containerd/containerd/pkg/process" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/containerd/runtime/v2/runc" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/runtime/v2/shim" + taskAPI "github.com/containerd/containerd/runtime/v2/task" + "github.com/containerd/containerd/sys/reaper" + runcC "github.com/containerd/go-runc" + "github.com/containerd/typeurl" + "github.com/gogo/protobuf/proto" + ptypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +var ( + _ = (taskAPI.TaskService)(&service{}) + empty = &ptypes.Empty{} +) + +// New returns a new shim service that can be used via GRPC +func New(ctx context.Context, id string, publisher shim.Publisher, shutdown func()) (shim.Shim, error) { + ep, err := oomv1.New(publisher) + if err != nil { + return nil, err + } + go ep.Run(ctx) + s := &service{ + id: id, + context: ctx, + events: make(chan interface{}, 128), + ec: reaper.Default.Subscribe(), + ep: ep, + cancel: shutdown, + } + go s.processExits() + runcC.Monitor = reaper.Default + if err := s.initPlatform(); err != nil { + shutdown() + return nil, errors.Wrap(err, "failed to initialized platform behavior") + } + go s.forward(ctx, publisher) + return s, nil +} + +// service is the shim implementation of a remote shim over GRPC +type service struct { + mu sync.Mutex + eventSendMu sync.Mutex + + context context.Context + events chan interface{} + platform stdio.Platform + ec chan runcC.Exit + ep oom.Watcher + + id string + container *runc.Container + + cancel func() +} + +func newCommand(ctx context.Context, id, containerdBinary, containerdAddress, containerdTTRPCAddress string) (*exec.Cmd, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + self, err := os.Executable() + if err != nil { + return nil, err + } + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + args := []string{ + "-namespace", ns, + "-id", id, + "-address", containerdAddress, + } + cmd := exec.Command(self, args...) + cmd.Dir = cwd + cmd.Env = append(os.Environ(), "GOMAXPROCS=2") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } + return cmd, nil +} + +func (s *service) StartShim(ctx context.Context, opts shim.StartOpts) (_ string, retErr error) { + cmd, err := newCommand(ctx, opts.ID, opts.ContainerdBinary, opts.Address, opts.TTRPCAddress) + if err != nil { + return "", err + } + address, err := shim.SocketAddress(ctx, opts.Address, opts.ID) + if err != nil { + return "", err + } + socket, err := shim.NewSocket(address) + if err != nil { + if !shim.SocketEaddrinuse(err) { + return "", err + } + if err := shim.RemoveSocket(address); err != nil { + return "", errors.Wrap(err, "remove already used socket") + } + if socket, err = shim.NewSocket(address); err != nil { + return "", err + } + } + defer func() { + if retErr != nil { + socket.Close() + _ = shim.RemoveSocket(address) + } + }() + // make sure that reexec shim-v2 binary use the value if need + if err := shim.WriteAddress("address", address); err != nil { + return "", err + } + + f, err := socket.File() + if err != nil { + return "", err + } + + cmd.ExtraFiles = append(cmd.ExtraFiles, f) + + if err := cmd.Start(); err != nil { + f.Close() + return "", err + } + defer func() { + if retErr != nil { + cmd.Process.Kill() + } + }() + // make sure to wait after start + go cmd.Wait() + if err := shim.WritePidFile("shim.pid", cmd.Process.Pid); err != nil { + return "", err + } + if data, err := ioutil.ReadAll(os.Stdin); err == nil { + if len(data) > 0 { + var any ptypes.Any + if err := proto.Unmarshal(data, &any); err != nil { + return "", err + } + v, err := typeurl.UnmarshalAny(&any) + if err != nil { + return "", err + } + if opts, ok := v.(*options.Options); ok { + if opts.ShimCgroup != "" { + cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(opts.ShimCgroup)) + if err != nil { + return "", errors.Wrapf(err, "failed to load cgroup %s", opts.ShimCgroup) + } + if err := cg.Add(cgroups.Process{ + Pid: cmd.Process.Pid, + }); err != nil { + return "", errors.Wrapf(err, "failed to join cgroup %s", opts.ShimCgroup) + } + } + } + } + } + if err := shim.AdjustOOMScore(cmd.Process.Pid); err != nil { + return "", errors.Wrap(err, "failed to adjust OOM score for shim") + } + return address, nil +} + +func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { + if address, err := shim.ReadAddress("address"); err == nil { + if err = shim.RemoveSocket(address); err != nil { + return nil, err + } + } + + path, err := os.Getwd() + if err != nil { + return nil, err + } + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + runtime, err := runc.ReadRuntime(path) + if err != nil { + return nil, err + } + opts, err := runc.ReadOptions(path) + if err != nil { + return nil, err + } + root := process.RuncRoot + if opts != nil && opts.Root != "" { + root = opts.Root + } + + r := process.NewRunc(root, path, ns, runtime, "", false) + if err := r.Delete(ctx, s.id, &runcC.DeleteOpts{ + Force: true, + }); err != nil { + logrus.WithError(err).Warn("failed to remove runc container") + } + if err := mount.UnmountAll(filepath.Join(path, "rootfs"), 0); err != nil { + logrus.WithError(err).Warn("failed to cleanup rootfs mount") + } + return &taskAPI.DeleteResponse{ + ExitedAt: time.Now(), + ExitStatus: 128 + uint32(unix.SIGKILL), + }, nil +} + +// Create a new initial process and container with the underlying OCI runtime +func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { + s.mu.Lock() + defer s.mu.Unlock() + + container, err := runc.NewContainer(ctx, s.platform, r) + if err != nil { + return nil, err + } + + s.container = container + + s.send(&eventstypes.TaskCreate{ + ContainerID: r.ID, + Bundle: r.Bundle, + Rootfs: r.Rootfs, + IO: &eventstypes.TaskIO{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }, + Checkpoint: r.Checkpoint, + Pid: uint32(container.Pid()), + }) + + return &taskAPI.CreateTaskResponse{ + Pid: uint32(container.Pid()), + }, nil +} + +// Start a process +func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + + // hold the send lock so that the start events are sent before any exit events in the error case + s.eventSendMu.Lock() + p, err := container.Start(ctx, r) + if err != nil { + s.eventSendMu.Unlock() + return nil, errdefs.ToGRPC(err) + } + switch r.ExecID { + case "": + if cg, ok := container.Cgroup().(cgroups.Cgroup); ok { + if err := s.ep.Add(container.ID, cg); err != nil { + logrus.WithError(err).Error("add cg to OOM monitor") + } + } else { + logrus.WithError(errdefs.ErrNotImplemented).Error("add cg to OOM monitor") + } + s.send(&eventstypes.TaskStart{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + }) + default: + s.send(&eventstypes.TaskExecStarted{ + ContainerID: container.ID, + ExecID: r.ExecID, + Pid: uint32(p.Pid()), + }) + } + s.eventSendMu.Unlock() + return &taskAPI.StartResponse{ + Pid: uint32(p.Pid()), + }, nil +} + +// Delete the initial process and container +func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + p, err := container.Delete(ctx, r) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + // if we deleted our init task, close the platform and send the task delete event + if r.ExecID == "" { + if s.platform != nil { + s.platform.Close() + } + s.send(&eventstypes.TaskDelete{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }) + } + return &taskAPI.DeleteResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + Pid: uint32(p.Pid()), + }, nil +} + +// Exec an additional process inside the container +func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + ok, cancel := container.ReserveProcess(r.ExecID) + if !ok { + return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID) + } + process, err := container.Exec(ctx, r) + if err != nil { + cancel() + return nil, errdefs.ToGRPC(err) + } + + s.send(&eventstypes.TaskExecAdded{ + ContainerID: s.container.ID, + ExecID: process.ID(), + }) + return empty, nil +} + +// ResizePty of a process +func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.ResizePty(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// State returns runtime state information for a process +func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + p, err := s.getProcess(r.ExecID) + if err != nil { + return nil, err + } + st, err := p.Status(ctx) + if err != nil { + return nil, err + } + status := task.StatusUnknown + switch st { + case "created": + status = task.StatusCreated + case "running": + status = task.StatusRunning + case "stopped": + status = task.StatusStopped + case "paused": + status = task.StatusPaused + case "pausing": + status = task.StatusPausing + } + sio := p.Stdio() + return &taskAPI.StateResponse{ + ID: p.ID(), + Bundle: s.container.Bundle, + Pid: uint32(p.Pid()), + Status: status, + Stdin: sio.Stdin, + Stdout: sio.Stdout, + Stderr: sio.Stderr, + Terminal: sio.Terminal, + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }, nil +} + +// Pause the container +func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.Pause(ctx); err != nil { + return nil, errdefs.ToGRPC(err) + } + s.send(&eventstypes.TaskPaused{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Resume the container +func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.Resume(ctx); err != nil { + return nil, errdefs.ToGRPC(err) + } + s.send(&eventstypes.TaskResumed{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Kill a process with the provided signal +func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.Kill(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Pids returns all pids inside the container +func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + pids, err := s.getContainerPids(ctx, r.ID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + var processes []*task.ProcessInfo + for _, pid := range pids { + pInfo := task.ProcessInfo{ + Pid: pid, + } + for _, p := range container.ExecdProcesses() { + if p.Pid() == int(pid) { + d := &options.ProcessDetails{ + ExecID: p.ID(), + } + a, err := typeurl.MarshalAny(d) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal process %d info", pid) + } + pInfo.Info = a + break + } + } + processes = append(processes, &pInfo) + } + return &taskAPI.PidsResponse{ + Processes: processes, + }, nil +} + +// CloseIO of a process +func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.CloseIO(ctx, r); err != nil { + return nil, err + } + return empty, nil +} + +// Checkpoint the container +func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.Checkpoint(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Update a running container +func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + if err := container.Update(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Wait for a process to exit +func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + p, err := container.Process(r.ExecID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + p.Wait() + + return &taskAPI.WaitResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }, nil +} + +// Connect returns shim information such as the shim's pid +func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + var pid int + if s.container != nil { + pid = s.container.Pid() + } + return &taskAPI.ConnectResponse{ + ShimPid: uint32(os.Getpid()), + TaskPid: uint32(pid), + }, nil +} + +func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { + // please make sure that temporary resource has been cleanup + // before shutdown service. + s.cancel() + close(s.events) + return empty, nil +} + +func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + cgx := s.container.Cgroup() + if cgx == nil { + return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") + } + cg, ok := cgx.(cgroups.Cgroup) + if !ok { + return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "cgroup v2 not implemented for Stats") + } + if cg == nil { + return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") + } + stats, err := cg.Stat(cgroups.IgnoreNotExist) + if err != nil { + return nil, err + } + data, err := typeurl.MarshalAny(stats) + if err != nil { + return nil, err + } + return &taskAPI.StatsResponse{ + Stats: data, + }, nil +} + +func (s *service) processExits() { + for e := range s.ec { + s.checkProcesses(e) + } +} + +func (s *service) send(evt interface{}) { + s.events <- evt +} + +func (s *service) sendL(evt interface{}) { + s.eventSendMu.Lock() + s.events <- evt + s.eventSendMu.Unlock() +} + +func (s *service) checkProcesses(e runcC.Exit) { + container, err := s.getContainer() + if err != nil { + return + } + + for _, p := range container.All() { + if p.Pid() == e.Pid { + if runc.ShouldKillAllOnExit(s.context, container.Bundle) { + if ip, ok := p.(*process.Init); ok { + // Ensure all children are killed + if err := ip.KillAll(s.context); err != nil { + logrus.WithError(err).WithField("id", ip.ID()). + Error("failed to kill init's children") + } + } + } + p.SetExited(e.Status) + s.sendL(&eventstypes.TaskExit{ + ContainerID: container.ID, + ID: p.ID(), + Pid: uint32(e.Pid), + ExitStatus: uint32(e.Status), + ExitedAt: p.ExitedAt(), + }) + return + } + } +} + +func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { + p, err := s.container.Process("") + if err != nil { + return nil, errdefs.ToGRPC(err) + } + ps, err := p.(*process.Init).Runtime().Ps(ctx, id) + if err != nil { + return nil, err + } + pids := make([]uint32, 0, len(ps)) + for _, pid := range ps { + pids = append(pids, uint32(pid)) + } + return pids, nil +} + +func (s *service) forward(ctx context.Context, publisher shim.Publisher) { + ns, _ := namespaces.Namespace(ctx) + ctx = namespaces.WithNamespace(context.Background(), ns) + for e := range s.events { + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + err := publisher.Publish(ctx, runc.GetTopic(e), e) + cancel() + if err != nil { + logrus.WithError(err).Error("post event") + } + } + publisher.Close() +} + +func (s *service) getContainer() (*runc.Container, error) { + s.mu.Lock() + container := s.container + s.mu.Unlock() + if container == nil { + return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "container not created") + } + return container, nil +} + +func (s *service) getProcess(execID string) (process.Process, error) { + container, err := s.getContainer() + if err != nil { + return nil, err + } + p, err := container.Process(execID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + return p, nil +} + +// initialize a single epoll fd to manage our consoles. `initPlatform` should +// only be called once. +func (s *service) initPlatform() error { + if s.platform != nil { + return nil + } + p, err := runc.NewPlatform() + if err != nil { + return err + } + s.platform = p + return nil +} diff -Nru containerd-1.2.6/runtime/v2/runc/v2/service.go containerd-1.5.9/runtime/v2/runc/v2/service.go --- containerd-1.2.6/runtime/v2/runc/v2/service.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runc/v2/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,834 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + "encoding/json" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sync" + "syscall" + "time" + + "github.com/containerd/cgroups" + cgroupsv2 "github.com/containerd/cgroups/v2" + eventstypes "github.com/containerd/containerd/api/events" + "github.com/containerd/containerd/api/types/task" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/oom" + oomv1 "github.com/containerd/containerd/pkg/oom/v1" + oomv2 "github.com/containerd/containerd/pkg/oom/v2" + "github.com/containerd/containerd/pkg/process" + "github.com/containerd/containerd/pkg/stdio" + "github.com/containerd/containerd/pkg/userns" + "github.com/containerd/containerd/runtime/v2/runc" + "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/runtime/v2/shim" + taskAPI "github.com/containerd/containerd/runtime/v2/task" + "github.com/containerd/containerd/sys/reaper" + runcC "github.com/containerd/go-runc" + "github.com/containerd/typeurl" + "github.com/gogo/protobuf/proto" + ptypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +var ( + _ = (taskAPI.TaskService)(&service{}) + empty = &ptypes.Empty{} +) + +// group labels specifies how the shim groups services. +// currently supports a runc.v2 specific .group label and the +// standard k8s pod label. Order matters in this list +var groupLabels = []string{ + "io.containerd.runc.v2.group", + "io.kubernetes.cri.sandbox-id", +} + +type spec struct { + Annotations map[string]string `json:"annotations,omitempty"` +} + +// New returns a new shim service that can be used via GRPC +func New(ctx context.Context, id string, publisher shim.Publisher, shutdown func()) (shim.Shim, error) { + var ( + ep oom.Watcher + err error + ) + if cgroups.Mode() == cgroups.Unified { + ep, err = oomv2.New(publisher) + } else { + ep, err = oomv1.New(publisher) + } + if err != nil { + return nil, err + } + go ep.Run(ctx) + s := &service{ + id: id, + context: ctx, + events: make(chan interface{}, 128), + ec: reaper.Default.Subscribe(), + ep: ep, + cancel: shutdown, + containers: make(map[string]*runc.Container), + } + go s.processExits() + runcC.Monitor = reaper.Default + if err := s.initPlatform(); err != nil { + shutdown() + return nil, errors.Wrap(err, "failed to initialized platform behavior") + } + go s.forward(ctx, publisher) + + if address, err := shim.ReadAddress("address"); err == nil { + s.shimAddress = address + } + return s, nil +} + +// service is the shim implementation of a remote shim over GRPC +type service struct { + mu sync.Mutex + eventSendMu sync.Mutex + + context context.Context + events chan interface{} + platform stdio.Platform + ec chan runcC.Exit + ep oom.Watcher + + // id only used in cleanup case + id string + + containers map[string]*runc.Container + + shimAddress string + cancel func() +} + +func newCommand(ctx context.Context, id, containerdBinary, containerdAddress, containerdTTRPCAddress string) (*exec.Cmd, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + self, err := os.Executable() + if err != nil { + return nil, err + } + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + args := []string{ + "-namespace", ns, + "-id", id, + "-address", containerdAddress, + } + cmd := exec.Command(self, args...) + cmd.Dir = cwd + cmd.Env = append(os.Environ(), "GOMAXPROCS=4") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } + return cmd, nil +} + +func readSpec() (*spec, error) { + f, err := os.Open("config.json") + if err != nil { + return nil, err + } + defer f.Close() + var s spec + if err := json.NewDecoder(f).Decode(&s); err != nil { + return nil, err + } + return &s, nil +} + +func (s *service) StartShim(ctx context.Context, opts shim.StartOpts) (_ string, retErr error) { + cmd, err := newCommand(ctx, opts.ID, opts.ContainerdBinary, opts.Address, opts.TTRPCAddress) + if err != nil { + return "", err + } + grouping := opts.ID + spec, err := readSpec() + if err != nil { + return "", err + } + for _, group := range groupLabels { + if groupID, ok := spec.Annotations[group]; ok { + grouping = groupID + break + } + } + address, err := shim.SocketAddress(ctx, opts.Address, grouping) + 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 "", errors.Wrap(err, "create new shim socket") + } + if shim.CanConnect(address) { + if err := shim.WriteAddress("address", address); err != nil { + return "", errors.Wrap(err, "write existing socket for shim") + } + return address, nil + } + if err := shim.RemoveSocket(address); err != nil { + return "", errors.Wrap(err, "remove pre-existing socket") + } + if socket, err = shim.NewSocket(address); err != nil { + return "", errors.Wrap(err, "try create new shim socket 2x") + } + } + defer func() { + if retErr != nil { + socket.Close() + _ = shim.RemoveSocket(address) + } + }() + + // make sure that reexec shim-v2 binary use the value if need + if err := shim.WriteAddress("address", address); err != nil { + return "", err + } + + f, err := socket.File() + if err != nil { + return "", err + } + + cmd.ExtraFiles = append(cmd.ExtraFiles, f) + + if err := cmd.Start(); err != nil { + f.Close() + return "", err + } + defer func() { + if retErr != nil { + cmd.Process.Kill() + } + }() + // make sure to wait after start + go cmd.Wait() + if data, err := ioutil.ReadAll(os.Stdin); err == nil { + if len(data) > 0 { + var any ptypes.Any + if err := proto.Unmarshal(data, &any); err != nil { + return "", err + } + v, err := typeurl.UnmarshalAny(&any) + if err != nil { + return "", err + } + if opts, ok := v.(*options.Options); ok { + if opts.ShimCgroup != "" { + if cgroups.Mode() == cgroups.Unified { + if err := cgroupsv2.VerifyGroupPath(opts.ShimCgroup); err != nil { + return "", errors.Wrapf(err, "failed to verify cgroup path %q", opts.ShimCgroup) + } + cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", opts.ShimCgroup) + if err != nil { + return "", errors.Wrapf(err, "failed to load cgroup %s", opts.ShimCgroup) + } + if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { + return "", errors.Wrapf(err, "failed to join cgroup %s", opts.ShimCgroup) + } + } else { + cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(opts.ShimCgroup)) + if err != nil { + return "", errors.Wrapf(err, "failed to load cgroup %s", opts.ShimCgroup) + } + if err := cg.Add(cgroups.Process{ + Pid: cmd.Process.Pid, + }); err != nil { + return "", errors.Wrapf(err, "failed to join cgroup %s", opts.ShimCgroup) + } + } + } + } + } + } + if err := shim.AdjustOOMScore(cmd.Process.Pid); err != nil { + return "", errors.Wrap(err, "failed to adjust OOM score for shim") + } + return address, nil +} + +func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + + path := filepath.Join(filepath.Dir(cwd), s.id) + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + runtime, err := runc.ReadRuntime(path) + if err != nil { + return nil, err + } + opts, err := runc.ReadOptions(path) + if err != nil { + return nil, err + } + root := process.RuncRoot + if opts != nil && opts.Root != "" { + root = opts.Root + } + + r := process.NewRunc(root, path, ns, runtime, "", false) + if err := r.Delete(ctx, s.id, &runcC.DeleteOpts{ + Force: true, + }); err != nil { + logrus.WithError(err).Warn("failed to remove runc container") + } + if err := mount.UnmountAll(filepath.Join(path, "rootfs"), 0); err != nil { + logrus.WithError(err).Warn("failed to cleanup rootfs mount") + } + return &taskAPI.DeleteResponse{ + ExitedAt: time.Now(), + ExitStatus: 128 + uint32(unix.SIGKILL), + }, nil +} + +// Create a new initial process and container with the underlying OCI runtime +func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { + s.mu.Lock() + defer s.mu.Unlock() + + container, err := runc.NewContainer(ctx, s.platform, r) + if err != nil { + return nil, err + } + + s.containers[r.ID] = container + + s.send(&eventstypes.TaskCreate{ + ContainerID: r.ID, + Bundle: r.Bundle, + Rootfs: r.Rootfs, + IO: &eventstypes.TaskIO{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }, + Checkpoint: r.Checkpoint, + Pid: uint32(container.Pid()), + }) + + return &taskAPI.CreateTaskResponse{ + Pid: uint32(container.Pid()), + }, nil +} + +// Start a process +func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + + // hold the send lock so that the start events are sent before any exit events in the error case + s.eventSendMu.Lock() + p, err := container.Start(ctx, r) + if err != nil { + s.eventSendMu.Unlock() + return nil, errdefs.ToGRPC(err) + } + + switch r.ExecID { + case "": + switch cg := container.Cgroup().(type) { + case cgroups.Cgroup: + if err := s.ep.Add(container.ID, cg); err != nil { + logrus.WithError(err).Error("add cg to OOM monitor") + } + case *cgroupsv2.Manager: + allControllers, err := cg.RootControllers() + if err != nil { + logrus.WithError(err).Error("failed to get root controllers") + } else { + if err := cg.ToggleControllers(allControllers, cgroupsv2.Enable); err != nil { + if userns.RunningInUserNS() { + logrus.WithError(err).Debugf("failed to enable controllers (%v)", allControllers) + } else { + logrus.WithError(err).Errorf("failed to enable controllers (%v)", allControllers) + } + } + } + if err := s.ep.Add(container.ID, cg); err != nil { + logrus.WithError(err).Error("add cg to OOM monitor") + } + } + + s.send(&eventstypes.TaskStart{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + }) + default: + s.send(&eventstypes.TaskExecStarted{ + ContainerID: container.ID, + ExecID: r.ExecID, + Pid: uint32(p.Pid()), + }) + } + s.eventSendMu.Unlock() + return &taskAPI.StartResponse{ + Pid: uint32(p.Pid()), + }, nil +} + +// Delete the initial process and container +func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Delete(ctx, r) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + // if we deleted an init task, send the task delete event + if r.ExecID == "" { + s.mu.Lock() + delete(s.containers, r.ID) + s.mu.Unlock() + s.send(&eventstypes.TaskDelete{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }) + } + return &taskAPI.DeleteResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + Pid: uint32(p.Pid()), + }, nil +} + +// Exec an additional process inside the container +func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + ok, cancel := container.ReserveProcess(r.ExecID) + if !ok { + return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID) + } + process, err := container.Exec(ctx, r) + if err != nil { + cancel() + return nil, errdefs.ToGRPC(err) + } + + s.send(&eventstypes.TaskExecAdded{ + ContainerID: container.ID, + ExecID: process.ID(), + }) + return empty, nil +} + +// ResizePty of a process +func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.ResizePty(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// State returns runtime state information for a process +func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Process(r.ExecID) + if err != nil { + return nil, errdefs.ToGRPC(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 + case "paused": + status = task.StatusPaused + case "pausing": + status = task.StatusPausing + } + sio := p.Stdio() + return &taskAPI.StateResponse{ + ID: p.ID(), + Bundle: container.Bundle, + Pid: uint32(p.Pid()), + Status: status, + Stdin: sio.Stdin, + Stdout: sio.Stdout, + Stderr: sio.Stderr, + Terminal: sio.Terminal, + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }, nil +} + +// Pause the container +func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Pause(ctx); err != nil { + return nil, errdefs.ToGRPC(err) + } + s.send(&eventstypes.TaskPaused{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Resume the container +func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Resume(ctx); err != nil { + return nil, errdefs.ToGRPC(err) + } + s.send(&eventstypes.TaskResumed{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Kill a process with the provided signal +func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Kill(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Pids returns all pids inside the container +func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + pids, err := s.getContainerPids(ctx, r.ID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + var processes []*task.ProcessInfo + for _, pid := range pids { + pInfo := task.ProcessInfo{ + Pid: pid, + } + for _, p := range container.ExecdProcesses() { + if p.Pid() == int(pid) { + d := &options.ProcessDetails{ + ExecID: p.ID(), + } + a, err := typeurl.MarshalAny(d) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal process %d info", pid) + } + pInfo.Info = a + break + } + } + processes = append(processes, &pInfo) + } + return &taskAPI.PidsResponse{ + Processes: processes, + }, nil +} + +// CloseIO of a process +func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.CloseIO(ctx, r); err != nil { + return nil, err + } + return empty, nil +} + +// Checkpoint the container +func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Checkpoint(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Update a running container +func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Update(ctx, r); err != nil { + return nil, errdefs.ToGRPC(err) + } + return empty, nil +} + +// Wait for a process to exit +func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Process(r.ExecID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + p.Wait() + + return &taskAPI.WaitResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: p.ExitedAt(), + }, nil +} + +// Connect returns shim information such as the shim's pid +func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + var pid int + if container, err := s.getContainer(r.ID); err == nil { + pid = container.Pid() + } + return &taskAPI.ConnectResponse{ + ShimPid: uint32(os.Getpid()), + TaskPid: uint32(pid), + }, nil +} + +func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + + // return out if the shim is still servicing containers + if len(s.containers) > 0 { + return empty, nil + } + + if s.platform != nil { + s.platform.Close() + } + + if s.shimAddress != "" { + _ = shim.RemoveSocket(s.shimAddress) + } + + // please make sure that temporary resource has been cleanup + // before shutdown service. + s.cancel() + close(s.events) + return empty, nil +} + +func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + cgx := container.Cgroup() + if cgx == nil { + return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") + } + var statsx interface{} + switch cg := cgx.(type) { + case cgroups.Cgroup: + stats, err := cg.Stat(cgroups.IgnoreNotExist) + if err != nil { + return nil, err + } + statsx = stats + case *cgroupsv2.Manager: + stats, err := cg.Stat() + if err != nil { + return nil, err + } + statsx = stats + default: + return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "unsupported cgroup type %T", cg) + } + data, err := typeurl.MarshalAny(statsx) + if err != nil { + return nil, err + } + return &taskAPI.StatsResponse{ + Stats: data, + }, nil +} + +func (s *service) processExits() { + for e := range s.ec { + s.checkProcesses(e) + } +} + +func (s *service) send(evt interface{}) { + s.events <- evt +} + +func (s *service) sendL(evt interface{}) { + s.eventSendMu.Lock() + s.events <- evt + s.eventSendMu.Unlock() +} + +func (s *service) checkProcesses(e runcC.Exit) { + s.mu.Lock() + defer s.mu.Unlock() + + for _, container := range s.containers { + if !container.HasPid(e.Pid) { + continue + } + + for _, p := range container.All() { + if p.Pid() != e.Pid { + continue + } + + if ip, ok := p.(*process.Init); ok { + // Ensure all children are killed + if runc.ShouldKillAllOnExit(s.context, container.Bundle) { + if err := ip.KillAll(s.context); err != nil { + logrus.WithError(err).WithField("id", ip.ID()). + Error("failed to kill init's children") + } + } + } + + p.SetExited(e.Status) + s.sendL(&eventstypes.TaskExit{ + ContainerID: container.ID, + ID: p.ID(), + Pid: uint32(e.Pid), + ExitStatus: uint32(e.Status), + ExitedAt: p.ExitedAt(), + }) + return + } + return + } +} + +func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { + container, err := s.getContainer(id) + if err != nil { + return nil, err + } + p, err := container.Process("") + if err != nil { + return nil, errdefs.ToGRPC(err) + } + ps, err := p.(*process.Init).Runtime().Ps(ctx, id) + if err != nil { + return nil, err + } + pids := make([]uint32, 0, len(ps)) + for _, pid := range ps { + pids = append(pids, uint32(pid)) + } + return pids, nil +} + +func (s *service) forward(ctx context.Context, publisher shim.Publisher) { + ns, _ := namespaces.Namespace(ctx) + ctx = namespaces.WithNamespace(context.Background(), ns) + for e := range s.events { + err := publisher.Publish(ctx, runc.GetTopic(e), e) + if err != nil { + logrus.WithError(err).Error("post event") + } + } + publisher.Close() +} + +func (s *service) getContainer(id string) (*runc.Container, error) { + s.mu.Lock() + container := s.containers[id] + s.mu.Unlock() + if container == nil { + return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "container not created") + } + return container, nil +} + +// initialize a single epoll fd to manage our consoles. `initPlatform` should +// only be called once. +func (s *service) initPlatform() error { + if s.platform != nil { + return nil + } + p, err := runc.NewPlatform() + if err != nil { + return err + } + s.platform = p + return nil +} diff -Nru containerd-1.2.6/runtime/v2/runhcs/io.go containerd-1.5.9/runtime/v2/runhcs/io.go --- containerd-1.2.6/runtime/v2/runhcs/io.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/io.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runhcs - -import ( - "context" - "io" - "net" - "sync" - "time" - - "github.com/Microsoft/go-winio" - "github.com/containerd/containerd/log" - runc "github.com/containerd/go-runc" - "github.com/pkg/errors" - "golang.org/x/sync/errgroup" -) - -type pipeSet struct { - stdin net.Conn - stdout net.Conn - stderr net.Conn -} - -// newPipeSet connects to the provided pipe addresses -func newPipeSet(ctx context.Context, stdin, stdout, stderr string, terminal bool) (*pipeSet, error) { - var ( - err error - set = &pipeSet{} - ) - - defer func() { - if err != nil { - set.Close() - } - }() - - g, _ := errgroup.WithContext(ctx) - - dialfn := func(name string, conn *net.Conn) error { - if name == "" { - return nil - } - dialTimeout := 3 * time.Second - c, err := winio.DialPipe(name, &dialTimeout) - if err != nil { - return errors.Wrapf(err, "failed to connect to %s", name) - } - *conn = c - return nil - } - - g.Go(func() error { - return dialfn(stdin, &set.stdin) - }) - g.Go(func() error { - return dialfn(stdout, &set.stdout) - }) - g.Go(func() error { - return dialfn(stderr, &set.stderr) - }) - - err = g.Wait() - if err != nil { - return nil, err - } - return set, nil -} - -// Close terminates all successfully dialed IO connections -func (p *pipeSet) Close() { - for _, cn := range []net.Conn{p.stdin, p.stdout, p.stderr} { - if cn != nil { - cn.Close() - } - } -} - -type pipeRelay struct { - ctx context.Context - - ps *pipeSet - io runc.IO - - wg sync.WaitGroup - once sync.Once -} - -func newPipeRelay(ctx context.Context, ps *pipeSet, downstream runc.IO) *pipeRelay { - pr := &pipeRelay{ - ctx: ctx, - ps: ps, - io: downstream, - } - if ps.stdin != nil { - go func() { - if _, err := io.Copy(downstream.Stdin(), ps.stdin); err != nil { - if err != winio.ErrFileClosed { - log.G(ctx).WithError(err).Error("error copying stdin to pipe") - } - } - }() - } - if ps.stdout != nil { - pr.wg.Add(1) - go func() { - if _, err := io.Copy(ps.stdout, downstream.Stdout()); err != nil { - log.G(ctx).WithError(err).Error("error copying stdout from pipe") - } - pr.wg.Done() - }() - } - if ps.stderr != nil { - pr.wg.Add(1) - go func() { - if _, err := io.Copy(ps.stderr, downstream.Stderr()); err != nil { - log.G(pr.ctx).WithError(err).Error("error copying stderr from pipe") - } - pr.wg.Done() - }() - } - return pr -} - -func (pr *pipeRelay) wait() { - pr.wg.Wait() -} - -// closeIO closes stdin to unblock an waiters -func (pr *pipeRelay) closeIO() { - if pr.ps.stdin != nil { - pr.ps.Close() - pr.io.Stdin().Close() - } -} - -// close closes all open pipes -func (pr *pipeRelay) close() { - pr.once.Do(func() { - pr.io.Close() - pr.ps.Close() - }) -} diff -Nru containerd-1.2.6/runtime/v2/runhcs/options/doc.go containerd-1.5.9/runtime/v2/runhcs/options/doc.go --- containerd-1.2.6/runtime/v2/runhcs/options/doc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/options/doc.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package options diff -Nru containerd-1.2.6/runtime/v2/runhcs/options/next.pb.txt containerd-1.5.9/runtime/v2/runhcs/options/next.pb.txt --- containerd-1.2.6/runtime/v2/runhcs/options/next.pb.txt 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/options/next.pb.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -file { - name: "github.com/containerd/containerd/runtime/v2/runhcs/options/runhcs.proto" - package: "containerd.runhcs.v1" - dependency: "gogoproto/gogo.proto" - message_type { - name: "Options" - field { - name: "debug" - number: 1 - label: LABEL_OPTIONAL - type: TYPE_BOOL - json_name: "debug" - } - field { - name: "debug_type" - number: 2 - label: LABEL_OPTIONAL - type: TYPE_ENUM - type_name: ".containerd.runhcs.v1.Options.DebugType" - json_name: "debugType" - } - field { - name: "registry_root" - number: 3 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "registryRoot" - } - field { - name: "sandbox_image" - number: 4 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "sandboxImage" - } - field { - name: "sandbox_platform" - number: 5 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "sandboxPlatform" - } - field { - name: "sandbox_isolation" - number: 6 - label: LABEL_OPTIONAL - type: TYPE_ENUM - type_name: ".containerd.runhcs.v1.Options.SandboxIsolation" - json_name: "sandboxIsolation" - } - enum_type { - name: "DebugType" - value { - name: "NPIPE" - number: 0 - } - value { - name: "FILE" - number: 1 - } - value { - name: "ETW" - number: 2 - } - } - enum_type { - name: "SandboxIsolation" - value { - name: "PROCESS" - number: 0 - } - value { - name: "HYPERVISOR" - number: 1 - } - } - } - options { - go_package: "github.com/containerd/containerd/runtime/v2/runhcs/options;options" - } - weak_dependency: 0 - syntax: "proto3" -} diff -Nru containerd-1.2.6/runtime/v2/runhcs/options/runhcs.pb.go containerd-1.5.9/runtime/v2/runhcs/options/runhcs.pb.go --- containerd-1.2.6/runtime/v2/runhcs/options/runhcs.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/options/runhcs.pb.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,571 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: github.com/containerd/containerd/runtime/v2/runhcs/options/runhcs.proto - -/* - Package options is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/runtime/v2/runhcs/options/runhcs.proto - - It has these top-level messages: - Options -*/ -package options - -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" - -// skipping weak import gogoproto "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_DebugType int32 - -const ( - Options_NPIPE Options_DebugType = 0 - Options_FILE Options_DebugType = 1 - Options_ETW Options_DebugType = 2 -) - -var Options_DebugType_name = map[int32]string{ - 0: "NPIPE", - 1: "FILE", - 2: "ETW", -} -var Options_DebugType_value = map[string]int32{ - "NPIPE": 0, - "FILE": 1, - "ETW": 2, -} - -func (x Options_DebugType) String() string { - return proto.EnumName(Options_DebugType_name, int32(x)) -} -func (Options_DebugType) EnumDescriptor() ([]byte, []int) { return fileDescriptorRunhcs, []int{0, 0} } - -type Options_SandboxIsolation int32 - -const ( - Options_PROCESS Options_SandboxIsolation = 0 - Options_HYPERVISOR Options_SandboxIsolation = 1 -) - -var Options_SandboxIsolation_name = map[int32]string{ - 0: "PROCESS", - 1: "HYPERVISOR", -} -var Options_SandboxIsolation_value = map[string]int32{ - "PROCESS": 0, - "HYPERVISOR": 1, -} - -func (x Options_SandboxIsolation) String() string { - return proto.EnumName(Options_SandboxIsolation_name, int32(x)) -} -func (Options_SandboxIsolation) EnumDescriptor() ([]byte, []int) { - return fileDescriptorRunhcs, []int{0, 1} -} - -type Options struct { - // enable debug tracing - Debug bool `protobuf:"varint,1,opt,name=debug,proto3" json:"debug,omitempty"` - // debug tracing output type - DebugType Options_DebugType `protobuf:"varint,2,opt,name=debug_type,json=debugType,proto3,enum=containerd.runhcs.v1.Options_DebugType" json:"debug_type,omitempty"` - // registry key root for storage of the runhcs container state - RegistryRoot string `protobuf:"bytes,3,opt,name=registry_root,json=registryRoot,proto3" json:"registry_root,omitempty"` - // sandbox_image is the image to use for the sandbox that matches the - // sandbox_platform. - SandboxImage string `protobuf:"bytes,4,opt,name=sandbox_image,json=sandboxImage,proto3" json:"sandbox_image,omitempty"` - // sandbox_platform is a CRI setting that specifies the platform - // architecture for all sandbox's in this runtime. Values are - // 'windows/amd64' and 'linux/amd64'. - SandboxPlatform string `protobuf:"bytes,5,opt,name=sandbox_platform,json=sandboxPlatform,proto3" json:"sandbox_platform,omitempty"` - // sandbox_isolation is a CRI setting that specifies the isolation level of - // the sandbox. For Windows runtime PROCESS and HYPERVISOR are valid. For - // LCOW only HYPERVISOR is valid and default if omitted. - SandboxIsolation Options_SandboxIsolation `protobuf:"varint,6,opt,name=sandbox_isolation,json=sandboxIsolation,proto3,enum=containerd.runhcs.v1.Options_SandboxIsolation" json:"sandbox_isolation,omitempty"` -} - -func (m *Options) Reset() { *m = Options{} } -func (*Options) ProtoMessage() {} -func (*Options) Descriptor() ([]byte, []int) { return fileDescriptorRunhcs, []int{0} } - -func init() { - proto.RegisterType((*Options)(nil), "containerd.runhcs.v1.Options") - proto.RegisterEnum("containerd.runhcs.v1.Options_DebugType", Options_DebugType_name, Options_DebugType_value) - proto.RegisterEnum("containerd.runhcs.v1.Options_SandboxIsolation", Options_SandboxIsolation_name, Options_SandboxIsolation_value) -} -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 m.Debug { - dAtA[i] = 0x8 - i++ - if m.Debug { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i++ - } - if m.DebugType != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintRunhcs(dAtA, i, uint64(m.DebugType)) - } - if len(m.RegistryRoot) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintRunhcs(dAtA, i, uint64(len(m.RegistryRoot))) - i += copy(dAtA[i:], m.RegistryRoot) - } - if len(m.SandboxImage) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintRunhcs(dAtA, i, uint64(len(m.SandboxImage))) - i += copy(dAtA[i:], m.SandboxImage) - } - if len(m.SandboxPlatform) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintRunhcs(dAtA, i, uint64(len(m.SandboxPlatform))) - i += copy(dAtA[i:], m.SandboxPlatform) - } - if m.SandboxIsolation != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintRunhcs(dAtA, i, uint64(m.SandboxIsolation)) - } - return i, nil -} - -func encodeVarintRunhcs(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 - if m.Debug { - n += 2 - } - if m.DebugType != 0 { - n += 1 + sovRunhcs(uint64(m.DebugType)) - } - l = len(m.RegistryRoot) - if l > 0 { - n += 1 + l + sovRunhcs(uint64(l)) - } - l = len(m.SandboxImage) - if l > 0 { - n += 1 + l + sovRunhcs(uint64(l)) - } - l = len(m.SandboxPlatform) - if l > 0 { - n += 1 + l + sovRunhcs(uint64(l)) - } - if m.SandboxIsolation != 0 { - n += 1 + sovRunhcs(uint64(m.SandboxIsolation)) - } - return n -} - -func sovRunhcs(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} -func sozRunhcs(x uint64) (n int) { - return sovRunhcs(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *Options) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Options{`, - `Debug:` + fmt.Sprintf("%v", this.Debug) + `,`, - `DebugType:` + fmt.Sprintf("%v", this.DebugType) + `,`, - `RegistryRoot:` + fmt.Sprintf("%v", this.RegistryRoot) + `,`, - `SandboxImage:` + fmt.Sprintf("%v", this.SandboxImage) + `,`, - `SandboxPlatform:` + fmt.Sprintf("%v", this.SandboxPlatform) + `,`, - `SandboxIsolation:` + fmt.Sprintf("%v", this.SandboxIsolation) + `,`, - `}`, - }, "") - return s -} -func valueToStringRunhcs(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 ErrIntOverflowRunhcs - } - 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 != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Debug", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - m.Debug = bool(v != 0) - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field DebugType", wireType) - } - m.DebugType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.DebugType |= (Options_DebugType(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RegistryRoot", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - 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 ErrInvalidLengthRunhcs - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RegistryRoot = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SandboxImage", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - 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 ErrInvalidLengthRunhcs - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SandboxImage = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SandboxPlatform", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - 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 ErrInvalidLengthRunhcs - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SandboxPlatform = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SandboxIsolation", wireType) - } - m.SandboxIsolation = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRunhcs - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SandboxIsolation |= (Options_SandboxIsolation(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipRunhcs(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthRunhcs - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipRunhcs(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, ErrIntOverflowRunhcs - } - 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, ErrIntOverflowRunhcs - } - 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, ErrIntOverflowRunhcs - } - 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, ErrInvalidLengthRunhcs - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRunhcs - } - 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 := skipRunhcs(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 ( - ErrInvalidLengthRunhcs = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowRunhcs = fmt.Errorf("proto: integer overflow") -) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/runtime/v2/runhcs/options/runhcs.proto", fileDescriptorRunhcs) -} - -var fileDescriptorRunhcs = []byte{ - // 383 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcd, 0x6e, 0x9b, 0x40, - 0x14, 0x85, 0x19, 0xff, 0x73, 0xdb, 0xba, 0x74, 0xe4, 0x05, 0xea, 0x02, 0x59, 0xee, 0xa2, 0xf6, - 0x06, 0x54, 0x77, 0xd9, 0x9d, 0x5b, 0xdc, 0x22, 0x55, 0x35, 0x1a, 0xac, 0xb6, 0xf9, 0x91, 0x2c, - 0x30, 0x04, 0x23, 0x19, 0x06, 0xc1, 0xd8, 0x8a, 0x77, 0x79, 0x89, 0xbc, 0x93, 0x97, 0x59, 0x66, - 0x19, 0xf3, 0x24, 0x11, 0x30, 0x38, 0x51, 0x14, 0x65, 0x91, 0x15, 0xe7, 0x1e, 0xbe, 0x7b, 0xee, - 0x5c, 0xcd, 0xc0, 0x4f, 0x3f, 0x60, 0xab, 0x8d, 0xa3, 0x2e, 0x69, 0xa8, 0x2d, 0x69, 0xc4, 0xec, - 0x20, 0xf2, 0x12, 0xf7, 0xb1, 0x4c, 0x36, 0x11, 0x0b, 0x42, 0x4f, 0xdb, 0x8e, 0x73, 0xb9, 0x5a, - 0xa6, 0x1a, 0x8d, 0x59, 0x40, 0xa3, 0x94, 0x97, 0x6a, 0x9c, 0x50, 0x46, 0x71, 0xef, 0xa1, 0x45, - 0xe5, 0x3f, 0xb6, 0x5f, 0x3e, 0xf6, 0x7c, 0xea, 0xd3, 0x02, 0xd0, 0x72, 0x55, 0xb2, 0x83, 0xeb, - 0x3a, 0xb4, 0x67, 0x65, 0x08, 0xee, 0x41, 0xd3, 0xf5, 0x9c, 0x8d, 0x2f, 0xa3, 0x3e, 0x1a, 0x76, - 0x48, 0x59, 0xe0, 0x29, 0x40, 0x21, 0x16, 0x6c, 0x17, 0x7b, 0x72, 0xad, 0x8f, 0x86, 0xdd, 0xf1, - 0x67, 0xf5, 0xb9, 0x11, 0x2a, 0x0f, 0x52, 0x7f, 0xe4, 0xfc, 0x7c, 0x17, 0x7b, 0x44, 0x74, 0x2b, - 0x89, 0x3f, 0xc1, 0xbb, 0xc4, 0xf3, 0x83, 0x94, 0x25, 0xbb, 0x45, 0x42, 0x29, 0x93, 0xeb, 0x7d, - 0x34, 0x14, 0xc9, 0xdb, 0xca, 0x24, 0x94, 0xb2, 0x1c, 0x4a, 0xed, 0xc8, 0x75, 0xe8, 0xe5, 0x22, - 0x08, 0x6d, 0xdf, 0x93, 0x1b, 0x25, 0xc4, 0x4d, 0x23, 0xf7, 0xf0, 0x08, 0xa4, 0x0a, 0x8a, 0xd7, - 0x36, 0xbb, 0xa0, 0x49, 0x28, 0x37, 0x0b, 0xee, 0x3d, 0xf7, 0x4d, 0x6e, 0xe3, 0x33, 0xf8, 0x70, - 0xcc, 0x4b, 0xe9, 0xda, 0xce, 0xcf, 0x27, 0xb7, 0x8a, 0x1d, 0xd4, 0x97, 0x77, 0xb0, 0xf8, 0xc4, - 0xaa, 0x8b, 0x54, 0x33, 0x8f, 0xce, 0x60, 0x04, 0xe2, 0x71, 0x53, 0x2c, 0x42, 0xf3, 0x8f, 0x69, - 0x98, 0xba, 0x24, 0xe0, 0x0e, 0x34, 0xa6, 0xc6, 0x6f, 0x5d, 0x42, 0xb8, 0x0d, 0x75, 0x7d, 0xfe, - 0x4f, 0xaa, 0x0d, 0x34, 0x90, 0x9e, 0x06, 0xe2, 0x37, 0xd0, 0x36, 0xc9, 0xec, 0xbb, 0x6e, 0x59, - 0x92, 0x80, 0xbb, 0x00, 0xbf, 0x4e, 0x4c, 0x9d, 0xfc, 0x35, 0xac, 0x19, 0x91, 0xd0, 0xe4, 0x7c, - 0x7f, 0x50, 0x84, 0xdb, 0x83, 0x22, 0x5c, 0x65, 0x0a, 0xda, 0x67, 0x0a, 0xba, 0xc9, 0x14, 0x74, - 0x97, 0x29, 0xe8, 0x74, 0xf2, 0xfa, 0x67, 0xf2, 0x8d, 0x7f, 0xff, 0x0b, 0x4e, 0xab, 0xb8, 0xfe, - 0xaf, 0xf7, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe8, 0xe0, 0x0a, 0x7a, 0x75, 0x02, 0x00, 0x00, -} diff -Nru containerd-1.2.6/runtime/v2/runhcs/options/runhcs.proto containerd-1.5.9/runtime/v2/runhcs/options/runhcs.proto --- containerd-1.2.6/runtime/v2/runhcs/options/runhcs.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/options/runhcs.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -syntax = "proto3"; - -package containerd.runhcs.v1; - -import weak "gogoproto/gogo.proto"; - -option go_package = "github.com/containerd/containerd/runtime/v2/runhcs/options;options"; - -message Options { - // enable debug tracing - bool debug = 1; - - enum DebugType { - NPIPE = 0; - FILE = 1; - ETW = 2; - } - - // debug tracing output type - DebugType debug_type = 2; - - // registry key root for storage of the runhcs container state - string registry_root = 3; - - // sandbox_image is the image to use for the sandbox that matches the - // sandbox_platform. - string sandbox_image = 4; - - // sandbox_platform is a CRI setting that specifies the platform - // architecture for all sandbox's in this runtime. Values are - // 'windows/amd64' and 'linux/amd64'. - string sandbox_platform = 5; - - enum SandboxIsolation { - PROCESS = 0; - HYPERVISOR = 1; - } - - // sandbox_isolation is a CRI setting that specifies the isolation level of - // the sandbox. For Windows runtime PROCESS and HYPERVISOR are valid. For - // LCOW only HYPERVISOR is valid and default if omitted. - SandboxIsolation sandbox_isolation = 6; -} diff -Nru containerd-1.2.6/runtime/v2/runhcs/process.go containerd-1.5.9/runtime/v2/runhcs/process.go --- containerd-1.2.6/runtime/v2/runhcs/process.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/process.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runhcs - -import ( - "context" - "os" - "os/exec" - "sync" - "sync/atomic" - "syscall" - "time" - - eventstypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/runtime" -) - -type processExit struct { - pid uint32 - exitStatus uint32 - exitedAt time.Time - exitErr error -} - -func newProcess(ctx context.Context, s *service, id string, pid uint32, pr *pipeRelay, bundle, stdin, stdout, stderr string, terminal bool) (*process, error) { - p, err := os.FindProcess(int(pid)) - if err != nil { - return nil, err - } - process := &process{ - cid: id, - id: id, - pid: pid, - bundle: bundle, - stdin: stdin, - stdout: stdout, - stderr: stderr, - terminal: terminal, - relay: pr, - waitBlock: make(chan struct{}), - } - // Store the default non-exited value for calls to stat - process.exit.Store(&processExit{ - pid: pid, - exitStatus: 255, - exitedAt: time.Time{}, - exitErr: nil, - }) - go waitForProcess(ctx, process, p, s) - return process, nil -} - -func waitForProcess(ctx context.Context, process *process, p *os.Process, s *service) { - var status int - _, eerr := p.Wait() - if eerr != nil { - status = 255 - if exitErr, ok := eerr.(*exec.ExitError); ok { - if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok { - status = ws.ExitStatus() - } - } - } - now := time.Now() - process.exit.Store(&processExit{ - pid: process.pid, - exitStatus: uint32(status), - exitedAt: now, - exitErr: eerr, - }) - - // Wait for the relay - process.relay.wait() - - // close the client io, and free upstream waiters - process.close() - - s.publisher.Publish( - ctx, - runtime.TaskExitEventTopic, - &eventstypes.TaskExit{ - ContainerID: process.cid, - ID: process.id, - Pid: process.pid, - ExitStatus: uint32(status), - ExitedAt: now, - }) -} - -func newExecProcess(ctx context.Context, s *service, cid, id string, pr *pipeRelay, bundle, stdin, stdout, stderr string, terminal bool) (*process, error) { - process := &process{ - cid: cid, - id: id, - bundle: bundle, - stdin: stdin, - stdout: stdout, - stderr: stderr, - terminal: terminal, - relay: pr, - waitBlock: make(chan struct{}), - } - // Store the default non-exited value for calls to stat - process.exit.Store(&processExit{ - exitStatus: 255, - exitedAt: time.Time{}, - exitErr: nil, - }) - return process, nil -} - -type process struct { - sync.Mutex - - cid string - id string - pid uint32 - - bundle string - stdin string - stdout string - stderr string - terminal bool - relay *pipeRelay - - // started track if the process has ever been started and will not be reset - // for the lifetime of the process object. - started bool - - waitBlock chan struct{} - // exit holds the exit value for all calls to `stat`. By default a - // non-exited value is stored of status: 255, at: time 0. - exit atomic.Value - - // closeOnce is responsible for closing waitBlock and any io. - closeOnce sync.Once -} - -// closeIO closes the stdin of the executing process to unblock any waiters -func (p *process) closeIO() { - p.Lock() - defer p.Unlock() - - p.relay.closeIO() -} - -// close closes all stdio and frees any waiters. This is safe to call multiple -// times. -func (p *process) close() { - p.closeOnce.Do(func() { - p.relay.close() - - // Free any waiters - close(p.waitBlock) - }) -} - -// stat is a non-blocking query of the current process state. -func (p *process) stat() *processExit { - er := p.exit.Load() - return er.(*processExit) -} - -// wait waits for the container process to exit and returns the exit status. If -// the process failed post start the processExit will contain the exitErr. This -// is safe to call previous to calling start(). -func (p *process) wait() *processExit { - <-p.waitBlock - return p.stat() -} diff -Nru containerd-1.2.6/runtime/v2/runhcs/service.go containerd-1.5.9/runtime/v2/runhcs/service.go --- containerd-1.2.6/runtime/v2/runhcs/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/runhcs/service.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,987 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package runhcs - -import ( - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "os/exec" - "path" - "path/filepath" - "strconv" - "strings" - "sync" - "syscall" - "time" - - winio "github.com/Microsoft/go-winio" - "github.com/Microsoft/hcsshim/pkg/go-runhcs" - containerd_types "github.com/containerd/containerd/api/types" - "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/runtime/v2/runhcs/options" - "github.com/containerd/containerd/runtime/v2/shim" - taskAPI "github.com/containerd/containerd/runtime/v2/task" - "github.com/containerd/go-runc" - "github.com/containerd/typeurl" - ptypes "github.com/gogo/protobuf/types" - oci "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -const ( - runhcsShimVersion = "0.0.1" - safePipePrefix = `\\.\pipe\ProtectedPrefix\Administrators\` - - errorConnectionAborted syscall.Errno = 1236 -) - -var ( - empty = &ptypes.Empty{} -) - -// forwardRunhcsLogs copies logs from c and writes them to the ctx logger -// upstream. -func forwardRunhcsLogs(ctx context.Context, c net.Conn, fields logrus.Fields) { - defer c.Close() - j := json.NewDecoder(c) - - for { - e := logrus.Entry{} - err := j.Decode(&e.Data) - if err == io.EOF || err == errorConnectionAborted { - break - } - if err != nil { - // Likely the last message wasn't complete at closure. Just read all - // data and forward as error. - data, _ := ioutil.ReadAll(io.MultiReader(j.Buffered(), c)) - if len(data) != 0 { - log.G(ctx).WithFields(fields).Error(string(data)) - } - break - } - - msg := e.Data[logrus.FieldKeyMsg] - delete(e.Data, logrus.FieldKeyMsg) - - level, err := logrus.ParseLevel(e.Data[logrus.FieldKeyLevel].(string)) - if err != nil { - log.G(ctx).WithFields(fields).WithError(err).Debug("invalid log level") - level = logrus.DebugLevel - } - delete(e.Data, logrus.FieldKeyLevel) - - // TODO: JTERRY75 maybe we need to make this configurable so we know - // that runhcs is using the same one we are deserializing. - ti, err := time.Parse(logrus.DefaultTimestampFormat, e.Data[logrus.FieldKeyTime].(string)) - if err != nil { - log.G(ctx).WithFields(fields).WithError(err).Debug("invalid time stamp format") - ti = time.Time{} - } - delete(e.Data, logrus.FieldKeyTime) - - etr := log.G(ctx).WithFields(fields).WithFields(e.Data) - etr.Time = ti - switch level { - case logrus.PanicLevel: - etr.Panic(msg) - case logrus.FatalLevel: - etr.Fatal(msg) - case logrus.ErrorLevel: - etr.Error(msg) - case logrus.WarnLevel: - etr.Warn(msg) - case logrus.InfoLevel: - etr.Info(msg) - case logrus.DebugLevel: - etr.Debug(msg) - } - } -} - -// New returns a new runhcs shim service that can be used via GRPC -func New(ctx context.Context, id string, publisher events.Publisher) (shim.Shim, error) { - return &service{ - context: ctx, - id: id, - processes: make(map[string]*process), - publisher: publisher, - }, nil -} - -var _ = (taskAPI.TaskService)(&service{}) -var _ = (shim.Shim)(&service{}) - -// service is the runhcs shim implementation of the v2 TaskService over GRPC -type service struct { - mu sync.Mutex - - context context.Context - - // debugLog if not "" indicates the log file or pipe path for runhcs.exe to - // write its logs to. - debugLog string - // if `shimOpts.DebugType == options.Opitons_NPIPE` will hold the listener - // for the runhcs.exe to connect to for sending logs. - debugListener net.Listener - - shimOpts options.Options - - id string - processes map[string]*process - - publisher events.Publisher -} - -func (s *service) newRunhcs() *runhcs.Runhcs { - return &runhcs.Runhcs{ - Debug: s.shimOpts.Debug, - Log: s.debugLog, - LogFormat: runhcs.JSON, - Owner: "containerd-runhcs-shim-v1", - Root: s.shimOpts.RegistryRoot, - } -} - -// getProcess attempts to get a process by id. -// The caller MUST NOT have locked s.mu previous to calling this function. -func (s *service) getProcess(id, execID string) (*process, error) { - s.mu.Lock() - defer s.mu.Unlock() - - return s.getProcessLocked(id, execID) -} - -// getProcessLocked attempts to get a process by id. -// The caller MUST protect s.mu previous to calling this function. -func (s *service) getProcessLocked(id, execID string) (*process, error) { - if execID != "" { - id = execID - } - - var p *process - var ok bool - if p, ok = s.processes[id]; !ok { - return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process %s", id) - } - return p, nil -} - -func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { - log.G(ctx).Info("Starting Cleanup") - - _, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return nil, err - } - // Forcibly shut down any container in this bundle - rhcs := s.newRunhcs() - dopts := &runhcs.DeleteOpts{ - Force: true, - } - if err := rhcs.Delete(ctx, s.id, dopts); err != nil { - log.G(ctx).WithError(err).Debugf("failed to delete container") - } - - opts, ok := ctx.Value(shim.OptsKey{}).(shim.Opts) - if ok && opts.BundlePath != "" { - if err := os.RemoveAll(opts.BundlePath); err != nil { - return nil, err - } - } - - return &taskAPI.DeleteResponse{ - ExitedAt: time.Now(), - ExitStatus: 255, - }, nil -} - -func (s *service) StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) { - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return "", err - } - self, err := os.Executable() - if err != nil { - return "", err - } - cwd, err := os.Getwd() - if err != nil { - return "", err - } - socketAddress, err := shim.SocketAddress(ctx, id) - if err != nil { - return "", err - } - args := []string{ - "-namespace", ns, - "-id", id, - "-address", containerdAddress, - "-publish-binary", containerdBinary, - "-socket", socketAddress, - } - - opts, ok := ctx.Value(shim.OptsKey{}).(shim.Opts) - if ok && opts.Debug { - args = append(args, "-debug") - } - - cmd := exec.Command(self, args...) - cmd.Dir = cwd - cmd.Env = append(os.Environ(), "GOMAXPROCS=2") - - if err = cmd.Start(); err != nil { - return "", err - } - defer func() { - if err != nil { - cmd.Process.Kill() - } - }() - // TODO: JTERRY75 - Windows does not use the ExtraFiles to pass the socket - // because winio does not support it which exposes a race condition between - // these two processes. For now AnonDialer will retry if the file does not - // exist up to the timeout waiting for the shim service to create the pipe. - go cmd.Wait() - if err := shim.WritePidFile("shim.pid", cmd.Process.Pid); err != nil { - return "", err - } - if err := shim.WriteAddress("address", socketAddress); err != nil { - return "", err - } - return socketAddress, nil -} - -// State returns runtime state information for a process -func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { - log.G(ctx).Debugf("State: %s: %s", r.ID, r.ExecID) - - s.mu.Lock() - defer s.mu.Unlock() - - var p *process - var err error - if p, err = s.getProcessLocked(r.ID, r.ExecID); err != nil { - return nil, err - } - - var tstatus string - - // This is a container - if p.cid == p.id { - rhcs := s.newRunhcs() - cs, err := rhcs.State(ctx, p.id) - if err != nil { - return nil, err - } - tstatus = cs.Status - } else { - if p.started { - tstatus = "running" - } else { - tstatus = "created" - } - } - - status := task.StatusUnknown - switch tstatus { - case "created": - status = task.StatusCreated - case "running": - status = task.StatusRunning - case "stopped": - status = task.StatusStopped - case "paused": - status = task.StatusPaused - } - pe := p.stat() - return &taskAPI.StateResponse{ - ID: p.id, - Bundle: p.bundle, - Pid: p.pid, - Status: status, - Stdin: p.stdin, - Stdout: p.stdout, - Stderr: p.stderr, - Terminal: p.terminal, - ExitStatus: pe.exitStatus, - ExitedAt: pe.exitedAt, - }, nil -} - -func writeMountsToConfig(bundle string, mounts []*containerd_types.Mount) error { - if len(mounts) != 1 { - return errors.New("Rootfs does not contain exactly 1 mount for the root file system") - } - - m := mounts[0] - if m.Type != "windows-layer" && m.Type != "lcow-layer" { - return errors.Errorf("unsupported mount type '%s'", m.Type) - } - - // parentLayerPaths are passed in layerN, layerN-1, ..., layer 0 - // - // The OCI spec expects: - // windows-layer order is layerN, layerN-1, ..., layer0, scratch - // lcow-layer order is layer0, layer1, ..., layerN, scratch - var parentLayerPaths []string - for _, option := range mounts[0].Options { - if strings.HasPrefix(option, mount.ParentLayerPathsFlag) { - err := json.Unmarshal([]byte(option[len(mount.ParentLayerPathsFlag):]), &parentLayerPaths) - if err != nil { - return errors.Wrap(err, "failed to unmarshal parent layer paths from mount") - } - } - } - - if m.Type == "lcow-layer" { - // Reverse the lcow-layer parents - for i := len(parentLayerPaths)/2 - 1; i >= 0; i-- { - opp := len(parentLayerPaths) - 1 - i - parentLayerPaths[i], parentLayerPaths[opp] = parentLayerPaths[opp], parentLayerPaths[i] - } - } - - cf, err := os.OpenFile(path.Join(bundle, "config.json"), os.O_RDWR, 0) - if err != nil { - return errors.Wrap(err, "bundle does not contain config.json") - } - defer cf.Close() - var spec oci.Spec - if err := json.NewDecoder(cf).Decode(&spec); err != nil { - return errors.Wrap(err, "bundle config.json is not valid oci spec") - } - if err := cf.Truncate(0); err != nil { - return errors.Wrap(err, "failed to truncate config.json") - } - if _, err := cf.Seek(0, 0); err != nil { - return errors.Wrap(err, "failed to seek to 0 in config.json") - } - - // If we are creating LCOW make sure that spec.Windows is filled out before - // appending layer folders. - if m.Type == "lcow-layer" && spec.Windows == nil { - spec.Windows = &oci.Windows{ - HyperV: &oci.WindowsHyperV{}, - } - } - - // Append the parents - spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, parentLayerPaths...) - // Append the scratch - spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, m.Source) - - if err := json.NewEncoder(cf).Encode(spec); err != nil { - return errors.Wrap(err, "failed to write Mounts into config.json") - } - return nil -} - -// Create a new initial process and container with runhcs -func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (*taskAPI.CreateTaskResponse, error) { - log.G(ctx).Debugf("Create: %s", r.ID) - - // Hold the lock for the entire duration to avoid duplicate process creation. - s.mu.Lock() - defer s.mu.Unlock() - - _, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return nil, errors.Wrap(err, "create namespace") - } - - if r.Options != nil { - v, err := typeurl.UnmarshalAny(r.Options) - if err != nil { - return nil, err - } - s.shimOpts = *v.(*options.Options) - } - - if p := s.processes[r.ID]; p != nil { - return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "process %s already exists", r.ID) - } - if r.ID != s.id { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "init process id '%s' != shim id '%s'", r.ID, s.id) - } - - // Add the mounts to the layer paths - if err := writeMountsToConfig(r.Bundle, r.Rootfs); err != nil { - return nil, errdefs.ToGRPC(err) - } - - // Create the IO for the process - io, err := runc.NewPipeIO() - if err != nil { - return nil, errors.Wrap(err, "failed to create io pipes") - } - defer func() { - if err != nil { - io.Close() - } - }() - // Create the upstream IO - ps, err := newPipeSet(ctx, r.Stdin, r.Stdout, r.Stderr, r.Terminal) - if err != nil { - return nil, errors.Wrap(err, "failed to connect to upstream IO") - } - defer func() { - if err != nil { - ps.Close() - } - }() - // Create the relay for them both. - pr := newPipeRelay(ctx, ps, io) - defer func() { - if err != nil { - pr.close() - } - }() - - if s.shimOpts.Debug { - if s.debugLog == "" { - if s.shimOpts.DebugType == options.Options_FILE { - s.debugLog = filepath.Join(r.Bundle, fmt.Sprintf("runhcs-%s.log", r.ID)) - } else { - logPath := safePipePrefix + fmt.Sprintf("runhcs-log-%s", r.ID) - l, err := winio.ListenPipe(logPath, nil) - if err != nil { - return nil, err - } - s.debugLog = logPath - s.debugListener = l - - // Accept connections and forward all logs for each runhcs.exe - // invocation - go func() { - for { - c, err := s.debugListener.Accept() - if err != nil { - if err == winio.ErrPipeListenerClosed { - break - } - log.G(ctx).WithError(err).Debug("log accept failure") - // Logrus error locally? - continue - } - fields := map[string]interface{}{ - "log-source": "runhcs", - "task-id": r.ID, - } - go forwardRunhcsLogs(ctx, c, fields) - } - }() - } - } - } - - pidfilePath := path.Join(r.Bundle, "runhcs-pidfile.pid") - copts := &runhcs.CreateOpts{ - IO: io, - PidFile: pidfilePath, - } - rhcs := s.newRunhcs() - if rhcs.Debug { - if s.shimOpts.DebugType == options.Options_FILE { - copts.ShimLog = filepath.Join(r.Bundle, fmt.Sprintf("runhcs-shim-%s.log", r.ID)) - copts.VMLog = filepath.Join(r.Bundle, fmt.Sprintf("runhcs-vmshim-%s.log", r.ID)) - } else { - doForwardLogs := func(source, logPipeFmt string, opt *string) error { - pipeName := fmt.Sprintf(logPipeFmt, r.ID) - *opt = safePipePrefix + pipeName - l, err := winio.ListenPipe(*opt, nil) - if err != nil { - return err - } - go func() { - defer l.Close() - c, err := l.Accept() - if err != nil { - log.G(ctx). - WithField("task-id", r.ID). - WithError(err). - Errorf("failed to accept %s", pipeName) - } else { - fields := map[string]interface{}{ - "log-source": source, - "task-id": r.ID, - } - go forwardRunhcsLogs(ctx, c, fields) - } - }() - return nil - } - - err = doForwardLogs("runhcs-shim", "runhcs-shim-log-%s", &copts.ShimLog) - if err != nil { - return nil, err - } - - err = doForwardLogs("runhcs--vm-shim", "runhcs-vm-shim-log-%s", &copts.VMLog) - if err != nil { - return nil, err - } - } - } - err = rhcs.Create(ctx, r.ID, r.Bundle, copts) - if err != nil { - return nil, err - } - - // We successfully created the process. Convert from initpid to the container process. - pid, err := runc.ReadPidFile(pidfilePath) - if err != nil { - return nil, errors.Wrap(err, "failed to read container pid from pidfile") - } - - process, err := newProcess( - ctx, - s, - r.ID, - uint32(pid), - pr, - r.Bundle, - r.Stdin, - r.Stdout, - r.Stderr, - r.Terminal) - - if err != nil { - return nil, err - } - s.processes[r.ID] = process - - return &taskAPI.CreateTaskResponse{ - Pid: uint32(pid), - }, nil -} - -// Start a process -func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { - log.G(ctx).Debugf("Start: %s: %s", r.ID, r.ExecID) - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - p.Lock() - defer p.Unlock() - - if p.started { - return nil, errors.New("cannot start already started container or process") - } - - rhcs := s.newRunhcs() - - // This is a start/exec - if r.ExecID != "" { - execFmt := fmt.Sprintf("exec-%s-%s", r.ID, r.ExecID) - pidfilePath := path.Join(p.bundle, fmt.Sprintf("runhcs-%s-pidfile.pid", execFmt)) - procConfig := path.Join(p.bundle, execFmt+"config.json") - eopts := &runhcs.ExecOpts{ - IO: p.relay.io, - PidFile: pidfilePath, - Detach: true, - } - - if rhcs.Debug { - if s.shimOpts.DebugType == options.Options_FILE { - eopts.ShimLog = filepath.Join(p.bundle, fmt.Sprintf("runhcs-shim-%s.log", execFmt)) - } else { - doForwardLogs := func(source, pipeName string, opt *string) error { - *opt = safePipePrefix + pipeName - l, err := winio.ListenPipe(*opt, nil) - if err != nil { - return err - } - go func() { - defer l.Close() - c, err := l.Accept() - if err != nil { - log.G(ctx). - WithField("task-id", r.ID). - WithField("exec-id", r.ExecID). - WithError(err). - Errorf("failed to accept %s", pipeName) - } else { - fields := map[string]interface{}{ - "log-source": source, - "task-id": r.ID, - "exec-id": r.ExecID, - } - go forwardRunhcsLogs(ctx, c, fields) - } - }() - return nil - } - - err = doForwardLogs("runhcs-shim-exec", "runhcs-shim-log-"+execFmt, &eopts.ShimLog) - if err != nil { - return nil, err - } - } - } - - // ID here is the containerID to exec the process in. - err = rhcs.Exec(ctx, r.ID, procConfig, eopts) - if err != nil { - return nil, errors.Wrapf(err, "failed to exec process: %s", r.ExecID) - } - - p.started = true - - // We successfully exec'd the process. Convert from initpid to the container process. - pid, err := runc.ReadPidFile(pidfilePath) - if err != nil { - return nil, errors.Wrap(err, "failed to read container pid from pidfile") - } - - proc, err := os.FindProcess(pid) - if err != nil { - return nil, errors.Wrap(err, "failed to find exec process pid") - } - p.pid = uint32(pid) - go waitForProcess(ctx, p, proc, s) - } else { - if err := rhcs.Start(ctx, p.id); err != nil { - return nil, errors.Wrapf(err, "failed to start container: %s", p.id) - } - - p.started = true - - // TODO: JTERRY75 - This is a total hack. We cant return from this call - // until the state has transitioned. Because runhcs start is long lived it - // will return before the actual state is "RUNNING" which causes a failure - // if the 'state' query comes in and it is not in the "RUNNING" state. - stateRequest := &taskAPI.StateRequest{ - ID: r.ID, - ExecID: r.ExecID, - } - for { - sr, err := s.State(ctx, stateRequest) - if err != nil { - log.G(ctx).WithError(err).Debug("failed to query state of container") - break - } - // Have we transitioned states yet? Expect != created && != unknown - if sr.Status != task.StatusCreated && sr.Status != task.StatusUnknown { - break - } - time.Sleep(1 * time.Second) - } - } - return &taskAPI.StartResponse{ - Pid: p.pid, - }, nil -} - -// Delete the initial process and container -func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { - log.G(ctx).Debugf("Delete: %s: %s", r.ID, r.ExecID) - - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - - // This is a container - if p.cid == p.id { - rhs := s.newRunhcs() - dopts := &runhcs.DeleteOpts{ - Force: true, - } - if err := rhs.Delete(ctx, p.id, dopts); err != nil { - return nil, errors.Wrapf(err, "failed to delete container: %s", p.id) - } - } - - select { - case <-time.After(5 * time.Second): - // Force close the container process since it didn't shutdown in time. - p.close() - case <-p.waitBlock: - } - - exit := p.stat() - - s.mu.Lock() - delete(s.processes, p.id) - s.mu.Unlock() - return &taskAPI.DeleteResponse{ - ExitedAt: exit.exitedAt, - ExitStatus: exit.exitStatus, - Pid: p.pid, - }, nil -} - -// Pids returns all pids inside the container -func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { - log.G(ctx).Debugf("Pids: %s", r.ID) - - return nil, errdefs.ErrNotImplemented -} - -// Pause the container -func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Pause: %s", r.ID) - - // TODO: Validate that 'id' is actually a valid parent container ID - var p *process - var err error - if p, err = s.getProcess(r.ID, ""); err != nil { - return nil, err - } - - rhcs := s.newRunhcs() - if err = rhcs.Pause(ctx, p.id); err != nil { - return nil, err - } - - return empty, nil -} - -// Resume the container -func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Resume: %s", r.ID) - - // TODO: Validate that 'id' is actually a valid parent container ID - var p *process - var err error - if p, err = s.getProcess(r.ID, ""); err != nil { - return nil, err - } - - rhcs := s.newRunhcs() - if err = rhcs.Resume(ctx, p.id); err != nil { - return nil, err - } - - return empty, nil -} - -// Checkpoint the container -func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Checkpoint: %s", r.ID) - - return nil, errdefs.ErrNotImplemented -} - -// Kill a process with the provided signal -func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Kill: %s: %s", r.ID, r.ExecID) - - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - - // TODO: JTERRY75 runhcs support for r.All? - rhcs := s.newRunhcs() - if err = rhcs.Kill(ctx, p.id, strconv.FormatUint(uint64(r.Signal), 10)); err != nil { - if !strings.Contains(err.Error(), "container is stopped") { - return nil, err - } - } - - return empty, nil -} - -// Exec an additional process inside the container -func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Exec: %s: %s", r.ID, r.ExecID) - - s.mu.Lock() - defer s.mu.Unlock() - - var parent *process - var err error - // Get the parent container - if parent, err = s.getProcessLocked(r.ID, ""); err != nil { - return nil, err - } - - if p := s.processes[r.ExecID]; p != nil { - return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "exec process %s already exists", r.ExecID) - } - - execFmt := fmt.Sprintf("exec-%s-%s", r.ID, r.ExecID) - - var spec oci.Process - if err := json.Unmarshal(r.Spec.Value, &spec); err != nil { - return nil, errors.Wrap(err, "request.Spec was not oci process") - } - procConfig := path.Join(parent.bundle, execFmt+"config.json") - cf, err := os.OpenFile(procConfig, os.O_CREATE|os.O_WRONLY, 0) - if err != nil { - return nil, errors.Wrap(err, "bundle does not contain config.json") - } - if err := json.NewEncoder(cf).Encode(spec); err != nil { - cf.Close() - return nil, errors.Wrap(err, "failed to write Mounts into config.json") - } - cf.Close() - - // Create the IO for the process - io, err := runc.NewPipeIO() - if err != nil { - return nil, errors.Wrap(err, "failed to create io pipes") - } - defer func() { - if err != nil { - io.Close() - } - }() - // Create the upstream IO - ps, err := newPipeSet(ctx, r.Stdin, r.Stdout, r.Stderr, r.Terminal) - if err != nil { - return nil, errors.Wrap(err, "failed to connect to upstream IO") - } - defer func() { - if err != nil { - ps.Close() - } - }() - // Create the relay for them both. - pr := newPipeRelay(ctx, ps, io) - defer func() { - if err != nil { - pr.close() - } - }() - - process, err := newExecProcess( - ctx, - s, - r.ID, - r.ExecID, - pr, - parent.bundle, - r.Stdin, - r.Stdout, - r.Stderr, - r.Terminal) - - if err != nil { - return nil, err - } - s.processes[r.ExecID] = process - - return empty, nil -} - -// ResizePty of a process -func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("ResizePty: %s: %s", r.ID, r.ExecID) - - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - - pid := int(p.pid) - opts := runhcs.ResizeTTYOpts{ - Pid: &pid, - } - rhcs := s.newRunhcs() - if err = rhcs.ResizeTTY(ctx, p.cid, uint16(r.Width), uint16(r.Height), &opts); err != nil { - return nil, err - } - - return empty, nil -} - -// CloseIO of a process -func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("CloseIO: %s: %s", r.ID, r.ExecID) - - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - p.closeIO() - return empty, nil -} - -// Update a running container -func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Update: %s", r.ID) - - return nil, errdefs.ErrNotImplemented -} - -// Wait for a process to exit -func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { - log.G(ctx).Debugf("Wait: %s: %s", r.ID, r.ExecID) - - var p *process - var err error - if p, err = s.getProcess(r.ID, r.ExecID); err != nil { - return nil, err - } - pe := p.wait() - return &taskAPI.WaitResponse{ - ExitedAt: pe.exitedAt, - ExitStatus: pe.exitStatus, - }, nil -} - -// Stats returns statistics about the running container -func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { - log.G(ctx).Debugf("Stats: %s", r.ID) - - return nil, errdefs.ErrNotImplemented -} - -// Connect returns the runhcs shim information -func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { - log.G(ctx).Debugf("Connect: %s", r.ID) - - return &taskAPI.ConnectResponse{ - ShimPid: uint32(os.Getpid()), - TaskPid: s.processes[s.id].pid, - Version: runhcsShimVersion, - }, nil -} - -// Shutdown stops this instance of the runhcs shim -func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { - log.G(ctx).Debugf("Shutdown: %s", r.ID) - - if s.debugListener != nil { - s.debugListener.Close() - } - - os.Exit(0) - return empty, nil -} diff -Nru containerd-1.2.6/runtime/v2/shim/publisher.go containerd-1.5.9/runtime/v2/shim/publisher.go --- containerd-1.2.6/runtime/v2/shim/publisher.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/publisher.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,169 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package shim + +import ( + "context" + "sync" + "time" + + v1 "github.com/containerd/containerd/api/services/ttrpc/events/v1" + "github.com/containerd/containerd/events" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/ttrpcutil" + "github.com/containerd/ttrpc" + "github.com/containerd/typeurl" + "github.com/sirupsen/logrus" +) + +const ( + queueSize = 2048 + maxRequeue = 5 +) + +type item struct { + ev *v1.Envelope + ctx context.Context + count int +} + +// NewPublisher creates a new remote events publisher +func NewPublisher(address string) (*RemoteEventsPublisher, error) { + client, err := ttrpcutil.NewClient(address) + if err != nil { + return nil, err + } + + l := &RemoteEventsPublisher{ + client: client, + closed: make(chan struct{}), + requeue: make(chan *item, queueSize), + } + + go l.processQueue() + return l, nil +} + +// RemoteEventsPublisher forwards events to a ttrpc server +type RemoteEventsPublisher struct { + client *ttrpcutil.Client + closed chan struct{} + closer sync.Once + requeue chan *item +} + +// Done returns a channel which closes when done +func (l *RemoteEventsPublisher) Done() <-chan struct{} { + return l.closed +} + +// Close closes the remote connection and closes the done channel +func (l *RemoteEventsPublisher) Close() (err error) { + err = l.client.Close() + l.closer.Do(func() { + close(l.closed) + }) + return err +} + +func (l *RemoteEventsPublisher) processQueue() { + for i := range l.requeue { + if i.count > maxRequeue { + logrus.Errorf("evicting %s from queue because of retry count", i.ev.Topic) + // drop the event + continue + } + + if err := l.forwardRequest(i.ctx, &v1.ForwardRequest{Envelope: i.ev}); err != nil { + logrus.WithError(err).Error("forward event") + l.queue(i) + } + } +} + +func (l *RemoteEventsPublisher) queue(i *item) { + go func() { + i.count++ + // re-queue after a short delay + time.Sleep(time.Duration(1*i.count) * time.Second) + l.requeue <- i + }() +} + +// Publish publishes the event by forwarding it to the configured ttrpc server +func (l *RemoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return err + } + any, err := typeurl.MarshalAny(event) + if err != nil { + return err + } + i := &item{ + ev: &v1.Envelope{ + Timestamp: time.Now(), + Namespace: ns, + Topic: topic, + Event: any, + }, + ctx: ctx, + } + + if err := l.forwardRequest(i.ctx, &v1.ForwardRequest{Envelope: i.ev}); err != nil { + l.queue(i) + return err + } + + return nil +} + +func (l *RemoteEventsPublisher) forwardRequest(ctx context.Context, req *v1.ForwardRequest) error { + service, err := l.client.EventsService() + if err == nil { + fCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + _, err = service.Forward(fCtx, req) + cancel() + if err == nil { + return nil + } + } + + if err != ttrpc.ErrClosed { + return err + } + + // Reconnect and retry request + if err = l.client.Reconnect(); err != nil { + return err + } + + service, err = l.client.EventsService() + if err != nil { + return err + } + + // try again with a fresh context, otherwise we may get a context timeout unexpectedly. + fCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + _, err = service.Forward(fCtx, req) + cancel() + if err != nil { + return err + } + + return nil +} diff -Nru containerd-1.2.6/runtime/v2/shim/reaper_unix.go containerd-1.5.9/runtime/v2/shim/reaper_unix.go --- containerd-1.2.6/runtime/v2/shim/reaper_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/reaper_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package shim - -import ( - "os/exec" - "sync" - "time" - - "github.com/containerd/containerd/sys" - runc "github.com/containerd/go-runc" - "github.com/pkg/errors" -) - -// ErrNoSuchProcess is returned when the process no longer exists -var ErrNoSuchProcess = errors.New("no such process") - -const bufferSize = 2048 - -// Reap should be called when the process receives an SIGCHLD. Reap will reap -// all exited processes and close their wait channels -func Reap() error { - now := time.Now() - exits, err := sys.Reap(false) - Default.Lock() - for c := range Default.subscribers { - for _, e := range exits { - c <- runc.Exit{ - Timestamp: now, - Pid: e.Pid, - Status: e.Status, - } - } - } - Default.Unlock() - return err -} - -// Default is the default monitor initialized for the package -var Default = &Monitor{ - subscribers: make(map[chan runc.Exit]struct{}), -} - -// Monitor monitors the underlying system for process status changes -type Monitor struct { - sync.Mutex - - subscribers map[chan runc.Exit]struct{} -} - -// Start starts the command a registers the process with the reaper -func (m *Monitor) Start(c *exec.Cmd) (chan runc.Exit, error) { - ec := m.Subscribe() - if err := c.Start(); err != nil { - m.Unsubscribe(ec) - return nil, err - } - return ec, nil -} - -// Wait blocks until a process is signal as dead. -// User should rely on the value of the exit status to determine if the -// command was successful or not. -func (m *Monitor) Wait(c *exec.Cmd, ec chan runc.Exit) (int, error) { - for e := range ec { - if e.Pid == c.Process.Pid { - // make sure we flush all IO - c.Wait() - m.Unsubscribe(ec) - return e.Status, nil - } - } - // return no such process if the ec channel is closed and no more exit - // events will be sent - return -1, ErrNoSuchProcess -} - -// Subscribe to process exit changes -func (m *Monitor) Subscribe() chan runc.Exit { - c := make(chan runc.Exit, bufferSize) - m.Lock() - m.subscribers[c] = struct{}{} - m.Unlock() - return c -} - -// Unsubscribe to process exit changes -func (m *Monitor) Unsubscribe(c chan runc.Exit) { - m.Lock() - delete(m.subscribers, c) - close(c) - m.Unlock() -} diff -Nru containerd-1.2.6/runtime/v2/shim/shim_freebsd.go containerd-1.5.9/runtime/v2/shim/shim_freebsd.go --- containerd-1.2.6/runtime/v2/shim/shim_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package shim + +import "github.com/containerd/ttrpc" + +func newServer() (*ttrpc.Server, error) { + return ttrpc.NewServer() +} + +func subreaper() error { + return nil +} diff -Nru containerd-1.2.6/runtime/v2/shim/shim.go containerd-1.5.9/runtime/v2/shim/shim.go --- containerd-1.2.6/runtime/v2/shim/shim.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ "context" "flag" "fmt" + "io" "os" "runtime" "runtime/debug" @@ -30,6 +31,7 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/namespaces" shimapi "github.com/containerd/containerd/runtime/v2/task" + "github.com/containerd/containerd/version" "github.com/containerd/ttrpc" "github.com/gogo/protobuf/proto" "github.com/pkg/errors" @@ -43,14 +45,28 @@ signals chan os.Signal } +// Publisher for events +type Publisher interface { + events.Publisher + io.Closer +} + +// StartOpts describes shim start configuration received from containerd +type StartOpts struct { + ID string + ContainerdBinary string + Address string + TTRPCAddress string +} + // Init func for the creation of a shim server -type Init func(context.Context, string, events.Publisher) (Shim, error) +type Init func(context.Context, string, Publisher, func()) (Shim, error) // Shim server interface type Shim interface { shimapi.TaskService Cleanup(ctx context.Context) (*shimapi.DeleteResponse, error) - StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) + StartShim(ctx context.Context, opts StartOpts) (string, error) } // OptsKey is the context key for the Opts value. @@ -62,8 +78,22 @@ Debug bool } +// BinaryOpts allows the configuration of a shims binary setup +type BinaryOpts func(*Config) + +// Config of shim binary options provided by shim implementations +type Config struct { + // NoSubreaper disables setting the shim as a child subreaper + NoSubreaper bool + // NoReaper disables the shim binary from reaping any child process implicitly + NoReaper bool + // NoSetupLogger disables automatic configuration of logrus to use the shim FIFO + NoSetupLogger bool +} + var ( debugFlag bool + versionFlag bool idFlag string namespaceFlag string socketFlag string @@ -73,11 +103,16 @@ action string ) +const ( + ttrpcAddressEnv = "TTRPC_ADDRESS" +) + func parseFlags() { flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs") + flag.BoolVar(&versionFlag, "v", false, "show the shim version and exit") flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim") flag.StringVar(&idFlag, "id", "", "id of the task") - flag.StringVar(&socketFlag, "socket", "", "abstract socket path to serve") + flag.StringVar(&socketFlag, "socket", "", "socket path to serve") flag.StringVar(&bundlePath, "bundle", "", "path to the bundle if not workdir") flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd") @@ -118,46 +153,68 @@ } // Run initializes and runs a shim server -func Run(id string, initFunc Init) { - if err := run(id, initFunc); err != nil { +func Run(id string, initFunc Init, opts ...BinaryOpts) { + var config Config + for _, o := range opts { + o(&config) + } + if err := run(id, initFunc, config); err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", id, err) os.Exit(1) } } -func run(id string, initFunc Init) error { +func run(id string, initFunc Init, config Config) error { parseFlags() + if versionFlag { + fmt.Printf("%s:\n", os.Args[0]) + fmt.Println(" Version: ", version.Version) + fmt.Println(" Revision:", version.Revision) + fmt.Println(" Go version:", version.GoVersion) + fmt.Println("") + return nil + } + + if namespaceFlag == "" { + return fmt.Errorf("shim namespace cannot be empty") + } + setRuntime() - signals, err := setupSignals() + signals, err := setupSignals(config) if err != nil { return err } - if err := subreaper(); err != nil { - return err - } - publisher := &remoteEventsPublisher{ - address: addressFlag, - containerdBinaryPath: containerdBinaryFlag, + + if !config.NoSubreaper { + if err := subreaper(); err != nil { + return err + } } - if namespaceFlag == "" { - return fmt.Errorf("shim namespace cannot be empty") + + ttrpcAddress := os.Getenv(ttrpcAddressEnv) + publisher, err := NewPublisher(ttrpcAddress) + if err != nil { + return err } + defer publisher.Close() + ctx := namespaces.WithNamespace(context.Background(), namespaceFlag) ctx = context.WithValue(ctx, OptsKey{}, Opts{BundlePath: bundlePath, Debug: debugFlag}) ctx = log.WithLogger(ctx, log.G(ctx).WithField("runtime", id)) - - service, err := initFunc(ctx, idFlag, publisher) + ctx, cancel := context.WithCancel(ctx) + service, err := initFunc(ctx, idFlag, publisher, cancel) if err != nil { return err } + switch action { case "delete": logger := logrus.WithFields(logrus.Fields{ "pid": os.Getpid(), "namespace": namespaceFlag, }) - go handleSignals(logger, signals) + go handleSignals(ctx, logger, signals) response, err := service.Cleanup(ctx) if err != nil { return err @@ -171,7 +228,13 @@ } return nil case "start": - address, err := service.StartShim(ctx, idFlag, containerdBinaryFlag, addressFlag) + opts := StartOpts{ + ID: idFlag, + ContainerdBinary: containerdBinaryFlag, + Address: addressFlag, + TTRPCAddress: ttrpcAddress, + } + address, err := service.StartShim(ctx, opts) if err != nil { return err } @@ -180,11 +243,30 @@ } return nil default: - if err := setLogger(ctx, idFlag); err != nil { - return err + if !config.NoSetupLogger { + if err := setLogger(ctx, idFlag); err != nil { + return err + } } client := NewShimClient(ctx, service, signals) - return client.Serve() + if err := client.Serve(); err != nil { + if err != context.Canceled { + return err + } + } + + // NOTE: If the shim server is down(like oom killer), the address + // socket might be leaking. + if address, err := ReadAddress("address"); err == nil { + _ = RemoveSocket(address) + } + + select { + case <-publisher.Done(): + return nil + case <-time.After(5 * time.Second): + return errors.New("publisher not closed") + } } } @@ -228,7 +310,7 @@ dumpStacks(logger) } }() - return handleSignals(logger, s.signals) + return handleSignals(s.context, logger, s.signals) } // serve serves the ttrpc API over a unix socket at the provided path @@ -262,8 +344,3 @@ buf = buf[:stackSize] logger.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) } - -type remoteEventsPublisher struct { - address string - containerdBinaryPath string -} diff -Nru containerd-1.2.6/runtime/v2/shim/shim_linux.go containerd-1.5.9/runtime/v2/shim/shim_linux.go --- containerd-1.2.6/runtime/v2/shim/shim_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,7 +17,7 @@ package shim import ( - "github.com/containerd/containerd/sys" + "github.com/containerd/containerd/sys/reaper" "github.com/containerd/ttrpc" ) @@ -26,5 +26,5 @@ } func subreaper() error { - return sys.SetSubreaper(1) + return reaper.SetSubreaper(1) } diff -Nru containerd-1.2.6/runtime/v2/shim/shim_test.go containerd-1.5.9/runtime/v2/shim/shim_test.go --- containerd-1.2.6/runtime/v2/shim/shim_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,9 +18,33 @@ import ( "context" + "os" + "runtime" "testing" ) +func TestRuntimeWithEmptyMaxEnvProcs(t *testing.T) { + var oldGoMaxProcs = runtime.GOMAXPROCS(0) + defer runtime.GOMAXPROCS(oldGoMaxProcs) + + os.Setenv("GOMAXPROCS", "") + setRuntime() + + var currentGoMaxProcs = runtime.GOMAXPROCS(0) + if currentGoMaxProcs != 2 { + t.Fatal("the max number of procs should be 2") + } +} + +func TestRuntimeWithNonEmptyMaxEnvProcs(t *testing.T) { + os.Setenv("GOMAXPROCS", "not_empty") + setRuntime() + var oldGoMaxProcs2 = runtime.GOMAXPROCS(0) + if oldGoMaxProcs2 != runtime.NumCPU() { + t.Fatal("the max number CPU should be equal to available CPUs") + } +} + func TestShimOptWithValue(t *testing.T) { ctx := context.TODO() ctx = context.WithValue(ctx, OptsKey{}, Opts{Debug: true}) diff -Nru containerd-1.2.6/runtime/v2/shim/shim_unix.go containerd-1.5.9/runtime/v2/shim/shim_unix.go --- containerd-1.2.6/runtime/v2/shim/shim_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,19 +19,15 @@ package shim import ( - "bytes" "context" "io" "net" "os" - "os/exec" "os/signal" "syscall" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/sys/reaper" "github.com/containerd/fifo" - "github.com/containerd/typeurl" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" @@ -39,9 +35,13 @@ // setupSignals creates a new signal handler for all signals and sets the shim as a // sub-reaper so that the container processes are reparented -func setupSignals() (chan os.Signal, error) { +func setupSignals(config Config) (chan os.Signal, error) { signals := make(chan os.Signal, 32) - signal.Notify(signals, unix.SIGTERM, unix.SIGINT, unix.SIGCHLD, unix.SIGPIPE) + smp := []os.Signal{unix.SIGTERM, unix.SIGINT, unix.SIGPIPE} + if !config.NoReaper { + smp = append(smp, unix.SIGCHLD) + } + signal.Notify(signals, smp...) return signals, nil } @@ -58,26 +58,29 @@ l, err = net.FileListener(os.NewFile(3, "socket")) path = "[inherited from parent]" } else { - if len(path) > 106 { - return nil, errors.Errorf("%q: unix socket path too long (> 106)", path) + if len(path) > socketPathLimit { + return nil, errors.Errorf("%q: unix socket path too long (> %d)", path, socketPathLimit) } - l, err = net.Listen("unix", "\x00"+path) + l, err = net.Listen("unix", path) } if err != nil { return nil, err } - logrus.WithField("socket", path).Debug("serving api on abstract socket") + logrus.WithField("socket", path).Debug("serving api on socket") return l, nil } -func handleSignals(logger *logrus.Entry, signals chan os.Signal) error { +func handleSignals(ctx context.Context, logger *logrus.Entry, signals chan os.Signal) error { logger.Info("starting signal loop") for { - for s := range signals { + select { + case <-ctx.Done(): + return ctx.Err() + case s := <-signals: switch s { case unix.SIGCHLD: - if err := Reap(); err != nil { + if err := reaper.Reap(); err != nil { logger.WithError(err).Error("reap exit status") } case unix.SIGPIPE: @@ -87,31 +90,5 @@ } func openLog(ctx context.Context, _ string) (io.Writer, error) { - return fifo.OpenFifo(ctx, "log", unix.O_WRONLY, 0700) -} - -func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error { - ns, _ := namespaces.Namespace(ctx) - encoded, err := typeurl.MarshalAny(event) - if err != nil { - return err - } - data, err := encoded.Marshal() - if err != nil { - return err - } - cmd := exec.CommandContext(ctx, l.containerdBinaryPath, "--address", l.address, "publish", "--topic", topic, "--namespace", ns) - cmd.Stdin = bytes.NewReader(data) - c, err := Default.Start(cmd) - if err != nil { - return err - } - status, err := Default.Wait(cmd, c) - if err != nil { - return err - } - if status != 0 { - return errors.New("failed to publish event") - } - return nil + return fifo.OpenFifoDup2(ctx, "log", unix.O_WRONLY, 0700, int(os.Stderr.Fd())) } diff -Nru containerd-1.2.6/runtime/v2/shim/shim_windows.go containerd-1.5.9/runtime/v2/shim/shim_windows.go --- containerd-1.2.6/runtime/v2/shim/shim_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,283 +19,39 @@ package shim import ( - "bytes" "context" - "fmt" "io" "net" "os" - "os/exec" - "sync" - "unsafe" - winio "github.com/Microsoft/go-winio" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/namespaces" "github.com/containerd/ttrpc" - "github.com/containerd/typeurl" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "golang.org/x/sys/windows" ) -// setupSignals creates a new signal handler for all signals -func setupSignals() (chan os.Signal, error) { - signals := make(chan os.Signal, 32) - return signals, nil +func setupSignals(config Config) (chan os.Signal, error) { + return nil, errors.New("not supported") } func newServer() (*ttrpc.Server, error) { - return ttrpc.NewServer() + return nil, errors.New("not supported") } func subreaper() error { - return nil -} - -type fakeSignal struct { -} - -func (fs *fakeSignal) String() string { - return "" -} - -func (fs *fakeSignal) Signal() { + return errors.New("not supported") } func setupDumpStacks(dump chan<- os.Signal) { - // Windows does not support signals like *nix systems. So instead of - // trapping on SIGUSR1 to dump stacks, we wait on a Win32 event to be - // signaled. ACL'd to builtin administrators and local system - event := "Global\\containerd-shim-runhcs-v1-" + fmt.Sprint(os.Getpid()) - ev, _ := windows.UTF16PtrFromString(event) - sd, err := winio.SddlToSecurityDescriptor("D:P(A;;GA;;;BA)(A;;GA;;;SY)") - if err != nil { - logrus.Errorf("failed to get security descriptor for debug stackdump event %s: %s", event, err.Error()) - return - } - var sa windows.SecurityAttributes - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) - h, err := windows.CreateEvent(&sa, 0, 0, ev) - if h == 0 || err != nil { - logrus.Errorf("failed to create debug stackdump event %s: %s", event, err.Error()) - return - } - go func() { - logrus.Debugf("Stackdump - waiting signal at %s", event) - for { - windows.WaitForSingleObject(h, windows.INFINITE) - dump <- new(fakeSignal) - } - }() } -// serve serves the ttrpc API over a unix socket at the provided path -// this function does not block func serveListener(path string) (net.Listener, error) { - if path == "" { - return nil, errors.New("'socket' must be npipe path") - } - l, err := winio.ListenPipe(path, nil) - if err != nil { - return nil, err - } - logrus.WithField("socket", path).Debug("serving api on npipe socket") - return l, nil -} - -func handleSignals(logger *logrus.Entry, signals chan os.Signal) error { - logger.Info("starting signal loop") - - for { - for s := range signals { - switch s { - case os.Interrupt: - } - } - } -} - -var _ = (io.WriterTo)(&blockingBuffer{}) -var _ = (io.Writer)(&blockingBuffer{}) - -// blockingBuffer implements the `io.Writer` and `io.WriterTo` interfaces. Once -// `capacity` is reached the calls to `Write` will block until a successful call -// to `WriterTo` frees up the buffer space. -// -// Note: This has the same threadding semantics as bytes.Buffer with no -// additional locking so multithreading is not supported. -type blockingBuffer struct { - c *sync.Cond - - capacity int - - buffer bytes.Buffer -} - -func newBlockingBuffer(capacity int) *blockingBuffer { - return &blockingBuffer{ - c: sync.NewCond(&sync.Mutex{}), - capacity: capacity, - } -} - -func (bb *blockingBuffer) Len() int { - bb.c.L.Lock() - defer bb.c.L.Unlock() - return bb.buffer.Len() -} - -func (bb *blockingBuffer) Write(p []byte) (int, error) { - if len(p) > bb.capacity { - return 0, errors.Errorf("len(p) (%d) too large for capacity (%d)", len(p), bb.capacity) - } - - bb.c.L.Lock() - for bb.buffer.Len()+len(p) > bb.capacity { - bb.c.Wait() - } - defer bb.c.L.Unlock() - return bb.buffer.Write(p) + return nil, errors.New("not supported") } -func (bb *blockingBuffer) WriteTo(w io.Writer) (int64, error) { - bb.c.L.Lock() - defer bb.c.L.Unlock() - defer bb.c.Signal() - return bb.buffer.WriteTo(w) -} - -// deferredShimWriteLogger exists to solve the upstream loggin issue presented -// by using Windows Named Pipes for logging. When containerd restarts it tries -// to reconnect to any shims. This means that the connection to the logger will -// be severed but when containerd starts up it should reconnect and start -// logging again. We abstract all of this logic behind what looks like a simple -// `io.Writer` that can reconnect in the lifetime and buffers logs while -// disconnected. -type deferredShimWriteLogger struct { - mu sync.Mutex - - ctx context.Context - - connected bool - aborted bool - - buffer *blockingBuffer - - l net.Listener - c net.Conn - conerr error -} - -// beginAccept issues an accept to wait for a connection. Once a connection -// occurs drains any outstanding buffer. While draining the buffer any writes -// are blocked. If the buffer fails to fully drain due to a connection drop a -// call to `beginAccept` is re-issued waiting for another connection from -// containerd. -func (dswl *deferredShimWriteLogger) beginAccept() { - dswl.mu.Lock() - if dswl.connected { - return - } - dswl.mu.Unlock() - - c, err := dswl.l.Accept() - if err == winio.ErrPipeListenerClosed { - dswl.mu.Lock() - dswl.aborted = true - dswl.l.Close() - dswl.conerr = errors.New("connection closed") - dswl.mu.Unlock() - return - } - dswl.mu.Lock() - dswl.connected = true - dswl.c = c - - // Drain the buffer - if dswl.buffer.Len() > 0 { - _, err := dswl.buffer.WriteTo(dswl.c) - if err != nil { - // We lost our connection draining the buffer. - dswl.connected = false - dswl.c.Close() - go dswl.beginAccept() - } - } - dswl.mu.Unlock() -} - -func (dswl *deferredShimWriteLogger) Write(p []byte) (int, error) { - dswl.mu.Lock() - defer dswl.mu.Unlock() - - if dswl.aborted { - return 0, dswl.conerr - } - - if dswl.connected { - // We have a connection. beginAccept would have drained the buffer so we just write our data to - // the connection directly. - written, err := dswl.c.Write(p) - if err != nil { - // We lost the connection. - dswl.connected = false - dswl.c.Close() - go dswl.beginAccept() - - // We weren't able to write the full `p` bytes. Buffer the rest - if written != len(p) { - w, err := dswl.buffer.Write(p[written:]) - if err != nil { - // We failed to buffer. Return this error - return written + w, err - } - written += w - } - } - - return written, nil - } - - // We are disconnected. Buffer the contents. - return dswl.buffer.Write(p) -} - -// openLog on Windows acts as the server of the log pipe. This allows the -// containerd daemon to independently restart and reconnect to the logs. -func openLog(ctx context.Context, id string) (io.Writer, error) { - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return nil, err - } - - dswl := &deferredShimWriteLogger{ - ctx: ctx, - buffer: newBlockingBuffer(64 * 1024), // 64KB, - } - l, err := winio.ListenPipe(fmt.Sprintf("\\\\.\\pipe\\containerd-shim-%s-%s-log", ns, id), nil) - if err != nil { - return nil, err - } - dswl.l = l - go dswl.beginAccept() - return dswl, nil +func handleSignals(ctx context.Context, logger *logrus.Entry, signals chan os.Signal) error { + return errors.New("not supported") } -func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error { - ns, _ := namespaces.Namespace(ctx) - encoded, err := typeurl.MarshalAny(event) - if err != nil { - return err - } - data, err := encoded.Marshal() - if err != nil { - return err - } - cmd := exec.CommandContext(ctx, l.containerdBinaryPath, "--address", l.address, "publish", "--topic", topic, "--namespace", ns) - cmd.Stdin = bytes.NewReader(data) - return cmd.Run() +func openLog(ctx context.Context, _ string) (io.Writer, error) { + return nil, errors.New("not supported") } diff -Nru containerd-1.2.6/runtime/v2/shim/shim_windows_test.go containerd-1.5.9/runtime/v2/shim/shim_windows_test.go --- containerd-1.2.6/runtime/v2/shim/shim_windows_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/shim_windows_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -// +build windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package shim - -import ( - "bytes" - "context" - "fmt" - "io" - "testing" - "time" - - winio "github.com/Microsoft/go-winio" - "github.com/containerd/containerd/namespaces" -) - -func readValueFrom(rdr io.Reader, expectedStr string, t *testing.T) { - expected := []byte(expectedStr) - actual := make([]byte, len(expected)) - read, err := rdr.Read(actual) - if err != nil { - t.Fatalf("failed to read with: %v", err) - } - if read != len(expected) { - t.Fatalf("failed to read len %v bytes read: %v", len(expected), read) - } - if !bytes.Equal(expected, actual) { - t.Fatalf("expected '%v' != actual '%v'", expected, actual) - } -} - -func writeValueTo(wr io.Writer, value string) { - expected := []byte(value) - written, err := wr.Write(expected) - if err != nil { - panic(fmt.Sprintf("failed to write with: %v", err)) - } - if len(expected) != written { - panic(fmt.Sprintf("failed to write len %v bytes wrote: %v", len(expected), written)) - } -} - -func runOneTest(ns, id string, writer io.Writer, t *testing.T) { - // Write on closed - go writeValueTo(writer, "Hello World!") - - // Connect - c, err := winio.DialPipe(fmt.Sprintf("\\\\.\\pipe\\containerd-shim-%s-%s-log", ns, id), nil) - if err != nil { - t.Fatal("should have successfully connected to log") - } - defer c.Close() - - // Read the deferred buffer. - readValueFrom(c, "Hello World!", t) - - go writeValueTo(writer, "Hello Next!") - readValueFrom(c, "Hello Next!", t) -} - -func TestOpenLog(t *testing.T) { - ns := "openlognamespace" - id := "openlogid" - ctx := namespaces.WithNamespace(context.TODO(), ns) - writer, err := openLog(ctx, id) - if err != nil { - t.Fatalf("failed openLog with %v", err) - } - - // Do three iterations of write/open/read/write/read/close - for i := 0; i < 3; i++ { - runOneTest(ns, id, writer, t) - } -} - -func TestBlockingBufferWriteNotEnoughCapacity(t *testing.T) { - bb := newBlockingBuffer(5) - val := make([]byte, 10) - w, err := bb.Write(val) - if err == nil { - t.Fatal("write should of failed capacity check") - } - if w != 0 { - t.Fatal("write should of not written any bytes on failed capacity check") - } -} - -func TestBlockingBufferLoop(t *testing.T) { - nameBytes := []byte(t.Name()) - nameBytesLen := len(nameBytes) - bb := newBlockingBuffer(nameBytesLen) - for i := 0; i < 3; i++ { - writeValueTo(bb, t.Name()) - if bb.Len() != nameBytesLen { - t.Fatalf("invalid buffer bytes len after write: (%d)", bb.buffer.Len()) - } - buf := &bytes.Buffer{} - w, err := bb.WriteTo(buf) - if err != nil { - t.Fatalf("should not have failed WriteTo: (%v)", err) - } - if w != int64(nameBytesLen) { - t.Fatalf("should have written all bytes, wrote (%d)", w) - } - readValueFrom(buf, t.Name(), t) - if bb.Len() != 0 { - t.Fatalf("invalid buffer bytes len after read: (%d)", bb.buffer.Len()) - } - } -} -func TestBlockingBuffer(t *testing.T) { - nameBytes := []byte(t.Name()) - nameBytesLen := len(nameBytes) - bb := newBlockingBuffer(nameBytesLen) - - // Write the first value - writeValueTo(bb, t.Name()) - if bb.Len() != nameBytesLen { - t.Fatalf("buffer len != %d", nameBytesLen) - } - - // We should now have filled capacity the next write should block - done := make(chan struct{}) - go func() { - writeValueTo(bb, t.Name()) - close(done) - }() - select { - case <-done: - t.Fatal("third write should of blocked") - case <-time.After(10 * time.Millisecond): - buff := &bytes.Buffer{} - _, err := bb.WriteTo(buff) - if err != nil { - t.Fatalf("failed to drain buffer with: %v", err) - } - if bb.Len() != 0 { - t.Fatalf("buffer len != %d", 0) - } - readValueFrom(buff, t.Name(), t) - } - <-done - if bb.Len() != nameBytesLen { - t.Fatalf("buffer len != %d", nameBytesLen) - } -} diff -Nru containerd-1.2.6/runtime/v2/shim/util.go containerd-1.5.9/runtime/v2/shim/util.go --- containerd-1.2.6/runtime/v2/shim/util.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/util.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,23 +17,28 @@ package shim import ( + "bytes" "context" "fmt" + "io/ioutil" "net" "os" "os/exec" "path/filepath" "strings" + "sync" "time" "github.com/containerd/containerd/namespaces" + "github.com/gogo/protobuf/proto" + "github.com/gogo/protobuf/types" "github.com/pkg/errors" ) -const shimBinaryFormat = "containerd-shim-%s-%s" +var runtimePaths sync.Map // Command returns the shim command with the provided args and configuration -func Command(ctx context.Context, runtime, containerdAddress, path string, cmdArgs ...string) (*exec.Cmd, error) { +func Command(ctx context.Context, runtime, containerdAddress, containerdTTRPCAddress, path string, opts *types.Any, cmdArgs ...string) (*exec.Cmd, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err @@ -52,23 +57,64 @@ if name == "" { return nil, fmt.Errorf("invalid runtime name %s, correct runtime name should format like io.containerd.runc.v1", runtime) } + var cmdPath string - var lerr error - if cmdPath, lerr = exec.LookPath(name); lerr != nil { - if eerr, ok := lerr.(*exec.Error); ok { - if eerr.Err == exec.ErrNotFound { - return nil, errors.Wrapf(os.ErrNotExist, "runtime %q binary not installed %q", runtime, name) + cmdPathI, cmdPathFound := runtimePaths.Load(name) + if cmdPathFound { + cmdPath = cmdPathI.(string) + } else { + var lerr error + binaryPath := BinaryPath(runtime) + if _, serr := os.Stat(binaryPath); serr == nil { + cmdPath = binaryPath + } + + if cmdPath == "" { + if cmdPath, lerr = exec.LookPath(name); lerr != nil { + if eerr, ok := lerr.(*exec.Error); ok { + if eerr.Err == exec.ErrNotFound { + // LookPath only finds current directory matches based on + // the callers current directory but the caller is not + // likely in the same directory as the containerd + // executables. Instead match the calling binaries path + // (containerd) and see if they are side by side. If so + // execute the shim found there. + testPath := filepath.Join(filepath.Dir(self), name) + if _, serr := os.Stat(testPath); serr == nil { + cmdPath = testPath + } + if cmdPath == "" { + return nil, errors.Wrapf(os.ErrNotExist, "runtime %q binary not installed %q", runtime, name) + } + } + } } } + cmdPath, err = filepath.Abs(cmdPath) + if err != nil { + return nil, err + } + if cmdPathI, cmdPathFound = runtimePaths.LoadOrStore(name, cmdPath); cmdPathFound { + // We didn't store cmdPath we loaded an already cached value. Use it. + cmdPath = cmdPathI.(string) + } } - cmdPath, err = filepath.Abs(cmdPath) - if err != nil { - return nil, err - } + cmd := exec.Command(cmdPath, args...) cmd.Dir = path - cmd.Env = append(os.Environ(), "GOMAXPROCS=2") + cmd.Env = append( + os.Environ(), + "GOMAXPROCS=2", + fmt.Sprintf("%s=%s", ttrpcAddressEnv, containerdTTRPCAddress), + ) cmd.SysProcAttr = getSysProcAttr() + if opts != nil { + d, err := proto.Marshal(opts) + if err != nil { + return nil, err + } + cmd.Stdin = bytes.NewReader(d) + } return cmd, nil } @@ -84,6 +130,20 @@ return fmt.Sprintf(shimBinaryFormat, parts[len(parts)-2], parts[len(parts)-1]) } +// BinaryPath returns the full path for the shim binary from the runtime name, +// empty string returns means runtime name is invalid +func BinaryPath(runtime string) string { + dir := filepath.Dir(runtime) + binary := BinaryName(runtime) + + path, err := filepath.Abs(filepath.Join(dir, binary)) + if err != nil { + return "" + } + + return path +} + // Connect to the provided address func Connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) { return d(address, 100*time.Second) @@ -126,3 +186,22 @@ } return os.Rename(tempPath, path) } + +// ErrNoAddress is returned when the address file has no content +var ErrNoAddress = errors.New("no shim address") + +// ReadAddress returns the shim's socket address from the path +func ReadAddress(path string) (string, error) { + path, err := filepath.Abs(path) + if err != nil { + return "", err + } + data, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + if len(data) == 0 { + return "", ErrNoAddress + } + return string(data), nil +} diff -Nru containerd-1.2.6/runtime/v2/shim/util_unix.go containerd-1.5.9/runtime/v2/shim/util_unix.go --- containerd-1.2.6/runtime/v2/shim/util_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/util_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,51 +20,148 @@ import ( "context" + "crypto/sha256" + "fmt" "net" + "os" "path/filepath" "strings" "syscall" "time" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/dialer" "github.com/containerd/containerd/sys" "github.com/pkg/errors" ) +const ( + shimBinaryFormat = "containerd-shim-%s-%s" + socketPathLimit = 106 +) + func getSysProcAttr() *syscall.SysProcAttr { return &syscall.SysProcAttr{ Setpgid: true, } } -// SetScore sets the oom score for a process -func SetScore(pid int) error { - return sys.SetOOMScore(pid, sys.OOMScoreMaxKillable) +// AdjustOOMScore sets the OOM score for the process to the parents OOM score +1 +// to ensure that they parent has a lower* score than the shim +// if not already at the maximum OOM Score +func AdjustOOMScore(pid int) error { + parent := os.Getppid() + score, err := sys.GetOOMScoreAdj(parent) + if err != nil { + return errors.Wrap(err, "get parent OOM score") + } + shimScore := score + 1 + if err := sys.AdjustOOMScore(pid, shimScore); err != nil { + return errors.Wrap(err, "set shim OOM score") + } + return nil } -// SocketAddress returns an abstract socket address -func SocketAddress(ctx context.Context, id string) (string, error) { +const socketRoot = "/run/containerd" + +// SocketAddress returns a socket address +func SocketAddress(ctx context.Context, socketPath, id string) (string, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return "", err } - return filepath.Join(string(filepath.Separator), "containerd-shim", ns, id, "shim.sock"), nil + d := sha256.Sum256([]byte(filepath.Join(socketPath, ns, id))) + return fmt.Sprintf("unix://%s/%x", filepath.Join(socketRoot, "s"), d), nil } -// AnonDialer returns a dialer for an abstract socket +// AnonDialer returns a dialer for a socket func AnonDialer(address string, timeout time.Duration) (net.Conn, error) { - address = strings.TrimPrefix(address, "unix://") - return net.DialTimeout("unix", "\x00"+address, timeout) + return dialer.Dialer(socket(address).path(), timeout) +} + +// AnonReconnectDialer returns a dialer for an existing socket on reconnection +func AnonReconnectDialer(address string, timeout time.Duration) (net.Conn, error) { + return AnonDialer(address, timeout) } // NewSocket returns a new socket func NewSocket(address string) (*net.UnixListener, error) { - if len(address) > 106 { - return nil, errors.Errorf("%q: unix socket path too long (> 106)", address) + var ( + sock = socket(address) + path = sock.path() + ) + if !sock.isAbstract() { + if err := os.MkdirAll(filepath.Dir(path), 0600); err != nil { + return nil, errors.Wrapf(err, "%s", path) + } } - l, err := net.Listen("unix", "\x00"+address) + l, err := net.Listen("unix", path) if err != nil { - return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address) + return nil, err + } + if err := os.Chmod(path, 0600); err != nil { + os.Remove(sock.path()) + l.Close() + return nil, err } return l.(*net.UnixListener), nil } + +const abstractSocketPrefix = "\x00" + +type socket string + +func (s socket) isAbstract() bool { + return !strings.HasPrefix(string(s), "unix://") +} + +func (s socket) path() string { + path := strings.TrimPrefix(string(s), "unix://") + // if there was no trim performed, we assume an abstract socket + if len(path) == len(s) { + path = abstractSocketPrefix + path + } + return path +} + +// RemoveSocket removes the socket at the specified address if +// it exists on the filesystem +func RemoveSocket(address string) error { + sock := socket(address) + if !sock.isAbstract() { + return os.Remove(sock.path()) + } + return nil +} + +// SocketEaddrinuse returns true if the provided error is caused by the +// EADDRINUSE error number +func SocketEaddrinuse(err error) bool { + netErr, ok := err.(*net.OpError) + if !ok { + return false + } + if netErr.Op != "listen" { + return false + } + syscallErr, ok := netErr.Err.(*os.SyscallError) + if !ok { + return false + } + errno, ok := syscallErr.Err.(syscall.Errno) + if !ok { + return false + } + return errno == syscall.EADDRINUSE +} + +// CanConnect returns true if the socket provided at the address +// is accepting new connections +func CanConnect(address string) bool { + conn, err := AnonDialer(address, 100*time.Millisecond) + if err != nil { + return false + } + conn.Close() + return true +} diff -Nru containerd-1.2.6/runtime/v2/shim/util_windows.go containerd-1.5.9/runtime/v2/shim/util_windows.go --- containerd-1.2.6/runtime/v2/shim/util_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim/util_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,73 +18,70 @@ import ( "context" - "fmt" "net" "os" "syscall" "time" winio "github.com/Microsoft/go-winio" - "github.com/containerd/containerd/namespaces" "github.com/pkg/errors" ) -func getSysProcAttr() *syscall.SysProcAttr { - return nil -} +const shimBinaryFormat = "containerd-shim-%s-%s.exe" -// SetScore sets the oom score for a process -func SetScore(pid int) error { +func getSysProcAttr() *syscall.SysProcAttr { return nil } -// SocketAddress returns a npipe address -func SocketAddress(ctx context.Context, id string) (string, error) { - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return "", err +// AnonReconnectDialer returns a dialer for an existing npipe on containerd reconnection +func AnonReconnectDialer(address string, timeout time.Duration) (net.Conn, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + c, err := winio.DialPipeContext(ctx, address) + if os.IsNotExist(err) { + return nil, errors.Wrap(os.ErrNotExist, "npipe not found on reconnect") + } else if err == context.DeadlineExceeded { + return nil, errors.Wrapf(err, "timed out waiting for npipe %s", address) + } else if err != nil { + return nil, err } - return fmt.Sprintf("\\\\.\\pipe\\containerd-shim-%s-%s-pipe", ns, id), nil + return c, nil } // AnonDialer returns a dialer for a npipe func AnonDialer(address string, timeout time.Duration) (net.Conn, error) { - var c net.Conn - var lastError error - timedOutError := errors.Errorf("timed out waiting for npipe %s", address) - start := time.Now() + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // If there is nobody serving the pipe we limit the timeout for this case to + // 5 seconds because any shim that would serve this endpoint should serve it + // within 5 seconds. + serveTimer := time.NewTimer(5 * time.Second) + defer serveTimer.Stop() for { - remaining := timeout - time.Since(start) - if remaining <= 0 { - lastError = timedOutError - break + c, err := winio.DialPipeContext(ctx, address) + if err != nil { + if os.IsNotExist(err) { + select { + case <-serveTimer.C: + return nil, errors.Wrap(os.ErrNotExist, "pipe not found before timeout") + default: + // Wait 10ms for the shim to serve and try again. + time.Sleep(10 * time.Millisecond) + continue + } + } else if err == context.DeadlineExceeded { + return nil, errors.Wrapf(err, "timed out waiting for npipe %s", address) + } + return nil, err } - c, lastError = winio.DialPipe(address, &remaining) - if lastError == nil { - break - } - if !os.IsNotExist(lastError) { - break - } - // There is nobody serving the pipe. We limit the timeout for this case - // to 5 seconds because any shim that would serve this endpoint should - // serve it within 5 seconds. We use the passed in timeout for the - // `DialPipe` timeout if the pipe exists however to give the pipe time - // to `Accept` the connection. - if time.Since(start) >= 5*time.Second { - lastError = timedOutError - break - } - time.Sleep(10 * time.Millisecond) + return c, nil } - return c, lastError } -// NewSocket returns a new npipe listener -func NewSocket(address string) (net.Listener, error) { - l, err := winio.ListenPipe(address, nil) - if err != nil { - return nil, errors.Wrapf(err, "failed to listen to npipe %s", address) - } - return l, nil +// RemoveSocket removes the socket at the specified address if +// it exists on the filesystem +func RemoveSocket(address string) error { + return nil } diff -Nru containerd-1.2.6/runtime/v2/shim.go containerd-1.5.9/runtime/v2/shim.go --- containerd-1.2.6/runtime/v2/shim.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,14 +31,29 @@ "github.com/containerd/containerd/events/exchange" "github.com/containerd/containerd/identifiers" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/runtime" client "github.com/containerd/containerd/runtime/v2/shim" "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/ttrpc" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) +const ( + loadTimeout = "io.containerd.timeout.shim.load" + cleanupTimeout = "io.containerd.timeout.shim.cleanup" + shutdownTimeout = "io.containerd.timeout.shim.shutdown" +) + +func init() { + timeout.Set(loadTimeout, 5*time.Second) + timeout.Set(cleanupTimeout, 5*time.Second) + timeout.Set(shutdownTimeout, 3*time.Second) +} + func loadAddress(path string) (string, error) { data, err := ioutil.ReadFile(path) if err != nil { @@ -47,18 +62,29 @@ return string(data), nil } -func loadShim(ctx context.Context, bundle *Bundle, events *exchange.Exchange, rt *runtime.TaskList) (_ *shim, err error) { +func loadShim(ctx context.Context, bundle *Bundle, events *exchange.Exchange, rt *runtime.TaskList, onClose func()) (_ *shim, err error) { address, err := loadAddress(filepath.Join(bundle.Path, "address")) if err != nil { return nil, err } - conn, err := client.Connect(address, client.AnonDialer) + conn, err := client.Connect(address, client.AnonReconnectDialer) if err != nil { return nil, err } - f, err := openShimLog(ctx, bundle) + defer func() { + if err != nil { + conn.Close() + } + }() + shimCtx, cancelShimLog := context.WithCancel(ctx) + defer func() { + if err != nil { + cancelShimLog() + } + }() + f, err := openShimLog(shimCtx, bundle, client.AnonReconnectDialer) if err != nil { - return nil, errors.Wrap(err, "open shim log pipe") + return nil, errors.Wrap(err, "open shim log pipe when reload") } defer func() { if err != nil { @@ -70,13 +96,26 @@ // copy the shim's logs to containerd's output go func() { defer f.Close() - if _, err := io.Copy(os.Stderr, f); err != nil { - log.G(ctx).WithError(err).Error("copy shim log") + _, err := io.Copy(os.Stderr, f) + // To prevent flood of error messages, the expected error + // should be reset, like os.ErrClosed or os.ErrNotExist, which + // depends on platform. + err = checkCopyShimLogError(ctx, err) + if err != nil { + log.G(ctx).WithError(err).Error("copy shim log after reload") + } + }() + onCloseWithShimLog := func() { + onClose() + cancelShimLog() + f.Close() + } + client := ttrpc.NewClient(conn, ttrpc.WithOnClose(onCloseWithShimLog)) + defer func() { + if err != nil { + client.Close() } }() - - client := ttrpc.NewClient(conn) - client.OnClose(func() { conn.Close() }) s := &shim{ client: client, task: task.NewTaskClient(client), @@ -84,12 +123,66 @@ events: events, rtTasks: rt, } + ctx, cancel := timeout.WithContext(ctx, loadTimeout) + defer cancel() if err := s.Connect(ctx); err != nil { return nil, err } return s, nil } +func cleanupAfterDeadShim(ctx context.Context, id, ns string, rt *runtime.TaskList, events *exchange.Exchange, binaryCall *binary) { + ctx = namespaces.WithNamespace(ctx, ns) + ctx, cancel := timeout.WithContext(ctx, cleanupTimeout) + defer cancel() + + log.G(ctx).WithFields(logrus.Fields{ + "id": id, + "namespace": ns, + }).Warn("cleaning up after shim disconnected") + response, err := binaryCall.Delete(ctx) + if err != nil { + log.G(ctx).WithError(err).WithFields(logrus.Fields{ + "id": id, + "namespace": ns, + }).Warn("failed to clean up after shim disconnected") + } + + if _, err := rt.Get(ctx, id); err != nil { + // Task was never started or was already successfully deleted + // No need to publish events + return + } + + var ( + pid uint32 + exitStatus uint32 + exitedAt time.Time + ) + if response != nil { + pid = response.Pid + exitStatus = response.Status + exitedAt = response.Timestamp + } else { + exitStatus = 255 + exitedAt = time.Now() + } + events.Publish(ctx, runtime.TaskExitEventTopic, &eventstypes.TaskExit{ + ContainerID: id, + ID: id, + Pid: pid, + ExitStatus: exitStatus, + ExitedAt: exitedAt, + }) + + events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ + ContainerID: id, + Pid: pid, + ExitStatus: exitStatus, + ExitedAt: exitedAt, + }) +} + type shim struct { bundle *Bundle client *ttrpc.Client @@ -100,7 +193,9 @@ } func (s *shim) Connect(ctx context.Context) error { - response, err := s.task.Connect(ctx, &task.ConnectRequest{}) + response, err := s.task.Connect(ctx, &task.ConnectRequest{ + ID: s.ID(), + }) if err != nil { return err } @@ -112,26 +207,16 @@ _, err := s.task.Shutdown(ctx, &task.ShutdownRequest{ ID: s.ID(), }) - if err != nil && err != ttrpc.ErrClosed { + if err != nil && !errors.Is(err, ttrpc.ErrClosed) { return errdefs.FromGRPC(err) } return nil } func (s *shim) waitShutdown(ctx context.Context) error { - dead := make(chan struct{}) - go func() { - if err := s.Shutdown(ctx); err != nil { - log.G(ctx).WithError(err).Error("shim shutdown error") - } - close(dead) - }() - select { - case <-time.After(3 * time.Second): - return errors.New("failed to shutdown shim in time") - case <-dead: - return nil - } + ctx, cancel := timeout.WithContext(ctx, shutdownTimeout) + defer cancel() + return s.Shutdown(ctx) } // ID of the shim/task @@ -139,6 +224,11 @@ return s.bundle.ID } +// PID of the task +func (s *shim) PID() uint32 { + return uint32(s.taskPid) +} + func (s *shim) Namespace() string { return s.bundle.Namespace } @@ -148,27 +238,48 @@ } func (s *shim) Delete(ctx context.Context) (*runtime.Exit, error) { - response, err := s.task.Delete(ctx, &task.DeleteRequest{ + response, shimErr := s.task.Delete(ctx, &task.DeleteRequest{ ID: s.ID(), }) - if err != nil { - return nil, errdefs.FromGRPC(err) + if shimErr != nil { + log.G(ctx).WithField("id", s.ID()).WithError(shimErr).Debug("failed to delete task") + if !errors.Is(shimErr, ttrpc.ErrClosed) { + shimErr = errdefs.FromGRPC(shimErr) + if !errdefs.IsNotFound(shimErr) { + return nil, shimErr + } + } } - if err := s.waitShutdown(ctx); err != nil { - return nil, err + + // NOTE: If the shim has been killed and ttrpc connection has been + // closed, the shimErr will not be nil. For this case, the event + // subscriber, like moby/moby, might have received the exit or delete + // events. Just in case, we should allow ttrpc-callback-on-close to + // send the exit and delete events again. And the exit status will + // depend on result of shimV2.Delete. + // + // If not, the shim has been delivered the exit and delete events. + // So we should remove the record and prevent duplicate events from + // ttrpc-callback-on-close. + if shimErr == nil { + s.rtTasks.Delete(ctx, s.ID()) } - if err := s.bundle.Delete(); err != nil { - return nil, err + + if err := s.waitShutdown(ctx); err != nil { + log.G(ctx).WithField("id", s.ID()).WithError(err).Error("failed to shutdown shim") } + s.Close() + s.client.UserOnCloseWait(ctx) + // remove self from the runtime task list // this seems dirty but it cleans up the API across runtimes, tasks, and the service s.rtTasks.Delete(ctx, s.ID()) - s.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ - ContainerID: s.ID(), - ExitStatus: response.ExitStatus, - ExitedAt: response.ExitedAt, - Pid: response.Pid, - }) + if err := s.bundle.Delete(); err != nil { + log.G(ctx).WithField("id", s.ID()).WithError(err).Error("failed to delete bundle") + } + if shimErr != nil { + return nil, shimErr + } return &runtime.Exit{ Status: response.ExitStatus, Timestamp: response.ExitedAt, @@ -212,9 +323,6 @@ }); err != nil { return errdefs.FromGRPC(err) } - s.events.Publish(ctx, runtime.TaskPausedEventTopic, &eventstypes.TaskPaused{ - ContainerID: s.ID(), - }) return nil } @@ -224,9 +332,6 @@ }); err != nil { return errdefs.FromGRPC(err) } - s.events.Publish(ctx, runtime.TaskResumedEventTopic, &eventstypes.TaskResumed{ - ContainerID: s.ID(), - }) return nil } @@ -238,10 +343,6 @@ return errdefs.FromGRPC(err) } s.taskPid = int(response.Pid) - s.events.Publish(ctx, runtime.TaskStartEventTopic, &eventstypes.TaskStart{ - ContainerID: s.ID(), - Pid: uint32(s.taskPid), - }) return nil } @@ -334,22 +435,21 @@ func (s *shim) Checkpoint(ctx context.Context, path string, options *ptypes.Any) error { request := &task.CheckpointTaskRequest{ + ID: s.ID(), Path: path, Options: options, } if _, err := s.task.Checkpoint(ctx, request); err != nil { return errdefs.FromGRPC(err) } - s.events.Publish(ctx, runtime.TaskCheckpointedEventTopic, &eventstypes.TaskCheckpointed{ - ContainerID: s.ID(), - }) return nil } -func (s *shim) Update(ctx context.Context, resources *ptypes.Any) error { +func (s *shim) Update(ctx context.Context, resources *ptypes.Any, annotations map[string]string) error { if _, err := s.task.Update(ctx, &task.UpdateTaskRequest{ - ID: s.ID(), - Resources: resources, + ID: s.ID(), + Resources: resources, + Annotations: annotations, }); err != nil { return errdefs.FromGRPC(err) } @@ -367,10 +467,14 @@ } func (s *shim) Process(ctx context.Context, id string) (runtime.Process, error) { - return &process{ + p := &process{ id: id, shim: s, - }, nil + } + if _, err := p.State(ctx); err != nil { + return nil, err + } + return p, nil } func (s *shim) State(ctx context.Context) (runtime.State, error) { @@ -378,7 +482,7 @@ ID: s.ID(), }) if err != nil { - if errors.Cause(err) != ttrpc.ErrClosed { + if !errors.Is(err, ttrpc.ErrClosed) { return runtime.State{}, errdefs.FromGRPC(err) } return runtime.State{}, errdefs.ErrNotFound diff -Nru containerd-1.2.6/runtime/v2/shim_unix.go containerd-1.5.9/runtime/v2/shim_unix.go --- containerd-1.2.6/runtime/v2/shim_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,12 +21,27 @@ import ( "context" "io" + "net" + "os" "path/filepath" + "time" "github.com/containerd/fifo" + "github.com/pkg/errors" "golang.org/x/sys/unix" ) -func openShimLog(ctx context.Context, bundle *Bundle) (io.ReadCloser, error) { - return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDWR|unix.O_CREAT, 0700) +func openShimLog(ctx context.Context, bundle *Bundle, _ func(string, time.Duration) (net.Conn, error)) (io.ReadCloser, error) { + return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDWR|unix.O_CREAT|unix.O_NONBLOCK, 0700) +} + +func checkCopyShimLogError(ctx context.Context, err error) error { + select { + case <-ctx.Done(): + if err == fifo.ErrReadClosed || errors.Is(err, os.ErrClosed) { + return nil + } + default: + } + return err } diff -Nru containerd-1.2.6/runtime/v2/shim_unix_test.go containerd-1.5.9/runtime/v2/shim_unix_test.go --- containerd-1.2.6/runtime/v2/shim_unix_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim_unix_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,53 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + "os" + "testing" + + "github.com/containerd/fifo" +) + +func TestCheckCopyShimLogError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + if err := checkCopyShimLogError(ctx, fifo.ErrReadClosed); err != fifo.ErrReadClosed { + t.Fatalf("should return the actual error before context is done, but %v", err) + } + if err := checkCopyShimLogError(ctx, nil); err != nil { + t.Fatalf("should return the actual error before context is done, but %v", err) + } + + cancel() + + if err := checkCopyShimLogError(ctx, fifo.ErrReadClosed); err != nil { + t.Fatalf("should return nil when error is ErrReadClosed after context is done, but %v", err) + } + if err := checkCopyShimLogError(ctx, nil); err != nil { + t.Fatalf("should return the actual error after context is done, but %v", err) + } + if err := checkCopyShimLogError(ctx, os.ErrClosed); err != nil { + t.Fatalf("should return the actual error after context is done, but %v", err) + } + if err := checkCopyShimLogError(ctx, fifo.ErrRdFrmWRONLY); err != fifo.ErrRdFrmWRONLY { + t.Fatalf("should return the actual error after context is done, but %v", err) + } +} diff -Nru containerd-1.2.6/runtime/v2/shim_windows.go containerd-1.5.9/runtime/v2/shim_windows.go --- containerd-1.2.6/runtime/v2/shim_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,11 +21,11 @@ "fmt" "io" "net" + "os" "sync" "time" "github.com/containerd/containerd/namespaces" - client "github.com/containerd/containerd/runtime/v2/shim" "github.com/pkg/errors" ) @@ -63,7 +63,7 @@ // openShimLog on Windows acts as the client of the log pipe. In this way the // containerd daemon can reconnect to the shim log stream if it is restarted. -func openShimLog(ctx context.Context, bundle *Bundle) (io.ReadCloser, error) { +func openShimLog(ctx context.Context, bundle *Bundle, dialer func(string, time.Duration) (net.Conn, error)) (io.ReadCloser, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err @@ -73,15 +73,25 @@ } dpc.wg.Add(1) go func() { - c, conerr := client.AnonDialer( + c, conerr := dialer( fmt.Sprintf("\\\\.\\pipe\\containerd-shim-%s-%s-log", ns, bundle.ID), time.Second*10, ) if conerr != nil { - dpc.conerr = errors.Wrap(err, "failed to connect to shim log") + dpc.conerr = errors.Wrap(conerr, "failed to connect to shim log") } dpc.c = c dpc.wg.Done() }() return dpc, nil } + +func checkCopyShimLogError(ctx context.Context, err error) error { + // When using a multi-container shim the 2nd to Nth container in the + // shim will not have a separate log pipe. Ignore the failure log + // message here when the shim connect times out. + if errors.Is(err, os.ErrNotExist) { + return nil + } + return err +} diff -Nru containerd-1.2.6/runtime/v2/shim_windows_test.go containerd-1.5.9/runtime/v2/shim_windows_test.go --- containerd-1.2.6/runtime/v2/shim_windows_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/runtime/v2/shim_windows_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,41 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "context" + "os" + "testing" + + "github.com/pkg/errors" +) + +func TestCheckCopyShimLogError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + testError := errors.New("test error") + + if err := checkCopyShimLogError(ctx, nil); err != nil { + t.Fatalf("should return the actual error except ErrNotExist, but %v", err) + } + if err := checkCopyShimLogError(ctx, testError); err != testError { + t.Fatalf("should return the actual error except ErrNotExist, but %v", err) + } + if err := checkCopyShimLogError(ctx, os.ErrNotExist); err != nil { + t.Fatalf("should return nil for ErrNotExist, but %v", err) + } +} diff -Nru containerd-1.2.6/runtime/v2/task/shim.pb.go containerd-1.5.9/runtime/v2/task/shim.pb.go --- containerd-1.2.6/runtime/v2/task/shim.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/task/shim.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,64 +1,25 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: github.com/containerd/containerd/runtime/v2/task/shim.proto -/* - Package task is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/runtime/v2/task/shim.proto - - It has these top-level messages: - CreateTaskRequest - CreateTaskResponse - DeleteRequest - DeleteResponse - ExecProcessRequest - ExecProcessResponse - ResizePtyRequest - StateRequest - StateResponse - KillRequest - CloseIORequest - PidsRequest - PidsResponse - CheckpointTaskRequest - UpdateTaskRequest - StartRequest - StartResponse - WaitRequest - WaitResponse - StatsRequest - StatsResponse - ConnectRequest - ConnectResponse - ShutdownRequest - PauseRequest - ResumeRequest -*/ package task -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import google_protobuf "github.com/gogo/protobuf/types" -import google_protobuf1 "github.com/gogo/protobuf/types" - -// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto" -import _ "github.com/gogo/protobuf/types" -import containerd_types "github.com/containerd/containerd/api/types" -import containerd_v1_types "github.com/containerd/containerd/api/types/task" - -import time "time" - -import types "github.com/gogo/protobuf/types" - -import strings "strings" -import reflect "reflect" - -import context "context" -import ttrpc "github.com/containerd/ttrpc" - -import io "io" +import ( + context "context" + fmt "fmt" + types "github.com/containerd/containerd/api/types" + task "github.com/containerd/containerd/api/types/task" + github_com_containerd_ttrpc "github.com/containerd/ttrpc" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types1 "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" + time "time" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -70,259 +31,1067 @@ // 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 +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type CreateTaskRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` - Rootfs []*containerd_types.Mount `protobuf:"bytes,3,rep,name=rootfs" json:"rootfs,omitempty"` - Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` - Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` - Checkpoint string `protobuf:"bytes,8,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` - ParentCheckpoint string `protobuf:"bytes,9,opt,name=parent_checkpoint,json=parentCheckpoint,proto3" json:"parent_checkpoint,omitempty"` - Options *google_protobuf.Any `protobuf:"bytes,10,opt,name=options" json:"options,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Rootfs []*types.Mount `protobuf:"bytes,3,rep,name=rootfs,proto3" json:"rootfs,omitempty"` + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Checkpoint string `protobuf:"bytes,8,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` + ParentCheckpoint string `protobuf:"bytes,9,opt,name=parent_checkpoint,json=parentCheckpoint,proto3" json:"parent_checkpoint,omitempty"` + Options *types1.Any `protobuf:"bytes,10,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } +func (*CreateTaskRequest) ProtoMessage() {} +func (*CreateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{0} +} +func (m *CreateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskRequest.Merge(m, src) +} +func (m *CreateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskRequest.DiscardUnknown(m) } -func (m *CreateTaskRequest) Reset() { *m = CreateTaskRequest{} } -func (*CreateTaskRequest) ProtoMessage() {} -func (*CreateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{0} } +var xxx_messageInfo_CreateTaskRequest proto.InternalMessageInfo type CreateTaskResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } +func (*CreateTaskResponse) ProtoMessage() {} +func (*CreateTaskResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{1} +} +func (m *CreateTaskResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateTaskResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateTaskResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateTaskResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTaskResponse.Merge(m, src) +} +func (m *CreateTaskResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateTaskResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTaskResponse.DiscardUnknown(m) } -func (m *CreateTaskResponse) Reset() { *m = CreateTaskResponse{} } -func (*CreateTaskResponse) ProtoMessage() {} -func (*CreateTaskResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{1} } +var xxx_messageInfo_CreateTaskResponse proto.InternalMessageInfo type DeleteRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } +func (*DeleteRequest) ProtoMessage() {} +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{2} +} +func (m *DeleteRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteRequest.Merge(m, src) +} +func (m *DeleteRequest) XXX_Size() int { + return m.Size() +} +func (m *DeleteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteRequest.DiscardUnknown(m) } -func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } -func (*DeleteRequest) ProtoMessage() {} -func (*DeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{2} } +var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo type DeleteResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` - ExitStatus uint32 `protobuf:"varint,2,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,3,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + ExitStatus uint32 `protobuf:"varint,2,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,3,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{3} +} +func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DeleteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResponse.Merge(m, src) +} +func (m *DeleteResponse) XXX_Size() int { + return m.Size() +} +func (m *DeleteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResponse.DiscardUnknown(m) } -func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } -func (*DeleteResponse) ProtoMessage() {} -func (*DeleteResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{3} } +var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo type ExecProcessRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Terminal bool `protobuf:"varint,3,opt,name=terminal,proto3" json:"terminal,omitempty"` - Stdin string `protobuf:"bytes,4,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"` - Spec *google_protobuf.Any `protobuf:"bytes,7,opt,name=spec" json:"spec,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Terminal bool `protobuf:"varint,3,opt,name=terminal,proto3" json:"terminal,omitempty"` + Stdin string `protobuf:"bytes,4,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,5,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,6,opt,name=stderr,proto3" json:"stderr,omitempty"` + Spec *types1.Any `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } +func (*ExecProcessRequest) ProtoMessage() {} +func (*ExecProcessRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{4} +} +func (m *ExecProcessRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessRequest.Merge(m, src) +} +func (m *ExecProcessRequest) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessRequest.DiscardUnknown(m) } -func (m *ExecProcessRequest) Reset() { *m = ExecProcessRequest{} } -func (*ExecProcessRequest) ProtoMessage() {} -func (*ExecProcessRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{4} } +var xxx_messageInfo_ExecProcessRequest proto.InternalMessageInfo type ExecProcessResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } +func (*ExecProcessResponse) ProtoMessage() {} +func (*ExecProcessResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{5} +} +func (m *ExecProcessResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecProcessResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecProcessResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExecProcessResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecProcessResponse.Merge(m, src) +} +func (m *ExecProcessResponse) XXX_Size() int { + return m.Size() +} +func (m *ExecProcessResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExecProcessResponse.DiscardUnknown(m) } -func (m *ExecProcessResponse) Reset() { *m = ExecProcessResponse{} } -func (*ExecProcessResponse) ProtoMessage() {} -func (*ExecProcessResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{5} } +var xxx_messageInfo_ExecProcessResponse proto.InternalMessageInfo type ResizePtyRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Width uint32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` - Height uint32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Width uint32 `protobuf:"varint,3,opt,name=width,proto3" json:"width,omitempty"` + Height uint32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } +func (*ResizePtyRequest) ProtoMessage() {} +func (*ResizePtyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{6} +} +func (m *ResizePtyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResizePtyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResizePtyRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResizePtyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResizePtyRequest.Merge(m, src) +} +func (m *ResizePtyRequest) XXX_Size() int { + return m.Size() +} +func (m *ResizePtyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResizePtyRequest.DiscardUnknown(m) } -func (m *ResizePtyRequest) Reset() { *m = ResizePtyRequest{} } -func (*ResizePtyRequest) ProtoMessage() {} -func (*ResizePtyRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{6} } +var xxx_messageInfo_ResizePtyRequest proto.InternalMessageInfo type StateRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StateRequest) Reset() { *m = StateRequest{} } +func (*StateRequest) ProtoMessage() {} +func (*StateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{7} +} +func (m *StateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StateRequest.Merge(m, src) +} +func (m *StateRequest) XXX_Size() int { + return m.Size() +} +func (m *StateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StateRequest.DiscardUnknown(m) } -func (m *StateRequest) Reset() { *m = StateRequest{} } -func (*StateRequest) ProtoMessage() {} -func (*StateRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{7} } +var xxx_messageInfo_StateRequest proto.InternalMessageInfo type StateResponse struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` - Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` - Status containerd_v1_types.Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` - Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` - Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` - Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` - Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` - ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Bundle string `protobuf:"bytes,2,opt,name=bundle,proto3" json:"bundle,omitempty"` + Pid uint32 `protobuf:"varint,3,opt,name=pid,proto3" json:"pid,omitempty"` + Status task.Status `protobuf:"varint,4,opt,name=status,proto3,enum=containerd.v1.types.Status" json:"status,omitempty"` + Stdin string `protobuf:"bytes,5,opt,name=stdin,proto3" json:"stdin,omitempty"` + Stdout string `protobuf:"bytes,6,opt,name=stdout,proto3" json:"stdout,omitempty"` + Stderr string `protobuf:"bytes,7,opt,name=stderr,proto3" json:"stderr,omitempty"` + Terminal bool `protobuf:"varint,8,opt,name=terminal,proto3" json:"terminal,omitempty"` + ExitStatus uint32 `protobuf:"varint,9,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,10,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + ExecID string `protobuf:"bytes,11,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StateResponse) Reset() { *m = StateResponse{} } +func (*StateResponse) ProtoMessage() {} +func (*StateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{8} +} +func (m *StateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StateResponse.Merge(m, src) +} +func (m *StateResponse) XXX_Size() int { + return m.Size() +} +func (m *StateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StateResponse.DiscardUnknown(m) } -func (m *StateResponse) Reset() { *m = StateResponse{} } -func (*StateResponse) ProtoMessage() {} -func (*StateResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{8} } +var xxx_messageInfo_StateResponse proto.InternalMessageInfo type KillRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Signal uint32 `protobuf:"varint,3,opt,name=signal,proto3" json:"signal,omitempty"` - All bool `protobuf:"varint,4,opt,name=all,proto3" json:"all,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Signal uint32 `protobuf:"varint,3,opt,name=signal,proto3" json:"signal,omitempty"` + All bool `protobuf:"varint,4,opt,name=all,proto3" json:"all,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KillRequest) Reset() { *m = KillRequest{} } +func (*KillRequest) ProtoMessage() {} +func (*KillRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{9} +} +func (m *KillRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KillRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KillRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *KillRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_KillRequest.Merge(m, src) +} +func (m *KillRequest) XXX_Size() int { + return m.Size() +} +func (m *KillRequest) XXX_DiscardUnknown() { + xxx_messageInfo_KillRequest.DiscardUnknown(m) } -func (m *KillRequest) Reset() { *m = KillRequest{} } -func (*KillRequest) ProtoMessage() {} -func (*KillRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{9} } +var xxx_messageInfo_KillRequest proto.InternalMessageInfo type CloseIORequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` - Stdin bool `protobuf:"varint,3,opt,name=stdin,proto3" json:"stdin,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + Stdin bool `protobuf:"varint,3,opt,name=stdin,proto3" json:"stdin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } +func (*CloseIORequest) ProtoMessage() {} +func (*CloseIORequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{10} +} +func (m *CloseIORequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CloseIORequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CloseIORequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CloseIORequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CloseIORequest.Merge(m, src) +} +func (m *CloseIORequest) XXX_Size() int { + return m.Size() +} +func (m *CloseIORequest) XXX_DiscardUnknown() { + xxx_messageInfo_CloseIORequest.DiscardUnknown(m) } -func (m *CloseIORequest) Reset() { *m = CloseIORequest{} } -func (*CloseIORequest) ProtoMessage() {} -func (*CloseIORequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{10} } +var xxx_messageInfo_CloseIORequest proto.InternalMessageInfo type PidsRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PidsRequest) Reset() { *m = PidsRequest{} } +func (*PidsRequest) ProtoMessage() {} +func (*PidsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{11} +} +func (m *PidsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PidsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PidsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PidsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PidsRequest.Merge(m, src) +} +func (m *PidsRequest) XXX_Size() int { + return m.Size() +} +func (m *PidsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PidsRequest.DiscardUnknown(m) } -func (m *PidsRequest) Reset() { *m = PidsRequest{} } -func (*PidsRequest) ProtoMessage() {} -func (*PidsRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{11} } +var xxx_messageInfo_PidsRequest proto.InternalMessageInfo type PidsResponse struct { - Processes []*containerd_v1_types.ProcessInfo `protobuf:"bytes,1,rep,name=processes" json:"processes,omitempty"` + Processes []*task.ProcessInfo `protobuf:"bytes,1,rep,name=processes,proto3" json:"processes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PidsResponse) Reset() { *m = PidsResponse{} } +func (*PidsResponse) ProtoMessage() {} +func (*PidsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{12} +} +func (m *PidsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PidsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PidsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PidsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PidsResponse.Merge(m, src) +} +func (m *PidsResponse) XXX_Size() int { + return m.Size() +} +func (m *PidsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PidsResponse.DiscardUnknown(m) } -func (m *PidsResponse) Reset() { *m = PidsResponse{} } -func (*PidsResponse) ProtoMessage() {} -func (*PidsResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{12} } +var xxx_messageInfo_PidsResponse proto.InternalMessageInfo type CheckpointTaskRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` - Options *google_protobuf.Any `protobuf:"bytes,3,opt,name=options" json:"options,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Options *types1.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } +func (*CheckpointTaskRequest) ProtoMessage() {} +func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{13} +} +func (m *CheckpointTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CheckpointTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CheckpointTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CheckpointTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CheckpointTaskRequest.Merge(m, src) +} +func (m *CheckpointTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *CheckpointTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CheckpointTaskRequest.DiscardUnknown(m) } -func (m *CheckpointTaskRequest) Reset() { *m = CheckpointTaskRequest{} } -func (*CheckpointTaskRequest) ProtoMessage() {} -func (*CheckpointTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{13} } +var xxx_messageInfo_CheckpointTaskRequest proto.InternalMessageInfo type UpdateTaskRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Resources *google_protobuf.Any `protobuf:"bytes,2,opt,name=resources" json:"resources,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Resources *types1.Any `protobuf:"bytes,2,opt,name=resources,proto3" json:"resources,omitempty"` + Annotations map[string]string `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } +func (*UpdateTaskRequest) ProtoMessage() {} +func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{14} +} +func (m *UpdateTaskRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateTaskRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateTaskRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UpdateTaskRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateTaskRequest.Merge(m, src) +} +func (m *UpdateTaskRequest) XXX_Size() int { + return m.Size() +} +func (m *UpdateTaskRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateTaskRequest.DiscardUnknown(m) } -func (m *UpdateTaskRequest) Reset() { *m = UpdateTaskRequest{} } -func (*UpdateTaskRequest) ProtoMessage() {} -func (*UpdateTaskRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{14} } +var xxx_messageInfo_UpdateTaskRequest proto.InternalMessageInfo type StartRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartRequest) Reset() { *m = StartRequest{} } +func (*StartRequest) ProtoMessage() {} +func (*StartRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{15} +} +func (m *StartRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartRequest.Merge(m, src) +} +func (m *StartRequest) XXX_Size() int { + return m.Size() +} +func (m *StartRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StartRequest.DiscardUnknown(m) } -func (m *StartRequest) Reset() { *m = StartRequest{} } -func (*StartRequest) ProtoMessage() {} -func (*StartRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{15} } +var xxx_messageInfo_StartRequest proto.InternalMessageInfo type StartResponse struct { - Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + Pid uint32 `protobuf:"varint,1,opt,name=pid,proto3" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartResponse) Reset() { *m = StartResponse{} } +func (*StartResponse) ProtoMessage() {} +func (*StartResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{16} +} +func (m *StartResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartResponse.Merge(m, src) +} +func (m *StartResponse) XXX_Size() int { + return m.Size() +} +func (m *StartResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StartResponse.DiscardUnknown(m) } -func (m *StartResponse) Reset() { *m = StartResponse{} } -func (*StartResponse) ProtoMessage() {} -func (*StartResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{16} } +var xxx_messageInfo_StartResponse proto.InternalMessageInfo type WaitRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ExecID string `protobuf:"bytes,2,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitRequest) Reset() { *m = WaitRequest{} } +func (*WaitRequest) ProtoMessage() {} +func (*WaitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{17} +} +func (m *WaitRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitRequest.Merge(m, src) +} +func (m *WaitRequest) XXX_Size() int { + return m.Size() +} +func (m *WaitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WaitRequest.DiscardUnknown(m) } -func (m *WaitRequest) Reset() { *m = WaitRequest{} } -func (*WaitRequest) ProtoMessage() {} -func (*WaitRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{17} } +var xxx_messageInfo_WaitRequest proto.InternalMessageInfo type WaitResponse struct { - ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` - ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,stdtime" json:"exited_at"` + ExitStatus uint32 `protobuf:"varint,1,opt,name=exit_status,json=exitStatus,proto3" json:"exit_status,omitempty"` + ExitedAt time.Time `protobuf:"bytes,2,opt,name=exited_at,json=exitedAt,proto3,stdtime" json:"exited_at"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WaitResponse) Reset() { *m = WaitResponse{} } +func (*WaitResponse) ProtoMessage() {} +func (*WaitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{18} +} +func (m *WaitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WaitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WaitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WaitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_WaitResponse.Merge(m, src) +} +func (m *WaitResponse) XXX_Size() int { + return m.Size() +} +func (m *WaitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_WaitResponse.DiscardUnknown(m) } -func (m *WaitResponse) Reset() { *m = WaitResponse{} } -func (*WaitResponse) ProtoMessage() {} -func (*WaitResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{18} } +var xxx_messageInfo_WaitResponse proto.InternalMessageInfo type StatsRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsRequest) Reset() { *m = StatsRequest{} } +func (*StatsRequest) ProtoMessage() {} +func (*StatsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{19} +} +func (m *StatsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsRequest.Merge(m, src) +} +func (m *StatsRequest) XXX_Size() int { + return m.Size() +} +func (m *StatsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StatsRequest.DiscardUnknown(m) } -func (m *StatsRequest) Reset() { *m = StatsRequest{} } -func (*StatsRequest) ProtoMessage() {} -func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{19} } +var xxx_messageInfo_StatsRequest proto.InternalMessageInfo type StatsResponse struct { - Stats *google_protobuf.Any `protobuf:"bytes,1,opt,name=stats" json:"stats,omitempty"` + Stats *types1.Any `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsResponse) Reset() { *m = StatsResponse{} } +func (*StatsResponse) ProtoMessage() {} +func (*StatsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{20} +} +func (m *StatsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StatsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsResponse.Merge(m, src) +} +func (m *StatsResponse) XXX_Size() int { + return m.Size() +} +func (m *StatsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatsResponse.DiscardUnknown(m) } -func (m *StatsResponse) Reset() { *m = StatsResponse{} } -func (*StatsResponse) ProtoMessage() {} -func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{20} } +var xxx_messageInfo_StatsResponse proto.InternalMessageInfo type ConnectRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectRequest) Reset() { *m = ConnectRequest{} } +func (*ConnectRequest) ProtoMessage() {} +func (*ConnectRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{21} +} +func (m *ConnectRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConnectRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConnectRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConnectRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectRequest.Merge(m, src) +} +func (m *ConnectRequest) XXX_Size() int { + return m.Size() +} +func (m *ConnectRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectRequest.DiscardUnknown(m) } -func (m *ConnectRequest) Reset() { *m = ConnectRequest{} } -func (*ConnectRequest) ProtoMessage() {} -func (*ConnectRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{21} } +var xxx_messageInfo_ConnectRequest proto.InternalMessageInfo type ConnectResponse struct { - ShimPid uint32 `protobuf:"varint,1,opt,name=shim_pid,json=shimPid,proto3" json:"shim_pid,omitempty"` - TaskPid uint32 `protobuf:"varint,2,opt,name=task_pid,json=taskPid,proto3" json:"task_pid,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + ShimPid uint32 `protobuf:"varint,1,opt,name=shim_pid,json=shimPid,proto3" json:"shim_pid,omitempty"` + TaskPid uint32 `protobuf:"varint,2,opt,name=task_pid,json=taskPid,proto3" json:"task_pid,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ConnectResponse) Reset() { *m = ConnectResponse{} } +func (*ConnectResponse) ProtoMessage() {} +func (*ConnectResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{22} +} +func (m *ConnectResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConnectResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConnectResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConnectResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConnectResponse.Merge(m, src) +} +func (m *ConnectResponse) XXX_Size() int { + return m.Size() +} +func (m *ConnectResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ConnectResponse.DiscardUnknown(m) } -func (m *ConnectResponse) Reset() { *m = ConnectResponse{} } -func (*ConnectResponse) ProtoMessage() {} -func (*ConnectResponse) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{22} } +var xxx_messageInfo_ConnectResponse proto.InternalMessageInfo type ShutdownRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Now bool `protobuf:"varint,2,opt,name=now,proto3" json:"now,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Now bool `protobuf:"varint,2,opt,name=now,proto3" json:"now,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ShutdownRequest) Reset() { *m = ShutdownRequest{} } +func (*ShutdownRequest) ProtoMessage() {} +func (*ShutdownRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{23} +} +func (m *ShutdownRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ShutdownRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ShutdownRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ShutdownRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShutdownRequest.Merge(m, src) +} +func (m *ShutdownRequest) XXX_Size() int { + return m.Size() +} +func (m *ShutdownRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ShutdownRequest.DiscardUnknown(m) } -func (m *ShutdownRequest) Reset() { *m = ShutdownRequest{} } -func (*ShutdownRequest) ProtoMessage() {} -func (*ShutdownRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{23} } +var xxx_messageInfo_ShutdownRequest proto.InternalMessageInfo type PauseRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PauseRequest) Reset() { *m = PauseRequest{} } +func (*PauseRequest) ProtoMessage() {} +func (*PauseRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{24} +} +func (m *PauseRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PauseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PauseRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PauseRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PauseRequest.Merge(m, src) +} +func (m *PauseRequest) XXX_Size() int { + return m.Size() +} +func (m *PauseRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PauseRequest.DiscardUnknown(m) } -func (m *PauseRequest) Reset() { *m = PauseRequest{} } -func (*PauseRequest) ProtoMessage() {} -func (*PauseRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{24} } +var xxx_messageInfo_PauseRequest proto.InternalMessageInfo type ResumeRequest struct { - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResumeRequest) Reset() { *m = ResumeRequest{} } +func (*ResumeRequest) ProtoMessage() {} +func (*ResumeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9202ee34bc3ad8ca, []int{25} +} +func (m *ResumeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResumeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResumeRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResumeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResumeRequest.Merge(m, src) +} +func (m *ResumeRequest) XXX_Size() int { + return m.Size() +} +func (m *ResumeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResumeRequest.DiscardUnknown(m) } -func (m *ResumeRequest) Reset() { *m = ResumeRequest{} } -func (*ResumeRequest) ProtoMessage() {} -func (*ResumeRequest) Descriptor() ([]byte, []int) { return fileDescriptorShim, []int{25} } +var xxx_messageInfo_ResumeRequest proto.InternalMessageInfo func init() { proto.RegisterType((*CreateTaskRequest)(nil), "containerd.task.v2.CreateTaskRequest") @@ -340,6 +1109,7 @@ proto.RegisterType((*PidsResponse)(nil), "containerd.task.v2.PidsResponse") proto.RegisterType((*CheckpointTaskRequest)(nil), "containerd.task.v2.CheckpointTaskRequest") proto.RegisterType((*UpdateTaskRequest)(nil), "containerd.task.v2.UpdateTaskRequest") + proto.RegisterMapType((map[string]string)(nil), "containerd.task.v2.UpdateTaskRequest.AnnotationsEntry") proto.RegisterType((*StartRequest)(nil), "containerd.task.v2.StartRequest") proto.RegisterType((*StartResponse)(nil), "containerd.task.v2.StartResponse") proto.RegisterType((*WaitRequest)(nil), "containerd.task.v2.WaitRequest") @@ -352,10 +1122,101 @@ proto.RegisterType((*PauseRequest)(nil), "containerd.task.v2.PauseRequest") proto.RegisterType((*ResumeRequest)(nil), "containerd.task.v2.ResumeRequest") } + +func init() { + proto.RegisterFile("github.com/containerd/containerd/runtime/v2/task/shim.proto", fileDescriptor_9202ee34bc3ad8ca) +} + +var fileDescriptor_9202ee34bc3ad8ca = []byte{ + // 1306 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6f, 0xdb, 0x46, + 0x13, 0x0e, 0xf5, 0x41, 0x49, 0xa3, 0xc8, 0x71, 0xf6, 0x75, 0xf2, 0x32, 0x0a, 0x20, 0x29, 0x4c, + 0x93, 0xaa, 0x2d, 0x40, 0xa1, 0x0a, 0x1a, 0x14, 0x31, 0x90, 0xc2, 0x76, 0xdc, 0x40, 0x4d, 0x5a, + 0x1b, 0x4c, 0x8a, 0x04, 0xbd, 0x18, 0xb4, 0xb8, 0x91, 0x08, 0x4b, 0x5c, 0x96, 0xbb, 0x74, 0xa2, + 0x02, 0x05, 0x7a, 0xea, 0xa1, 0xa7, 0xfe, 0xac, 0x1c, 0x0b, 0xf4, 0xd2, 0x4b, 0xd3, 0x46, 0xff, + 0xa0, 0xc7, 0xde, 0x8a, 0xfd, 0x90, 0x45, 0x49, 0xa4, 0x14, 0x07, 0xba, 0x18, 0x3b, 0xdc, 0x67, + 0x67, 0x67, 0x67, 0x9f, 0x79, 0x66, 0x65, 0xd8, 0xee, 0x79, 0xac, 0x1f, 0x1d, 0x5b, 0x5d, 0x32, + 0x6c, 0x75, 0x89, 0xcf, 0x1c, 0xcf, 0xc7, 0xa1, 0x1b, 0x1f, 0x86, 0x91, 0xcf, 0xbc, 0x21, 0x6e, + 0x9d, 0xb6, 0x5b, 0xcc, 0xa1, 0x27, 0x2d, 0xda, 0xf7, 0x86, 0x56, 0x10, 0x12, 0x46, 0x10, 0x9a, + 0xc2, 0x2c, 0x3e, 0x67, 0x9d, 0xb6, 0xab, 0xd7, 0x7a, 0x84, 0xf4, 0x06, 0xb8, 0x25, 0x10, 0xc7, + 0xd1, 0x8b, 0x96, 0xe3, 0x8f, 0x24, 0xbc, 0x7a, 0x7d, 0x7e, 0x0a, 0x0f, 0x03, 0x36, 0x99, 0xdc, + 0xea, 0x91, 0x1e, 0x11, 0xc3, 0x16, 0x1f, 0xa9, 0xaf, 0xf5, 0xf9, 0x25, 0x3c, 0x14, 0xca, 0x9c, + 0x61, 0xa0, 0x00, 0x77, 0x57, 0xc6, 0xef, 0x04, 0x5e, 0x8b, 0x8d, 0x02, 0x4c, 0x5b, 0x43, 0x12, + 0xf9, 0x4c, 0xad, 0xbb, 0x77, 0x8e, 0x75, 0xe2, 0xd8, 0xe2, 0x7c, 0x62, 0xad, 0xf9, 0x7b, 0x06, + 0x2e, 0xef, 0x85, 0xd8, 0x61, 0xf8, 0xa9, 0x43, 0x4f, 0x6c, 0xfc, 0x7d, 0x84, 0x29, 0x43, 0x57, + 0x21, 0xe3, 0xb9, 0x86, 0xd6, 0xd0, 0x9a, 0xa5, 0x5d, 0x7d, 0xfc, 0xa6, 0x9e, 0xe9, 0x3c, 0xb0, + 0x33, 0x9e, 0x8b, 0xae, 0x82, 0x7e, 0x1c, 0xf9, 0xee, 0x00, 0x1b, 0x19, 0x3e, 0x67, 0x2b, 0x0b, + 0xb5, 0x40, 0x0f, 0x09, 0x61, 0x2f, 0xa8, 0x91, 0x6d, 0x64, 0x9b, 0xe5, 0xf6, 0xff, 0xad, 0x78, + 0x36, 0xf9, 0xc6, 0xd6, 0xd7, 0x3c, 0x60, 0x5b, 0xc1, 0x50, 0x15, 0x8a, 0x0c, 0x87, 0x43, 0xcf, + 0x77, 0x06, 0x46, 0xae, 0xa1, 0x35, 0x8b, 0xf6, 0x99, 0x8d, 0xb6, 0x20, 0x4f, 0x99, 0xeb, 0xf9, + 0x46, 0x5e, 0xec, 0x21, 0x0d, 0xbe, 0x35, 0x65, 0x2e, 0x89, 0x98, 0xa1, 0xcb, 0xad, 0xa5, 0xa5, + 0xbe, 0xe3, 0x30, 0x34, 0x0a, 0x67, 0xdf, 0x71, 0x18, 0xa2, 0x1a, 0x40, 0xb7, 0x8f, 0xbb, 0x27, + 0x01, 0xf1, 0x7c, 0x66, 0x14, 0xc5, 0x5c, 0xec, 0x0b, 0xfa, 0x04, 0x2e, 0x07, 0x4e, 0x88, 0x7d, + 0x76, 0x14, 0x83, 0x95, 0x04, 0x6c, 0x53, 0x4e, 0xec, 0x4d, 0xc1, 0x16, 0x14, 0x48, 0xc0, 0x3c, + 0xe2, 0x53, 0x03, 0x1a, 0x5a, 0xb3, 0xdc, 0xde, 0xb2, 0xe4, 0x65, 0x5a, 0x93, 0xcb, 0xb4, 0x76, + 0xfc, 0x91, 0x3d, 0x01, 0x99, 0xb7, 0x01, 0xc5, 0x93, 0x4a, 0x03, 0xe2, 0x53, 0x8c, 0x36, 0x21, + 0x1b, 0xa8, 0xb4, 0x56, 0x6c, 0x3e, 0x34, 0x1f, 0x43, 0xe5, 0x01, 0x1e, 0x60, 0x86, 0x57, 0x25, + 0xfe, 0x26, 0x14, 0xf0, 0x2b, 0xdc, 0x3d, 0xf2, 0x5c, 0x99, 0xf9, 0x5d, 0x18, 0xbf, 0xa9, 0xeb, + 0xfb, 0xaf, 0x70, 0xb7, 0xf3, 0xc0, 0xd6, 0xf9, 0x54, 0xc7, 0x35, 0x7f, 0xd6, 0x60, 0x63, 0xe2, + 0x2e, 0x6d, 0x4b, 0x54, 0x87, 0x32, 0x7e, 0xe5, 0xb1, 0x23, 0xca, 0x1c, 0x16, 0x51, 0xe1, 0xad, + 0x62, 0x03, 0xff, 0xf4, 0x44, 0x7c, 0x41, 0x3b, 0x50, 0xe2, 0x16, 0x76, 0x8f, 0x1c, 0x66, 0x64, + 0xc5, 0x69, 0xab, 0x0b, 0xa7, 0x7d, 0x3a, 0xa1, 0xee, 0x6e, 0xf1, 0xf5, 0x9b, 0xfa, 0x85, 0x5f, + 0xff, 0xaa, 0x6b, 0x76, 0x51, 0x2e, 0xdb, 0x61, 0xe6, 0x9f, 0x1a, 0x20, 0x1e, 0xdb, 0x61, 0x48, + 0xba, 0x98, 0xd2, 0x75, 0x1c, 0x6e, 0x86, 0x31, 0xd9, 0x34, 0xc6, 0xe4, 0x92, 0x19, 0x93, 0x4f, + 0x61, 0x8c, 0x3e, 0xc3, 0x98, 0x26, 0xe4, 0x68, 0x80, 0xbb, 0x82, 0x47, 0x69, 0x37, 0x2c, 0x10, + 0xe6, 0x15, 0xf8, 0xdf, 0xcc, 0xf1, 0x64, 0xb2, 0xcd, 0x1f, 0x61, 0xd3, 0xc6, 0xd4, 0xfb, 0x01, + 0x1f, 0xb2, 0xd1, 0x5a, 0xce, 0xbc, 0x05, 0xf9, 0x97, 0x9e, 0xcb, 0xfa, 0xe2, 0xc0, 0x15, 0x5b, + 0x1a, 0x3c, 0xfe, 0x3e, 0xf6, 0x7a, 0x7d, 0x26, 0x8e, 0x5b, 0xb1, 0x95, 0x65, 0x3e, 0x82, 0x8b, + 0xfc, 0x0a, 0xd7, 0xc3, 0xa5, 0x7f, 0x32, 0x50, 0x51, 0xde, 0x14, 0x95, 0xce, 0xab, 0x09, 0x8a, + 0x7a, 0xd9, 0x29, 0xf5, 0xee, 0xf0, 0xc4, 0x0b, 0xd6, 0xf1, 0xc0, 0x37, 0xda, 0xd7, 0xe3, 0x2a, + 0x71, 0xfa, 0xa9, 0x12, 0x0a, 0x49, 0x43, 0x5b, 0x41, 0xd7, 0xa4, 0x06, 0x71, 0xf6, 0x14, 0xe7, + 0xd8, 0x33, 0x57, 0x11, 0xa5, 0xe5, 0x15, 0x01, 0xef, 0x53, 0x11, 0xf1, 0x9c, 0x97, 0x53, 0x73, + 0xce, 0xa0, 0xfc, 0xc8, 0x1b, 0x0c, 0xd6, 0x42, 0x1d, 0x9e, 0x08, 0xaf, 0x37, 0x29, 0x96, 0x8a, + 0xad, 0x2c, 0x7e, 0x2b, 0xce, 0x60, 0xa2, 0xb9, 0x7c, 0x68, 0x76, 0x61, 0x63, 0x6f, 0x40, 0x28, + 0xee, 0x1c, 0xac, 0x8b, 0xb3, 0xf2, 0xbe, 0x64, 0x91, 0x4a, 0xc3, 0xbc, 0x05, 0xe5, 0x43, 0xcf, + 0x5d, 0xa5, 0x04, 0xe6, 0x37, 0x70, 0x51, 0xc2, 0x14, 0xe7, 0xee, 0x43, 0x29, 0x90, 0x45, 0x86, + 0xa9, 0xa1, 0x89, 0xd6, 0xd2, 0x48, 0x24, 0x8d, 0x2a, 0xc5, 0x8e, 0xff, 0x82, 0xd8, 0xd3, 0x25, + 0x26, 0x85, 0x2b, 0x53, 0x15, 0x7f, 0x97, 0x06, 0x87, 0x20, 0x17, 0x38, 0xac, 0xaf, 0xa8, 0x2c, + 0xc6, 0x71, 0xf1, 0xcf, 0xbe, 0x8b, 0xf8, 0xff, 0xab, 0xc1, 0xe5, 0x6f, 0x03, 0xf7, 0x1d, 0x5b, + 0x6a, 0x1b, 0x4a, 0x21, 0xa6, 0x24, 0x0a, 0xbb, 0x58, 0xaa, 0x71, 0x9a, 0xff, 0x29, 0x0c, 0x3d, + 0x87, 0xb2, 0xe3, 0xfb, 0x84, 0x39, 0x93, 0xa8, 0x78, 0x62, 0xee, 0x5a, 0x8b, 0x2f, 0x18, 0x6b, + 0x21, 0x0e, 0x6b, 0x67, 0xba, 0x70, 0xdf, 0x67, 0xe1, 0xc8, 0x8e, 0xbb, 0xaa, 0xde, 0x87, 0xcd, + 0x79, 0x00, 0xa7, 0xcc, 0x09, 0x1e, 0xc9, 0xd0, 0x6d, 0x3e, 0xe4, 0x77, 0x7c, 0xea, 0x0c, 0xa2, + 0x49, 0xc5, 0x4b, 0xe3, 0x5e, 0xe6, 0x73, 0x4d, 0x69, 0x50, 0xc8, 0xd6, 0xa2, 0x41, 0x37, 0x84, + 0x04, 0x71, 0x67, 0xa9, 0x0d, 0xf4, 0x2b, 0x28, 0x3f, 0x73, 0xbc, 0xf5, 0x6c, 0x17, 0xc2, 0x45, + 0xe9, 0x4b, 0xed, 0x36, 0xa7, 0x0b, 0xda, 0x72, 0x5d, 0xc8, 0xbc, 0x57, 0xa7, 0xbc, 0x2d, 0x35, + 0x7b, 0x65, 0x61, 0x6c, 0x4b, 0x35, 0x9e, 0x56, 0xc6, 0xc7, 0xbc, 0xcc, 0x1c, 0x26, 0xc3, 0x4a, + 0xa3, 0x8c, 0x84, 0x98, 0x4d, 0xd8, 0xd8, 0x23, 0xbe, 0x8f, 0xbb, 0xab, 0xf2, 0x64, 0x3a, 0x70, + 0xe9, 0x0c, 0xa9, 0x36, 0xba, 0x06, 0x45, 0xfe, 0x4a, 0x3e, 0x9a, 0x26, 0xbe, 0xc0, 0xed, 0x43, + 0xcf, 0xe5, 0x53, 0x9c, 0x67, 0x62, 0x4a, 0xbe, 0x23, 0x0a, 0xdc, 0xe6, 0x53, 0x06, 0x14, 0x4e, + 0x71, 0x48, 0x3d, 0x22, 0x75, 0xa0, 0x64, 0x4f, 0x4c, 0x73, 0x1b, 0x2e, 0x3d, 0xe9, 0x47, 0xcc, + 0x25, 0x2f, 0xfd, 0x55, 0xb7, 0xb6, 0x09, 0x59, 0x9f, 0xbc, 0x14, 0xae, 0x8b, 0x36, 0x1f, 0xf2, + 0x74, 0x1d, 0x3a, 0x11, 0x5d, 0xd5, 0xe2, 0xcc, 0x0f, 0xa1, 0x62, 0x63, 0x1a, 0x0d, 0x57, 0x01, + 0xdb, 0xbf, 0x00, 0xe4, 0x78, 0x75, 0xa0, 0xc7, 0x90, 0x17, 0xed, 0x0e, 0x35, 0x92, 0xca, 0x28, + 0xde, 0x57, 0xab, 0x37, 0x96, 0x20, 0x54, 0xd2, 0x9e, 0x81, 0x2e, 0xdf, 0x7f, 0xe8, 0x56, 0x12, + 0x78, 0xe1, 0xc1, 0x5d, 0xbd, 0xbd, 0x0a, 0xa6, 0x1c, 0xcb, 0x30, 0x43, 0x96, 0x1a, 0xe6, 0x59, + 0xe9, 0xa5, 0x86, 0x19, 0xab, 0xa7, 0x03, 0xd0, 0xe5, 0x7b, 0x11, 0x25, 0x82, 0x67, 0x9e, 0xa6, + 0x55, 0x73, 0x19, 0x44, 0x39, 0xec, 0x40, 0x8e, 0xeb, 0x37, 0xaa, 0x27, 0x61, 0x63, 0x0d, 0xa0, + 0xda, 0x48, 0x07, 0x28, 0x57, 0x3b, 0x90, 0x17, 0x57, 0x9d, 0x7c, 0xd2, 0x38, 0x0b, 0xaa, 0x57, + 0x17, 0xc8, 0xbf, 0xcf, 0x7f, 0x8c, 0xa1, 0x3d, 0xd0, 0x25, 0x0b, 0x92, 0x8f, 0x37, 0xc3, 0x90, + 0x54, 0x27, 0x07, 0x00, 0xb1, 0x1f, 0x02, 0x1f, 0x25, 0xde, 0x53, 0x52, 0x8b, 0x49, 0x75, 0xf8, + 0x05, 0xe4, 0x78, 0x97, 0x4f, 0xce, 0x51, 0xac, 0xff, 0xa7, 0x3a, 0xf8, 0x12, 0x72, 0x5c, 0xb9, + 0x50, 0x22, 0x67, 0x16, 0x9f, 0xdd, 0xa9, 0x7e, 0x3a, 0x50, 0x3a, 0x7b, 0xae, 0xa2, 0x0f, 0x52, + 0x32, 0x34, 0xf3, 0x9a, 0x4d, 0x75, 0xb5, 0x0f, 0x05, 0xf5, 0x86, 0x40, 0x89, 0x34, 0x99, 0x7d, + 0x60, 0xa4, 0xba, 0x79, 0x08, 0xba, 0x6c, 0x58, 0xc9, 0x65, 0xb3, 0xd0, 0xcc, 0x96, 0x1c, 0x2d, + 0xc7, 0xa5, 0x3c, 0x39, 0xc7, 0xb1, 0x86, 0x91, 0xcc, 0xc3, 0x99, 0x2e, 0xa0, 0x84, 0x81, 0xa6, + 0x0b, 0x03, 0x5d, 0x29, 0x0c, 0x53, 0x56, 0xdb, 0x50, 0x50, 0x02, 0x9b, 0x92, 0xa8, 0x19, 0x9d, + 0xae, 0xde, 0x5c, 0x8a, 0x51, 0x3e, 0x1f, 0x42, 0x71, 0xa2, 0xa8, 0x28, 0x71, 0xc1, 0x9c, 0xde, + 0xa6, 0x65, 0x6d, 0xf7, 0xe0, 0xf5, 0xdb, 0xda, 0x85, 0x3f, 0xde, 0xd6, 0x2e, 0xfc, 0x34, 0xae, + 0x69, 0xaf, 0xc7, 0x35, 0xed, 0xb7, 0x71, 0x4d, 0xfb, 0x7b, 0x5c, 0xd3, 0xbe, 0xfb, 0xec, 0xbc, + 0xff, 0x59, 0xd9, 0xe6, 0x7f, 0x9e, 0x67, 0x8e, 0x75, 0xb1, 0xc5, 0x9d, 0xff, 0x02, 0x00, 0x00, + 0xff, 0xff, 0xd3, 0xbf, 0xc3, 0xa9, 0x9b, 0x11, 0x00, 0x00, +} + func (m *CreateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -363,91 +1224,111 @@ } func (m *CreateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Bundle) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) - i += copy(dAtA[i:], m.Bundle) - } - if len(m.Rootfs) > 0 { - for _, msg := range m.Rootfs { - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) + if m.Options != nil { + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } - i += n + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x52 + } + if len(m.ParentCheckpoint) > 0 { + i -= len(m.ParentCheckpoint) + copy(dAtA[i:], m.ParentCheckpoint) + i = encodeVarintShim(dAtA, i, uint64(len(m.ParentCheckpoint))) + i-- + dAtA[i] = 0x4a + } + if len(m.Checkpoint) > 0 { + i -= len(m.Checkpoint) + copy(dAtA[i:], m.Checkpoint) + i = encodeVarintShim(dAtA, i, uint64(len(m.Checkpoint))) + i-- + dAtA[i] = 0x42 + } + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x3a + } + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x32 + } + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x2a } if m.Terminal { - dAtA[i] = 0x20 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.Stdin) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) - } - if len(m.Stderr) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + i-- + dAtA[i] = 0x20 } - if len(m.Checkpoint) > 0 { - dAtA[i] = 0x42 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Checkpoint))) - i += copy(dAtA[i:], m.Checkpoint) + if len(m.Rootfs) > 0 { + for iNdEx := len(m.Rootfs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rootfs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } } - if len(m.ParentCheckpoint) > 0 { - dAtA[i] = 0x4a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ParentCheckpoint))) - i += copy(dAtA[i:], m.ParentCheckpoint) + if len(m.Bundle) > 0 { + i -= len(m.Bundle) + copy(dAtA[i:], m.Bundle) + i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) + i-- + dAtA[i] = 0x12 } - if m.Options != nil { - dAtA[i] = 0x52 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Options.Size())) - n1, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CreateTaskResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -455,22 +1336,31 @@ } func (m *CreateTaskResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateTaskResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Pid != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -478,29 +1368,40 @@ } func (m *DeleteRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *DeleteResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -508,35 +1409,44 @@ } func (m *DeleteResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeleteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.Pid != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Pid)) - } + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintShim(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x1a if m.ExitStatus != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x10 } - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n2, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if m.Pid != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - i += n2 - return i, nil + return len(dAtA) - i, nil } func (m *ExecProcessRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -544,67 +1454,83 @@ } func (m *ExecProcessRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if m.Spec != nil { + { + size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x32 + } + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x2a + } + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x22 } if m.Terminal { - dAtA[i] = 0x18 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ - } - if len(m.Stdin) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + i-- + dAtA[i] = 0x18 } - if len(m.Stderr) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 } - if m.Spec != nil { - dAtA[i] = 0x3a - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Spec.Size())) - n3, err := m.Spec.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n3 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ExecProcessResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -612,17 +1538,26 @@ } func (m *ExecProcessResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecProcessResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - return i, nil + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + return len(dAtA) - i, nil } func (m *ResizePtyRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -630,39 +1565,50 @@ } func (m *ResizePtyRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResizePtyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if m.Height != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x20 } if m.Width != 0 { - dAtA[i] = 0x18 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Width)) + i-- + dAtA[i] = 0x18 } - if m.Height != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Height)) + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StateRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -670,29 +1616,40 @@ } func (m *StateRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StateResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -700,125 +1657,157 @@ } func (m *StateResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if len(m.Bundle) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) - i += copy(dAtA[i:], m.Bundle) - } - if m.Pid != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if m.Status != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Status)) - } - if len(m.Stdin) > 0 { - dAtA[i] = 0x2a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) - i += copy(dAtA[i:], m.Stdin) - } - if len(m.Stdout) > 0 { - dAtA[i] = 0x32 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) - i += copy(dAtA[i:], m.Stdout) + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x5a } - if len(m.Stderr) > 0 { - dAtA[i] = 0x3a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) - i += copy(dAtA[i:], m.Stderr) + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintShim(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0x52 + if m.ExitStatus != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x48 } if m.Terminal { - dAtA[i] = 0x40 - i++ + i-- if m.Terminal { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x40 } - if m.ExitStatus != 0 { - dAtA[i] = 0x48 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + if len(m.Stderr) > 0 { + i -= len(m.Stderr) + copy(dAtA[i:], m.Stderr) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stderr))) + i-- + dAtA[i] = 0x3a } - dAtA[i] = 0x52 - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n4, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err + if len(m.Stdout) > 0 { + i -= len(m.Stdout) + copy(dAtA[i:], m.Stdout) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdout))) + i-- + dAtA[i] = 0x32 + } + if len(m.Stdin) > 0 { + i -= len(m.Stdin) + copy(dAtA[i:], m.Stdin) + i = encodeVarintShim(dAtA, i, uint64(len(m.Stdin))) + i-- + dAtA[i] = 0x2a + } + if m.Status != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x20 + } + if m.Pid != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x18 + } + if len(m.Bundle) > 0 { + i -= len(m.Bundle) + copy(dAtA[i:], m.Bundle) + i = encodeVarintShim(dAtA, i, uint64(len(m.Bundle))) + i-- + dAtA[i] = 0x12 } - i += n4 - return i, nil + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *KillRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } return dAtA[:n], nil -} - -func (m *KillRequest) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) - } - if m.Signal != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Signal)) +} + +func (m *KillRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KillRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.All { - dAtA[i] = 0x20 - i++ + i-- if m.All { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x20 + } + if m.Signal != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.Signal)) + i-- + dAtA[i] = 0x18 + } + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *CloseIORequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -826,39 +1815,50 @@ } func (m *CloseIORequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CloseIORequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) - } - if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Stdin { - dAtA[i] = 0x18 - i++ + i-- if m.Stdin { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x18 + } + if len(m.ExecID) > 0 { + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *PidsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -866,23 +1866,33 @@ } func (m *PidsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PidsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *PidsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -890,29 +1900,40 @@ } func (m *PidsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PidsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.Processes) > 0 { - for _, msg := range m.Processes { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + for iNdEx := len(m.Processes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Processes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n + i-- + dAtA[i] = 0xa } } - return i, nil + return len(dAtA) - i, nil } func (m *CheckpointTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -920,39 +1941,52 @@ } func (m *CheckpointTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CheckpointTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Options != nil { + { + size, err := m.Options.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } if len(m.Path) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.Path) + copy(dAtA[i:], m.Path) i = encodeVarintShim(dAtA, i, uint64(len(m.Path))) - i += copy(dAtA[i:], m.Path) + i-- + dAtA[i] = 0x12 } - if m.Options != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Options.Size())) - n5, err := m.Options.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n5 + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *UpdateTaskRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -960,33 +1994,64 @@ } func (m *UpdateTaskRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateTaskRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Annotations) > 0 { + for k := range m.Annotations { + v := m.Annotations[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintShim(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintShim(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintShim(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } } if m.Resources != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Resources.Size())) - n6, err := m.Resources.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Resources.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n6 + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -994,29 +2059,40 @@ } func (m *StartRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StartResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1024,22 +2100,31 @@ } func (m *StartResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Pid != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.Pid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *WaitRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1047,29 +2132,40 @@ } func (m *WaitRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ExecID) > 0 { - dAtA[i] = 0x12 - i++ + i -= len(m.ExecID) + copy(dAtA[i:], m.ExecID) i = encodeVarintShim(dAtA, i, uint64(len(m.ExecID))) - i += copy(dAtA[i:], m.ExecID) + i-- + dAtA[i] = 0x12 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *WaitResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1077,30 +2173,39 @@ } func (m *WaitResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WaitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.ExitedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt):]) + if err7 != nil { + return 0, err7 + } + i -= n7 + i = encodeVarintShim(dAtA, i, uint64(n7)) + i-- + dAtA[i] = 0x12 if m.ExitStatus != 0 { - dAtA[i] = 0x8 - i++ i = encodeVarintShim(dAtA, i, uint64(m.ExitStatus)) + i-- + dAtA[i] = 0x8 } - dAtA[i] = 0x12 - i++ - i = encodeVarintShim(dAtA, i, uint64(types.SizeOfStdTime(m.ExitedAt))) - n7, err := types.StdTimeMarshalTo(m.ExitedAt, dAtA[i:]) - if err != nil { - return 0, err - } - i += n7 - return i, nil + return len(dAtA) - i, nil } func (m *StatsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1108,23 +2213,33 @@ } func (m *StatsRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *StatsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1132,27 +2247,38 @@ } func (m *StatsResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StatsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if m.Stats != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(m.Stats.Size())) - n8, err := m.Stats.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + { + size, err := m.Stats.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintShim(dAtA, i, uint64(size)) } - i += n8 + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ConnectRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1160,23 +2286,33 @@ } func (m *ConnectRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConnectRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ConnectResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1184,33 +2320,43 @@ } func (m *ConnectResponse) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConnectResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if m.ShimPid != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintShim(dAtA, i, uint64(m.ShimPid)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintShim(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x1a } if m.TaskPid != 0 { - dAtA[i] = 0x10 - i++ i = encodeVarintShim(dAtA, i, uint64(m.TaskPid)) + i-- + dAtA[i] = 0x10 } - if len(m.Version) > 0 { - dAtA[i] = 0x1a - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.Version))) - i += copy(dAtA[i:], m.Version) + if m.ShimPid != 0 { + i = encodeVarintShim(dAtA, i, uint64(m.ShimPid)) + i-- + dAtA[i] = 0x8 } - return i, nil + return len(dAtA) - i, nil } func (m *ShutdownRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1218,33 +2364,43 @@ } func (m *ShutdownRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ShutdownRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l - if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } if m.Now { - dAtA[i] = 0x10 - i++ + i-- if m.Now { dAtA[i] = 1 } else { dAtA[i] = 0 } - i++ + i-- + dAtA[i] = 0x10 + } + if len(m.ID) > 0 { + i -= len(m.ID) + copy(dAtA[i:], m.ID) + i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *PauseRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1252,23 +2408,33 @@ } func (m *PauseRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PauseRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func (m *ResumeRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) if err != nil { return nil, err } @@ -1276,29 +2442,44 @@ } func (m *ResumeRequest) MarshalTo(dAtA []byte) (int, error) { - var i int + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResumeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) _ = i var l int _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } if len(m.ID) > 0 { - dAtA[i] = 0xa - i++ + i -= len(m.ID) + copy(dAtA[i:], m.ID) i = encodeVarintShim(dAtA, i, uint64(len(m.ID))) - i += copy(dAtA[i:], m.ID) + i-- + dAtA[i] = 0xa } - return i, nil + return len(dAtA) - i, nil } func encodeVarintShim(dAtA []byte, offset int, v uint64) int { + offset -= sovShim(v) + base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return offset + 1 + return base } func (m *CreateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1342,19 +2523,31 @@ l = m.Options.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CreateTaskResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { n += 1 + sovShim(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1365,10 +2558,16 @@ if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *DeleteResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { @@ -1377,12 +2576,18 @@ if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1412,16 +2617,28 @@ l = m.Spec.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ExecProcessResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ResizePtyRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1438,10 +2655,16 @@ if m.Height != 0 { n += 1 + sovShim(uint64(m.Height)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StateRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1452,10 +2675,16 @@ if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StateResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1490,12 +2719,22 @@ if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + l = len(m.ExecID) + if l > 0 { + n += 1 + l + sovShim(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *KillRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1512,10 +2751,16 @@ if m.All { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CloseIORequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1529,20 +2774,32 @@ if m.Stdin { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PidsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PidsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if len(m.Processes) > 0 { @@ -1551,10 +2808,16 @@ n += 1 + l + sovShim(uint64(l)) } } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *CheckpointTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1569,10 +2832,16 @@ l = m.Options.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *UpdateTaskRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1583,10 +2852,24 @@ l = m.Resources.Size() n += 1 + l + sovShim(uint64(l)) } + if len(m.Annotations) > 0 { + for k, v := range m.Annotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovShim(uint64(len(k))) + 1 + len(v) + sovShim(uint64(len(v))) + n += mapEntrySize + 1 + sovShim(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1597,19 +2880,31 @@ if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StartResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Pid != 0 { n += 1 + sovShim(uint64(m.Pid)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1620,51 +2915,81 @@ if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *WaitResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ExitStatus != 0 { n += 1 + sovShim(uint64(m.ExitStatus)) } - l = types.SizeOfStdTime(m.ExitedAt) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.ExitedAt) n += 1 + l + sovShim(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatsRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *StatsResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.Stats != nil { l = m.Stats.Size() n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ConnectRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ConnectResponse) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l if m.ShimPid != 0 { @@ -1677,10 +3002,16 @@ if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ShutdownRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) @@ -1690,38 +3021,46 @@ if m.Now { n += 2 } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *PauseRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func (m *ResumeRequest) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l l = len(m.ID) if l > 0 { n += 1 + l + sovShim(uint64(l)) } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } return n } func sovShim(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n + return (math_bits.Len64(x|1) + 6) / 7 } func sozShim(x uint64) (n int) { return sovShim(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1730,17 +3069,23 @@ if this == nil { return "nil" } + repeatedStringForRootfs := "[]*Mount{" + for _, f := range this.Rootfs { + repeatedStringForRootfs += strings.Replace(fmt.Sprintf("%v", f), "Mount", "types.Mount", 1) + "," + } + repeatedStringForRootfs += "}" s := strings.Join([]string{`&CreateTaskRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Bundle:` + fmt.Sprintf("%v", this.Bundle) + `,`, - `Rootfs:` + strings.Replace(fmt.Sprintf("%v", this.Rootfs), "Mount", "containerd_types.Mount", 1) + `,`, + `Rootfs:` + repeatedStringForRootfs + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Checkpoint:` + fmt.Sprintf("%v", this.Checkpoint) + `,`, `ParentCheckpoint:` + fmt.Sprintf("%v", this.ParentCheckpoint) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1751,6 +3096,7 @@ } s := strings.Join([]string{`&CreateTaskResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1762,6 +3108,7 @@ s := strings.Join([]string{`&DeleteRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1773,7 +3120,8 @@ s := strings.Join([]string{`&DeleteResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1789,7 +3137,8 @@ `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, `Stdout:` + fmt.Sprintf("%v", this.Stdout) + `,`, `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, - `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "google_protobuf.Any", 1) + `,`, + `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1799,6 +3148,7 @@ return "nil" } s := strings.Join([]string{`&ExecProcessResponse{`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1812,6 +3162,7 @@ `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Width:` + fmt.Sprintf("%v", this.Width) + `,`, `Height:` + fmt.Sprintf("%v", this.Height) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1823,6 +3174,7 @@ s := strings.Join([]string{`&StateRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1841,7 +3193,9 @@ `Stderr:` + fmt.Sprintf("%v", this.Stderr) + `,`, `Terminal:` + fmt.Sprintf("%v", this.Terminal) + `,`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1855,6 +3209,7 @@ `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Signal:` + fmt.Sprintf("%v", this.Signal) + `,`, `All:` + fmt.Sprintf("%v", this.All) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1867,6 +3222,7 @@ `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, `Stdin:` + fmt.Sprintf("%v", this.Stdin) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1877,6 +3233,7 @@ } s := strings.Join([]string{`&PidsRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1885,8 +3242,14 @@ if this == nil { return "nil" } + repeatedStringForProcesses := "[]*ProcessInfo{" + for _, f := range this.Processes { + repeatedStringForProcesses += strings.Replace(fmt.Sprintf("%v", f), "ProcessInfo", "task.ProcessInfo", 1) + "," + } + repeatedStringForProcesses += "}" s := strings.Join([]string{`&PidsResponse{`, - `Processes:` + strings.Replace(fmt.Sprintf("%v", this.Processes), "ProcessInfo", "containerd_v1_types.ProcessInfo", 1) + `,`, + `Processes:` + repeatedStringForProcesses + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1898,7 +3261,8 @@ s := strings.Join([]string{`&CheckpointTaskRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Path:` + fmt.Sprintf("%v", this.Path) + `,`, - `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "google_protobuf.Any", 1) + `,`, + `Options:` + strings.Replace(fmt.Sprintf("%v", this.Options), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1907,9 +3271,21 @@ if this == nil { return "nil" } + keysForAnnotations := make([]string, 0, len(this.Annotations)) + for k, _ := range this.Annotations { + keysForAnnotations = append(keysForAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + mapStringForAnnotations := "map[string]string{" + for _, k := range keysForAnnotations { + mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k]) + } + mapStringForAnnotations += "}" s := strings.Join([]string{`&UpdateTaskRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "google_protobuf.Any", 1) + `,`, + `Resources:` + strings.Replace(fmt.Sprintf("%v", this.Resources), "Any", "types1.Any", 1) + `,`, + `Annotations:` + mapStringForAnnotations + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1921,6 +3297,7 @@ s := strings.Join([]string{`&StartRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1931,6 +3308,7 @@ } s := strings.Join([]string{`&StartResponse{`, `Pid:` + fmt.Sprintf("%v", this.Pid) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1942,6 +3320,7 @@ s := strings.Join([]string{`&WaitRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1952,7 +3331,8 @@ } s := strings.Join([]string{`&WaitResponse{`, `ExitStatus:` + fmt.Sprintf("%v", this.ExitStatus) + `,`, - `ExitedAt:` + strings.Replace(strings.Replace(this.ExitedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `ExitedAt:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ExitedAt), "Timestamp", "types1.Timestamp", 1), `&`, ``, 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1963,6 +3343,7 @@ } s := strings.Join([]string{`&StatsRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1972,7 +3353,8 @@ return "nil" } s := strings.Join([]string{`&StatsResponse{`, - `Stats:` + strings.Replace(fmt.Sprintf("%v", this.Stats), "Any", "google_protobuf.Any", 1) + `,`, + `Stats:` + strings.Replace(fmt.Sprintf("%v", this.Stats), "Any", "types1.Any", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1983,6 +3365,7 @@ } s := strings.Join([]string{`&ConnectRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -1995,6 +3378,7 @@ `ShimPid:` + fmt.Sprintf("%v", this.ShimPid) + `,`, `TaskPid:` + fmt.Sprintf("%v", this.TaskPid) + `,`, `Version:` + fmt.Sprintf("%v", this.Version) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2006,6 +3390,7 @@ s := strings.Join([]string{`&ShutdownRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Now:` + fmt.Sprintf("%v", this.Now) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2016,6 +3401,7 @@ } s := strings.Join([]string{`&PauseRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2026,6 +3412,7 @@ } s := strings.Join([]string{`&ResumeRequest{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `}`, }, "") return s @@ -2045,22 +3432,22 @@ Start(ctx context.Context, req *StartRequest) (*StartResponse, error) Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) Pids(ctx context.Context, req *PidsRequest) (*PidsResponse, error) - Pause(ctx context.Context, req *PauseRequest) (*google_protobuf1.Empty, error) - Resume(ctx context.Context, req *ResumeRequest) (*google_protobuf1.Empty, error) - Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) - Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) - Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) - ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) - CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) - Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) + Pause(ctx context.Context, req *PauseRequest) (*types1.Empty, error) + Resume(ctx context.Context, req *ResumeRequest) (*types1.Empty, error) + Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*types1.Empty, error) + Kill(ctx context.Context, req *KillRequest) (*types1.Empty, error) + Exec(ctx context.Context, req *ExecProcessRequest) (*types1.Empty, error) + ResizePty(ctx context.Context, req *ResizePtyRequest) (*types1.Empty, error) + CloseIO(ctx context.Context, req *CloseIORequest) (*types1.Empty, error) + Update(ctx context.Context, req *UpdateTaskRequest) (*types1.Empty, error) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) Stats(ctx context.Context, req *StatsRequest) (*StatsResponse, error) Connect(ctx context.Context, req *ConnectRequest) (*ConnectResponse, error) - Shutdown(ctx context.Context, req *ShutdownRequest) (*google_protobuf1.Empty, error) + Shutdown(ctx context.Context, req *ShutdownRequest) (*types1.Empty, error) } -func RegisterTaskService(srv *ttrpc.Server, svc TaskService) { - srv.Register("containerd.task.v2.Task", map[string]ttrpc.Method{ +func RegisterTaskService(srv *github_com_containerd_ttrpc.Server, svc TaskService) { + srv.Register("containerd.task.v2.Task", map[string]github_com_containerd_ttrpc.Method{ "State": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { var req StateRequest if err := unmarshal(&req); err != nil { @@ -2184,10 +3571,10 @@ } type taskClient struct { - client *ttrpc.Client + client *github_com_containerd_ttrpc.Client } -func NewTaskClient(client *ttrpc.Client) TaskService { +func NewTaskClient(client *github_com_containerd_ttrpc.Client) TaskService { return &taskClient{ client: client, } @@ -2233,64 +3620,64 @@ return &resp, nil } -func (c *taskClient) Pause(ctx context.Context, req *PauseRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Pause(ctx context.Context, req *PauseRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Pause", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) Resume(ctx context.Context, req *ResumeRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Resume(ctx context.Context, req *ResumeRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Resume", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Checkpoint", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) Kill(ctx context.Context, req *KillRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Kill(ctx context.Context, req *KillRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Kill", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) Exec(ctx context.Context, req *ExecProcessRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Exec(ctx context.Context, req *ExecProcessRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Exec", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "ResizePty", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) CloseIO(ctx context.Context, req *CloseIORequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) CloseIO(ctx context.Context, req *CloseIORequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "CloseIO", req, &resp); err != nil { return nil, err } return &resp, nil } -func (c *taskClient) Update(ctx context.Context, req *UpdateTaskRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Update(ctx context.Context, req *UpdateTaskRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Update", req, &resp); err != nil { return nil, err } @@ -2321,8 +3708,8 @@ return &resp, nil } -func (c *taskClient) Shutdown(ctx context.Context, req *ShutdownRequest) (*google_protobuf1.Empty, error) { - var resp google_protobuf1.Empty +func (c *taskClient) Shutdown(ctx context.Context, req *ShutdownRequest) (*types1.Empty, error) { + var resp types1.Empty if err := c.client.Call(ctx, "containerd.task.v2.Task", "Shutdown", req, &resp); err != nil { return nil, err } @@ -2343,7 +3730,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2371,7 +3758,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2381,6 +3768,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2400,7 +3790,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2410,6 +3800,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2429,7 +3822,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2438,10 +3831,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Rootfs = append(m.Rootfs, &containerd_types.Mount{}) + m.Rootfs = append(m.Rootfs, &types.Mount{}) if err := m.Rootfs[len(m.Rootfs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -2460,7 +3856,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2480,7 +3876,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2490,6 +3886,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2509,7 +3908,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2519,6 +3918,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2538,7 +3940,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2548,6 +3950,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2567,7 +3972,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2577,6 +3982,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2596,7 +4004,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2606,6 +4014,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2625,7 +4036,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2634,11 +4045,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2650,12 +4064,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2680,7 +4095,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2708,7 +4123,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2719,12 +4134,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2749,7 +4165,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2777,7 +4193,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2787,6 +4203,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2806,7 +4225,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2816,6 +4235,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2827,12 +4249,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2857,7 +4280,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -2885,7 +4308,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2904,7 +4327,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -2923,7 +4346,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -2932,10 +4355,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -2945,12 +4371,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -2975,7 +4402,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3003,7 +4430,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3013,6 +4440,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3032,7 +4462,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3042,6 +4472,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3061,7 +4494,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3081,7 +4514,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3091,6 +4524,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3110,7 +4546,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3120,6 +4556,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3139,7 +4578,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3149,6 +4588,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3168,7 +4610,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3177,11 +4619,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Spec == nil { - m.Spec = &google_protobuf.Any{} + m.Spec = &types1.Any{} } if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -3193,12 +4638,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3223,7 +4669,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3243,12 +4689,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3273,7 +4720,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3301,7 +4748,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3311,6 +4758,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3330,7 +4780,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3340,6 +4790,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3359,7 +4812,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Width |= (uint32(b) & 0x7F) << shift + m.Width |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3378,7 +4831,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Height |= (uint32(b) & 0x7F) << shift + m.Height |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3389,12 +4842,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3419,7 +4873,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3447,7 +4901,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3457,6 +4911,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3476,7 +4933,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3486,6 +4943,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3497,12 +4957,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3527,7 +4988,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3555,7 +5016,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3565,6 +5026,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3584,7 +5048,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3594,6 +5058,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3613,7 +5080,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3632,7 +5099,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Status |= (containerd_v1_types.Status(b) & 0x7F) << shift + m.Status |= task.Status(b&0x7F) << shift if b < 0x80 { break } @@ -3651,7 +5118,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3661,6 +5128,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3680,7 +5150,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3690,6 +5160,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3709,7 +5182,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3719,6 +5192,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3738,7 +5214,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3758,7 +5234,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3777,7 +5253,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3786,25 +5262,61 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowShim + } + 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 ErrInvalidLengthShim + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExecID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipShim(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3829,7 +5341,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3857,7 +5369,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3867,6 +5379,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3886,7 +5401,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -3896,6 +5411,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3915,7 +5433,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Signal |= (uint32(b) & 0x7F) << shift + m.Signal |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -3934,7 +5452,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -3946,12 +5464,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -3976,7 +5495,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4004,7 +5523,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4014,6 +5533,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4033,7 +5555,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4043,6 +5565,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4062,7 +5587,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4074,12 +5599,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4104,7 +5630,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4132,7 +5658,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4142,6 +5668,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4153,12 +5682,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4183,7 +5713,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4211,7 +5741,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4220,10 +5750,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - m.Processes = append(m.Processes, &containerd_v1_types.ProcessInfo{}) + m.Processes = append(m.Processes, &task.ProcessInfo{}) if err := m.Processes[len(m.Processes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -4234,12 +5767,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4264,7 +5798,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4292,7 +5826,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4302,6 +5836,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4321,7 +5858,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4331,6 +5868,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4350,7 +5890,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4359,11 +5899,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Options == nil { - m.Options = &google_protobuf.Any{} + m.Options = &types1.Any{} } if err := m.Options.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -4375,12 +5918,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4405,7 +5949,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4433,7 +5977,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4443,6 +5987,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4462,7 +6009,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4471,28 +6018,159 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Resources == nil { - m.Resources = &google_protobuf.Any{} + m.Resources = &types1.Any{} } if err := m.Resources.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowShim + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthShim + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Annotations == nil { + m.Annotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowShim + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowShim + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthShim + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthShim + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowShim + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthShim + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthShim + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipShim(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthShim + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Annotations[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipShim(dAtA[iNdEx:]) if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4517,7 +6195,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4545,7 +6223,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4555,6 +6233,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4574,7 +6255,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4584,6 +6265,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4595,12 +6279,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4625,7 +6310,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4653,7 +6338,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.Pid |= (uint32(b) & 0x7F) << shift + m.Pid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4664,12 +6349,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4694,7 +6380,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4722,7 +6408,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4732,6 +6418,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4751,7 +6440,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4761,6 +6450,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4772,12 +6464,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4802,7 +6495,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4830,7 +6523,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ExitStatus |= (uint32(b) & 0x7F) << shift + m.ExitStatus |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -4849,7 +6542,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -4858,10 +6551,13 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } - if err := types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.ExitedAt, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -4871,12 +6567,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4901,7 +6598,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4929,7 +6626,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -4939,6 +6636,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -4950,12 +6650,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -4980,7 +6681,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5008,7 +6709,7 @@ } b := dAtA[iNdEx] iNdEx++ - msglen |= (int(b) & 0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5017,11 +6718,14 @@ return ErrInvalidLengthShim } postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } if m.Stats == nil { - m.Stats = &google_protobuf.Any{} + m.Stats = &types1.Any{} } if err := m.Stats.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -5033,12 +6737,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5063,7 +6768,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5091,7 +6796,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5101,6 +6806,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5112,12 +6820,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5142,7 +6851,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5170,7 +6879,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.ShimPid |= (uint32(b) & 0x7F) << shift + m.ShimPid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -5189,7 +6898,7 @@ } b := dAtA[iNdEx] iNdEx++ - m.TaskPid |= (uint32(b) & 0x7F) << shift + m.TaskPid |= uint32(b&0x7F) << shift if b < 0x80 { break } @@ -5208,7 +6917,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5218,6 +6927,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5229,12 +6941,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5259,7 +6972,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5287,7 +7000,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5297,6 +7010,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5316,7 +7032,7 @@ } b := dAtA[iNdEx] iNdEx++ - v |= (int(b) & 0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } @@ -5328,12 +7044,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5358,7 +7075,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5386,7 +7103,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5396,6 +7113,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5407,12 +7127,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5437,7 +7158,7 @@ } b := dAtA[iNdEx] iNdEx++ - wire |= (uint64(b) & 0x7F) << shift + wire |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5465,7 +7186,7 @@ } b := dAtA[iNdEx] iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -5475,6 +7196,9 @@ return ErrInvalidLengthShim } postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthShim + } if postIndex > l { return io.ErrUnexpectedEOF } @@ -5486,12 +7210,13 @@ if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthShim } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -5504,6 +7229,7 @@ func skipShim(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -5535,10 +7261,8 @@ break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -5555,139 +7279,34 @@ break } } - iNdEx += length if length < 0 { return 0, ErrInvalidLengthShim } - return iNdEx, nil + iNdEx += length case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowShim - } - 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 := skipShim(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupShim + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthShim + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthShim = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowShim = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthShim = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowShim = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupShim = fmt.Errorf("proto: unexpected end of group") ) - -func init() { - proto.RegisterFile("github.com/containerd/containerd/runtime/v2/task/shim.proto", fileDescriptorShim) -} - -var fileDescriptorShim = []byte{ - // 1240 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0xdb, 0x6f, 0x1b, 0xc5, - 0x17, 0xee, 0xfa, 0xb2, 0xb6, 0x8f, 0xeb, 0x34, 0x9d, 0x5f, 0x9a, 0xdf, 0xd6, 0x95, 0x6c, 0x77, - 0x4b, 0x83, 0x01, 0xc9, 0x16, 0xae, 0xe0, 0x81, 0x48, 0xa0, 0xdc, 0xa8, 0x4c, 0x0b, 0x89, 0xb6, - 0x45, 0x45, 0xbc, 0x58, 0x1b, 0xef, 0xc4, 0x5e, 0xc5, 0xde, 0x59, 0x76, 0x66, 0x73, 0x41, 0x42, - 0xe2, 0x89, 0x07, 0x9e, 0xf8, 0xb3, 0xf2, 0xc0, 0x03, 0x12, 0x2f, 0xbc, 0x10, 0xa8, 0xff, 0x12, - 0x34, 0x17, 0xc7, 0x6b, 0x67, 0xd7, 0x4e, 0x2a, 0xbf, 0x44, 0x73, 0x76, 0xbe, 0x39, 0x33, 0xe7, - 0xcc, 0x77, 0xbe, 0x33, 0x31, 0x6c, 0xf6, 0x5c, 0xd6, 0x0f, 0x0f, 0x1b, 0x5d, 0x32, 0x6c, 0x76, - 0x89, 0xc7, 0x6c, 0xd7, 0xc3, 0x81, 0x13, 0x1d, 0x06, 0xa1, 0xc7, 0xdc, 0x21, 0x6e, 0x9e, 0xb4, - 0x9a, 0xcc, 0xa6, 0xc7, 0x4d, 0xda, 0x77, 0x87, 0x0d, 0x3f, 0x20, 0x8c, 0x20, 0x34, 0x81, 0x35, - 0xf8, 0x5c, 0xe3, 0xa4, 0x55, 0x7e, 0xd8, 0x23, 0xa4, 0x37, 0xc0, 0x4d, 0x81, 0x38, 0x0c, 0x8f, - 0x9a, 0xb6, 0x77, 0x2e, 0xe1, 0xe5, 0x47, 0xb3, 0x53, 0x78, 0xe8, 0xb3, 0xf1, 0xe4, 0x5a, 0x8f, - 0xf4, 0x88, 0x18, 0x36, 0xf9, 0x48, 0x7d, 0xad, 0xce, 0x2e, 0xe1, 0x47, 0xa1, 0xcc, 0x1e, 0xfa, - 0x0a, 0xf0, 0xe9, 0xc2, 0xf3, 0xdb, 0xbe, 0xdb, 0x64, 0xe7, 0x3e, 0xa6, 0xcd, 0x21, 0x09, 0x3d, - 0xa6, 0xd6, 0x7d, 0x76, 0x8b, 0x75, 0x22, 0x6c, 0x11, 0x9f, 0x58, 0x6b, 0xfe, 0x99, 0x82, 0xfb, - 0x3b, 0x01, 0xb6, 0x19, 0x7e, 0x6d, 0xd3, 0x63, 0x0b, 0xff, 0x10, 0x62, 0xca, 0xd0, 0x3a, 0xa4, - 0x5c, 0xc7, 0xd0, 0x6a, 0x5a, 0xbd, 0xb0, 0xad, 0x8f, 0x2e, 0xab, 0xa9, 0xf6, 0xae, 0x95, 0x72, - 0x1d, 0xb4, 0x0e, 0xfa, 0x61, 0xe8, 0x39, 0x03, 0x6c, 0xa4, 0xf8, 0x9c, 0xa5, 0x2c, 0xd4, 0x04, - 0x3d, 0x20, 0x84, 0x1d, 0x51, 0x23, 0x5d, 0x4b, 0xd7, 0x8b, 0xad, 0xff, 0x37, 0xa2, 0xd9, 0xe4, - 0x1b, 0x37, 0xbe, 0xe6, 0x07, 0xb6, 0x14, 0x0c, 0x95, 0x21, 0xcf, 0x70, 0x30, 0x74, 0x3d, 0x7b, - 0x60, 0x64, 0x6a, 0x5a, 0x3d, 0x6f, 0x5d, 0xd9, 0x68, 0x0d, 0xb2, 0x94, 0x39, 0xae, 0x67, 0x64, - 0xc5, 0x1e, 0xd2, 0xe0, 0x5b, 0x53, 0xe6, 0x90, 0x90, 0x19, 0xba, 0xdc, 0x5a, 0x5a, 0xea, 0x3b, - 0x0e, 0x02, 0x23, 0x77, 0xf5, 0x1d, 0x07, 0x01, 0xaa, 0x00, 0x74, 0xfb, 0xb8, 0x7b, 0xec, 0x13, - 0xd7, 0x63, 0x46, 0x5e, 0xcc, 0x45, 0xbe, 0xa0, 0x8f, 0xe0, 0xbe, 0x6f, 0x07, 0xd8, 0x63, 0x9d, - 0x08, 0xac, 0x20, 0x60, 0xab, 0x72, 0x62, 0x67, 0x02, 0x6e, 0x40, 0x8e, 0xf8, 0xcc, 0x25, 0x1e, - 0x35, 0xa0, 0xa6, 0xd5, 0x8b, 0xad, 0xb5, 0x86, 0xbc, 0xcc, 0xc6, 0xf8, 0x32, 0x1b, 0x5b, 0xde, - 0xb9, 0x35, 0x06, 0x99, 0x1b, 0x80, 0xa2, 0x49, 0xa5, 0x3e, 0xf1, 0x28, 0x46, 0xab, 0x90, 0xf6, - 0x55, 0x5a, 0x4b, 0x16, 0x1f, 0x9a, 0x2f, 0xa1, 0xb4, 0x8b, 0x07, 0x98, 0xe1, 0x45, 0x89, 0x7f, - 0x02, 0x39, 0x7c, 0x86, 0xbb, 0x1d, 0xd7, 0x91, 0x99, 0xdf, 0x86, 0xd1, 0x65, 0x55, 0xdf, 0x3b, - 0xc3, 0xdd, 0xf6, 0xae, 0xa5, 0xf3, 0xa9, 0xb6, 0x63, 0xfe, 0xa2, 0xc1, 0xca, 0xd8, 0x5d, 0xd2, - 0x96, 0xa8, 0x0a, 0x45, 0x7c, 0xe6, 0xb2, 0x0e, 0x65, 0x36, 0x0b, 0xa9, 0xf0, 0x56, 0xb2, 0x80, - 0x7f, 0x7a, 0x25, 0xbe, 0xa0, 0x2d, 0x28, 0x70, 0x0b, 0x3b, 0x1d, 0x9b, 0x19, 0x69, 0x11, 0x6d, - 0xf9, 0x5a, 0xb4, 0xaf, 0xc7, 0xd4, 0xdd, 0xce, 0x5f, 0x5c, 0x56, 0xef, 0xfc, 0xf6, 0x4f, 0x55, - 0xb3, 0xf2, 0x72, 0xd9, 0x16, 0x33, 0xff, 0xd6, 0x00, 0xf1, 0xb3, 0x1d, 0x04, 0xa4, 0x8b, 0x29, - 0x5d, 0x46, 0x70, 0x53, 0x8c, 0x49, 0x27, 0x31, 0x26, 0x13, 0xcf, 0x98, 0x6c, 0x02, 0x63, 0xf4, - 0x29, 0xc6, 0xd4, 0x21, 0x43, 0x7d, 0xdc, 0x15, 0x3c, 0x4a, 0xba, 0x61, 0x81, 0x30, 0x1f, 0xc0, - 0xff, 0xa6, 0xc2, 0x93, 0xc9, 0x36, 0x7f, 0x82, 0x55, 0x0b, 0x53, 0xf7, 0x47, 0x7c, 0xc0, 0xce, - 0x97, 0x12, 0xf3, 0x1a, 0x64, 0x4f, 0x5d, 0x87, 0xf5, 0x45, 0xc0, 0x25, 0x4b, 0x1a, 0xfc, 0xfc, - 0x7d, 0xec, 0xf6, 0xfa, 0x4c, 0x84, 0x5b, 0xb2, 0x94, 0x65, 0xbe, 0x80, 0xbb, 0xfc, 0x0a, 0x97, - 0xc3, 0xa5, 0xdf, 0x53, 0x50, 0x52, 0xde, 0x14, 0x95, 0x6e, 0xab, 0x09, 0x8a, 0x7a, 0xe9, 0x09, - 0xf5, 0x9e, 0xf1, 0xc4, 0x0b, 0xd6, 0xf1, 0x83, 0xaf, 0xb4, 0x1e, 0x45, 0x55, 0xe2, 0xe4, 0x63, - 0x25, 0x14, 0x92, 0x86, 0x96, 0x82, 0x2e, 0x49, 0x0d, 0xa2, 0xec, 0xc9, 0xcf, 0xb0, 0x67, 0xa6, - 0x22, 0x0a, 0xf3, 0x2b, 0x02, 0xde, 0xa9, 0x22, 0x18, 0x14, 0x5f, 0xb8, 0x83, 0xc1, 0x52, 0x58, - 0xc1, 0x63, 0x74, 0x7b, 0xe3, 0x3a, 0x28, 0x59, 0xca, 0xe2, 0x09, 0xb7, 0x07, 0x63, 0x39, 0xe5, - 0x43, 0xb3, 0x0b, 0x2b, 0x3b, 0x03, 0x42, 0x71, 0x7b, 0x7f, 0x59, 0x74, 0x94, 0x57, 0x21, 0xeb, - 0x4f, 0x1a, 0xe6, 0x53, 0x28, 0x1e, 0xb8, 0xce, 0xa2, 0x22, 0x37, 0xbf, 0x81, 0xbb, 0x12, 0xa6, - 0xe8, 0xf4, 0x39, 0x14, 0x7c, 0x59, 0x3f, 0x98, 0x1a, 0x9a, 0xe8, 0x1a, 0xb5, 0x58, 0x3e, 0xa8, - 0x2a, 0x6b, 0x7b, 0x47, 0xc4, 0x9a, 0x2c, 0x31, 0x29, 0x3c, 0x98, 0x08, 0xf4, 0x4d, 0x7a, 0x17, - 0x82, 0x8c, 0x6f, 0xb3, 0xbe, 0x62, 0xa9, 0x18, 0x47, 0x75, 0x3d, 0x7d, 0x13, 0x5d, 0xef, 0xc0, - 0xfd, 0x6f, 0x7d, 0xe7, 0x86, 0xcd, 0xb2, 0x05, 0x85, 0x00, 0x53, 0x12, 0x06, 0x5d, 0x2c, 0x75, - 0x36, 0xc9, 0xfd, 0x04, 0xa6, 0x6a, 0x38, 0x60, 0x4b, 0xa9, 0xe1, 0xc7, 0xa2, 0x84, 0xb9, 0xb3, - 0xc4, 0x06, 0xf4, 0x15, 0x14, 0xdf, 0xd8, 0xee, 0x72, 0xb6, 0x0b, 0xe0, 0xae, 0xf4, 0xa5, 0x76, - 0x9b, 0xa9, 0x2b, 0x6d, 0x7e, 0x5d, 0xa5, 0xde, 0xa9, 0xae, 0x36, 0xa4, 0xe6, 0x2d, 0x64, 0xdf, - 0xa6, 0x54, 0xb3, 0x09, 0xfd, 0x3e, 0xe4, 0x5c, 0xb6, 0x99, 0x3c, 0x56, 0xd2, 0xc5, 0x48, 0x88, - 0x59, 0x87, 0x95, 0x1d, 0xe2, 0x79, 0xb8, 0xbb, 0x28, 0x4f, 0xa6, 0x0d, 0xf7, 0xae, 0x90, 0x6a, - 0xa3, 0x87, 0x90, 0xe7, 0xaf, 0xcc, 0xce, 0x24, 0xf1, 0x39, 0x6e, 0x1f, 0xb8, 0x0e, 0x9f, 0xe2, - 0x2f, 0x31, 0x31, 0x25, 0xfb, 0x70, 0x8e, 0xdb, 0x7c, 0xca, 0x80, 0xdc, 0x09, 0x0e, 0xa8, 0x4b, - 0x64, 0xb1, 0x15, 0xac, 0xb1, 0x69, 0x6e, 0xc2, 0xbd, 0x57, 0xfd, 0x90, 0x39, 0xe4, 0xd4, 0x5b, - 0x74, 0x6b, 0xab, 0x90, 0xf6, 0xc8, 0xa9, 0x70, 0x9d, 0xb7, 0xf8, 0x90, 0xa7, 0xeb, 0xc0, 0x0e, - 0xe9, 0xa2, 0x16, 0x61, 0xbe, 0x0f, 0x25, 0x0b, 0xd3, 0x70, 0xb8, 0x08, 0xd8, 0xfa, 0x15, 0x20, - 0xc3, 0x6b, 0x01, 0xbd, 0x84, 0xac, 0x68, 0x17, 0x68, 0xaa, 0x88, 0xd5, 0x43, 0xba, 0x11, 0xed, - 0x4b, 0xe5, 0xc7, 0x73, 0x10, 0x2a, 0x69, 0x6f, 0x40, 0x97, 0xef, 0x27, 0xf4, 0x34, 0x0e, 0x7c, - 0xed, 0xc1, 0x5a, 0xde, 0x58, 0x04, 0x53, 0x8e, 0xe5, 0x31, 0x03, 0x96, 0x78, 0xcc, 0xab, 0xd2, - 0x4b, 0x3c, 0x66, 0xa4, 0x9e, 0xf6, 0x41, 0x97, 0xef, 0x2d, 0x14, 0x0b, 0x9e, 0x7a, 0xda, 0x95, - 0xcd, 0x79, 0x10, 0xe5, 0xb0, 0x0d, 0x19, 0x2e, 0x92, 0xa8, 0x1a, 0x87, 0x8d, 0xa8, 0x6c, 0xb9, - 0x96, 0x0c, 0x50, 0xae, 0xb6, 0x20, 0x2b, 0xae, 0x3a, 0x3e, 0xd2, 0x28, 0x0b, 0xca, 0xeb, 0xd7, - 0xc8, 0xbf, 0xc7, 0xff, 0x99, 0x41, 0x3b, 0xa0, 0x4b, 0x16, 0xc4, 0x87, 0x37, 0xc5, 0x90, 0x44, - 0x27, 0xfb, 0x00, 0x91, 0x87, 0xf4, 0x07, 0xb1, 0xf7, 0x14, 0xa7, 0xe3, 0x89, 0x0e, 0xbf, 0x80, - 0x0c, 0x6f, 0xa5, 0xf1, 0x39, 0x8a, 0x34, 0xd9, 0x44, 0x07, 0x5f, 0x42, 0x86, 0x2b, 0x17, 0x8a, - 0xe5, 0xcc, 0xf5, 0x67, 0x6b, 0xa2, 0x9f, 0x36, 0x14, 0xae, 0x9e, 0x7b, 0xe8, 0xbd, 0x84, 0x0c, - 0x4d, 0xbd, 0x06, 0x13, 0x5d, 0xed, 0x41, 0x4e, 0x35, 0x6a, 0x14, 0x4b, 0x93, 0xe9, 0x2e, 0x9e, - 0xe8, 0xe6, 0x39, 0xe8, 0xb2, 0x3d, 0xc5, 0x97, 0xcd, 0xb5, 0xd6, 0x35, 0x27, 0xb4, 0x0c, 0x97, - 0xf2, 0xf8, 0x1c, 0x47, 0x1a, 0x46, 0x3c, 0x0f, 0xa7, 0xba, 0x80, 0x12, 0x06, 0x9a, 0x2c, 0x0c, - 0x74, 0xa1, 0x30, 0x4c, 0x58, 0x6d, 0x41, 0x4e, 0x09, 0x6c, 0x42, 0xa2, 0xa6, 0x74, 0xba, 0xfc, - 0x64, 0x2e, 0x46, 0xf9, 0x7c, 0x0e, 0xf9, 0xb1, 0xa2, 0xa2, 0xd8, 0x05, 0x33, 0x7a, 0x9b, 0x94, - 0xb5, 0xed, 0xfd, 0x8b, 0xb7, 0x95, 0x3b, 0x7f, 0xbd, 0xad, 0xdc, 0xf9, 0x79, 0x54, 0xd1, 0x2e, - 0x46, 0x15, 0xed, 0x8f, 0x51, 0x45, 0xfb, 0x77, 0x54, 0xd1, 0xbe, 0xff, 0xe4, 0xb6, 0xbf, 0x4c, - 0x6c, 0xf2, 0x3f, 0xdf, 0xa5, 0x0e, 0x75, 0xb1, 0xc5, 0xb3, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x11, 0x4c, 0x17, 0x02, 0xdb, 0x10, 0x00, 0x00, -} diff -Nru containerd-1.2.6/runtime/v2/task/shim.proto containerd-1.5.9/runtime/v2/task/shim.proto --- containerd-1.2.6/runtime/v2/task/shim.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/runtime/v2/task/shim.proto 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + syntax = "proto3"; package containerd.task.v2; @@ -99,6 +115,7 @@ bool terminal = 8; uint32 exit_status = 9; google.protobuf.Timestamp exited_at = 10 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + string exec_id = 11; } message KillRequest { @@ -131,6 +148,7 @@ message UpdateTaskRequest { string id = 1; google.protobuf.Any resources = 2; + map annotations = 3; } message StartRequest { diff -Nru containerd-1.2.6/SCOPE.md containerd-1.5.9/SCOPE.md --- containerd-1.2.6/SCOPE.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/SCOPE.md 2022-01-05 17:30:58.000000000 +0000 @@ -52,6 +52,6 @@ ### How is the scope changed? -The scope of this project is a whitelist. +The scope of this project is an allowed list. If it's not mentioned as being in scope, it is out of scope. For the scope of this project to change it requires a 100% vote from all maintainers of the project. diff -Nru containerd-1.2.6/script/setup/config-containerd containerd-1.5.9/script/setup/config-containerd --- containerd-1.2.6/script/setup/config-containerd 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/config-containerd 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# establishes /etc/containerd/config.toml +# parameterized by the current SELinux mode +# +set -eux -o pipefail + +enable_selinux=false + +if type -p getenforce &>/dev/null && [[ $(getenforce) != Disabled ]]; then + enable_selinux=true +fi + +mkdir -p /etc/containerd + +cat << EOF | sudo tee /etc/containerd/config.toml +version = 2 +[plugins] + [plugins."io.containerd.grpc.v1.cri"] + enable_selinux = ${enable_selinux} +EOF diff -Nru containerd-1.2.6/script/setup/config-selinux containerd-1.5.9/script/setup/config-selinux --- containerd-1.2.6/script/setup/config-selinux 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/config-selinux 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# set the desired SELinux mode via envvar +# +set -eux -o pipefail + +if ! type -p getenforce setenforce &>/dev/null; then + echo SELinux is Disabled + exit 0 +fi + +case "${SELINUX}" in + Disabled) + if mountpoint -q /sys/fs/selinux; then + setenforce 0 + umount -v /sys/fs/selinux + fi + ;; + Enforcing) + mountpoint -q /sys/fs/selinux || mount -o rw,relatime -t selinuxfs selinuxfs /sys/fs/selinux + setenforce 1 + ;; + Permissive) + mountpoint -q /sys/fs/selinux || mount -o rw,relatime -t selinuxfs selinuxfs /sys/fs/selinux + setenforce 0 + ;; + *) + echo "SELinux mode not supported: ${SELINUX}" >&2 + exit 1 + ;; +esac + +echo SELinux is $(getenforce) diff -Nru containerd-1.2.6/script/setup/critools-version containerd-1.5.9/script/setup/critools-version --- containerd-1.2.6/script/setup/critools-version 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/critools-version 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +53ad8bb7f97e1b1d1c0c0634e43a3c2b8b07b718 diff -Nru containerd-1.2.6/script/setup/imgcrypt-version containerd-1.5.9/script/setup/imgcrypt-version --- containerd-1.2.6/script/setup/imgcrypt-version 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/imgcrypt-version 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +8eebb5ea37f38ff04f1a543252bdcd78cef7ce6b diff -Nru containerd-1.2.6/script/setup/install-cni containerd-1.5.9/script/setup/install-cni --- containerd-1.2.6/script/setup/install-cni 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/script/setup/install-cni 2022-01-05 17:30:58.000000000 +0000 @@ -17,24 +17,25 @@ # # Builds and installs cni plugins to /opt/cni/bin, # and create basic cni config in /etc/cni/net.d. -# The commit defined in vendor.conf +# The commit defined in go.mod # set -eu -o pipefail -CNI_COMMIT=$(grep containernetworking/plugins ${GOPATH}/src/github.com/containerd/containerd/vendor.conf | cut -d " " -f 2) -CNI_DIR=/opt/cni -CNI_CONFIG_DIR=/etc/cni/net.d +CNI_COMMIT=$(grep containernetworking/plugins "$GOPATH"/src/github.com/containerd/containerd/go.mod | awk '{print $2}') +CNI_DIR=${DESTDIR:=''}/opt/cni +CNI_CONFIG_DIR=${DESTDIR}/etc/cni/net.d -go get -d github.com/containernetworking/plugins/... -cd $GOPATH/src/github.com/containernetworking/plugins +TMPROOT=$(mktemp -d) +git clone https://github.com/containernetworking/plugins.git "${TMPROOT}"/plugins +pushd "${TMPROOT}"/plugins git checkout $CNI_COMMIT -FASTBUILD=true ./build.sh +./build_linux.sh mkdir -p $CNI_DIR cp -r ./bin $CNI_DIR mkdir -p $CNI_CONFIG_DIR -bash -c 'cat >'$CNI_CONFIG_DIR'/10-containerd-net.conflist <= 8 )); then + mask=255 + elif (( len > 0 )); then + mask=$(( 256 - 2 ** ( 8 - len ) )) + else + mask=0 + fi + (( len -= 8 )) + result_array[i]=$(( gateway_array[i] & mask )) + done + result="$(printf ".%s" "${result_array[@]}")" + result="${result:1}" + echo "$result/$((32 - prefix_len))" +} + +# nat already exists on the Windows VM, the subnet and gateway +# we specify should match that. +gateway="$(powershell -c "(Get-NetIPAddress -InterfaceAlias 'vEthernet (nat)' -AddressFamily IPv4).IPAddress")" +prefix_len="$(powershell -c "(Get-NetIPAddress -InterfaceAlias 'vEthernet (nat)' -AddressFamily IPv4).PrefixLength")" + +subnet="$(calculate_subnet "$gateway" "$prefix_len")" + +# The "name" field in the config is used as the underlying +# network type right now (see +# https://github.com/microsoft/windows-container-networking/pull/45), +# so it must match a network type in: +# https://docs.microsoft.com/en-us/windows-server/networking/technologies/hcn/hcn-json-document-schemas +bash -c 'cat >"'"${CNI_CONFIG_DIR}"'"/0-containerd-nat.conf < /dev/null 2>&1; pwd -P)" + +cd "$GOPATH" go get -u github.com/onsi/ginkgo/ginkgo -CRITEST_COMMIT=v1.12.0 -go get -d github.com/kubernetes-incubator/cri-tools/... -cd $GOPATH/src/github.com/kubernetes-incubator/cri-tools -git checkout $CRITEST_COMMIT + +: "${CRITEST_COMMIT:=$(cat "${script_dir}/critools-version")}" + +TMPROOT=$(mktemp -d) +git clone https://github.com/kubernetes-sigs/cri-tools.git "${TMPROOT}"/cri-tools +pushd "${TMPROOT}"/cri-tools +git checkout "$CRITEST_COMMIT" make -make install +make install -e DESTDIR=${DESTDIR:=''} BINDIR=/usr/local/bin + +cat << EOF | tee ${DESTDIR:=''}/etc/crictl.yaml +runtime-endpoint: unix:///run/containerd/containerd.sock +EOF + +popd +rm -fR "${TMPROOT}" diff -Nru containerd-1.2.6/script/setup/install-dev-tools containerd-1.5.9/script/setup/install-dev-tools --- containerd-1.2.6/script/setup/install-dev-tools 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/script/setup/install-dev-tools 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,18 @@ # set -eu -o pipefail -go get -u github.com/stevvooe/protobuild -go get -u github.com/alecthomas/gometalinter -gometalinter --install >/dev/null -go get -u github.com/cpuguy83/go-md2man +# change to tmp dir, otherwise `go get` will change go.mod +cd "$GOPATH" + +# install the `protobuild` binary in $GOPATH/bin; requires module-aware install +# to pin dependencies +GO111MODULE=on go get github.com/stevvooe/protobuild + +# the following packages need to exist in $GOPATH so we can't use +# go modules-aware mode of `go get` for these includes used during +# proto building +GO111MODULE=off go get -d github.com/gogo/googleapis || true +GO111MODULE=off go get -d github.com/gogo/protobuf || true + +GO111MODULE=on go get github.com/cpuguy83/go-md2man/v2@v2.0.0 +GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.38.0 diff -Nru containerd-1.2.6/script/setup/install-gotestsum containerd-1.5.9/script/setup/install-gotestsum --- containerd-1.2.6/script/setup/install-gotestsum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/install-gotestsum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +GO111MODULE=on go install gotest.tools/gotestsum@v1.6.2 \ No newline at end of file diff -Nru containerd-1.2.6/script/setup/install-imgcrypt containerd-1.5.9/script/setup/install-imgcrypt --- containerd-1.2.6/script/setup/install-imgcrypt 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/install-imgcrypt 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Builds and installs imgcrypt including ctd-decoder and ctr-enc +# to /usr/local/bin. +# +set -eu -o pipefail + +script_dir="$(cd -- "$(dirname -- "$0")" > /dev/null 2>&1; pwd -P)" + +: "${IMGCRYPT_COMMIT:=$(cat "${script_dir}/imgcrypt-version")}" + +TMPROOT=$(mktemp -d) +git clone https://github.com/containerd/imgcrypt.git "${TMPROOT}"/imgcrypt +pushd "${TMPROOT}"/imgcrypt +git checkout "${IMGCRYPT_COMMIT}" +make +make containerd-release -e DESTDIR="${DESTDIR}/usr/local" + +popd +rm -fR "${TMPROOT}" diff -Nru containerd-1.2.6/script/setup/install-protobuf containerd-1.5.9/script/setup/install-protobuf --- containerd-1.2.6/script/setup/install-protobuf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/script/setup/install-protobuf 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,7 @@ # set -eu -o pipefail -PROTOBUF_VERSION=3.5.1 +PROTOBUF_VERSION=3.11.4 GOARCH=$(go env GOARCH) GOOS=$(go env GOOS) PROTOBUF_DIR=$(mktemp -d) @@ -33,14 +33,18 @@ ;; amd64|386) - if [ $GOOS == "windows" ]; then + if [ "$GOOS" = windows ]; then wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-win32.zip" - elif [ $GOOS == "linux" ]; then + elif [ "$GOOS" = linux ]; then wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-x86_64.zip" fi unzip $PROTOBUF_DIR/protobuf -d /usr/local ;; +ppc64le) + wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protoc-$PROTOBUF_VERSION-linux-ppcle_64.zip" + unzip $PROTOBUF_DIR/protobuf -d /usr/local + ;; *) wget -O $PROTOBUF_DIR/protobuf "https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-cpp-$PROTOBUF_VERSION.zip" unzip $PROTOBUF_DIR/protobuf -d /usr/src/protobuf diff -Nru containerd-1.2.6/script/setup/install-runc containerd-1.5.9/script/setup/install-runc --- containerd-1.2.6/script/setup/install-runc 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/script/setup/install-runc 2022-01-05 17:30:58.000000000 +0000 @@ -14,16 +14,40 @@ # See the License for the specific language governing permissions and # limitations under the License. - # # Builds and installs runc to /usr/local/go/bin based off -# the commit defined in vendor.conf +# the commit defined in go.mod # set -eu -o pipefail -RUNC_COMMIT=$(grep opencontainers/runc ${GOPATH}/src/github.com/containerd/containerd/vendor.conf | cut -d " " -f 2) +function install_runc() { + script_dir="$(cd -- "$(dirname -- "$0")" > /dev/null 2>&1; pwd -P)" + + # When updating runc-version, consider updating the runc module in go.mod as well + : "${RUNC_VERSION:=$(cat "${script_dir}/runc-version")}" + + TMPROOT=$(mktemp -d) + git clone https://github.com/opencontainers/runc.git "${TMPROOT}"/runc + pushd "${TMPROOT}"/runc + git checkout "${RUNC_VERSION}" + make BUILDTAGS='seccomp' runc + make install + popd + rm -fR "${TMPROOT}" +} + +function install_crun() { + CRUN_VERSION=0.19 + curl -o /usr/local/sbin/runc -L https://github.com/containers/crun/releases/download/"${CRUN_VERSION}"/crun-"${CRUN_VERSION}"-linux-"$(go env GOARCH)" + chmod +x /usr/local/sbin/runc +} -go get -d github.com/opencontainers/runc -cd $GOPATH/src/github.com/opencontainers/runc -git checkout $RUNC_COMMIT -make BUILDTAGS="apparmor seccomp" runc install +: "${RUNC_FLAVOR:=runc}" +case ${RUNC_FLAVOR} in +runc) install_runc ;; +crun) install_crun ;; +*) + echo >&2 "unknown runc flavor: ${RUNC_FLAVOR}" + exit 1 + ;; +esac diff -Nru containerd-1.2.6/script/setup/install-seccomp containerd-1.5.9/script/setup/install-seccomp --- containerd-1.2.6/script/setup/install-seccomp 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/install-seccomp 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# +# Builds a specific version of libseccomp and installs in /usr/local +# +set -eu -o pipefail + +set -x + +export SECCOMP_VERSION=2.5.1 +export SECCOMP_PATH=$(mktemp -d) +curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" | tar -xzC "$SECCOMP_PATH" --strip-components=1 +( + cd "$SECCOMP_PATH" + ./configure --prefix=/usr/local + make + make install + ldconfig +) + +rm -rf "$SECCOMP_PATH" diff -Nru containerd-1.2.6/script/setup/runc-version containerd-1.5.9/script/setup/runc-version --- containerd-1.2.6/script/setup/runc-version 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/setup/runc-version 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +v1.0.3 diff -Nru containerd-1.2.6/script/test/cri-integration.sh containerd-1.5.9/script/test/cri-integration.sh --- containerd-1.2.6/script/test/cri-integration.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/test/cri-integration.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o nounset +set -o pipefail + +source $(dirname "${BASH_SOURCE[0]}")/utils.sh +cd ${ROOT} + +# FOCUS focuses the test to run. +FOCUS=${FOCUS:-""} +# REPORT_DIR is the the directory to store test logs. +REPORT_DIR=${REPORT_DIR:-"/tmp/test-integration"} +# RUNTIME is the runtime handler to use in the test. +RUNTIME=${RUNTIME:-""} + +CRI_ROOT="${CONTAINERD_ROOT}/io.containerd.grpc.v1.cri" + +mkdir -p ${REPORT_DIR} +test_setup ${REPORT_DIR} + +# Run integration test. +sudo PATH=${PATH} bin/cri-integration.test --test.run="${FOCUS}" --test.v \ + --cri-endpoint=${CONTAINERD_SOCK} \ + --cri-root=${CRI_ROOT} \ + --runtime-handler=${RUNTIME} \ + --containerd-bin=${CONTAINERD_BIN} \ + --image-list="${TEST_IMAGE_LIST:-}" + +test_exit_code=$? + +test_teardown + +exit ${test_exit_code} diff -Nru containerd-1.2.6/script/test/utils.sh containerd-1.5.9/script/test/utils.sh --- containerd-1.2.6/script/test/utils.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/script/test/utils.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,123 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/../.. + +# RESTART_WAIT_PERIOD is the period to wait before restarting containerd. +RESTART_WAIT_PERIOD=${RESTART_WAIT_PERIOD:-10} +# CONTAINERD_FLAGS contains all containerd flags. +CONTAINERD_FLAGS="--log-level=debug " + +# Use a configuration file for containerd. +CONTAINERD_CONFIG_FILE=${CONTAINERD_CONFIG_FILE:-""} +# The runtime to use (ignored when CONTAINERD_CONFIG_FILE is set) +CONTAINERD_RUNTIME=${CONTAINERD_RUNTIME:-""} +if [ -z "${CONTAINERD_CONFIG_FILE}" ]; then + config_file="/tmp/containerd-config-cri.toml" + truncate --size 0 "${config_file}" + if command -v sestatus >/dev/null 2>&1; then + cat >>${config_file} <>${config_file} < ${report_dir}/containerd.log & + pid=$! + set +m + containerd_groupid=$(ps -o pgid= -p ${pid}) + # Wait for containerd to be running by using the containerd client ctr to check the version + # of the containerd server. Wait an increasing amount of time after each of five attempts + local -r crictl_path=$(which crictl) + if [ -z "${crictl_path}" ]; then + echo "crictl is not in PATH" + exit 1 + fi + readiness_check "sudo bin/ctr --address ${CONTAINERD_SOCK#"unix://"} version" + readiness_check "sudo ${crictl_path} --runtime-endpoint=${CONTAINERD_SOCK} info" +} + +# test_teardown kills containerd. +test_teardown() { + if [ -n "${containerd_groupid}" ]; then + sudo pkill -g ${containerd_groupid} + fi +} + +# keepalive runs a command and keeps it alive. +# keepalive process is eventually killed in test_teardown. +keepalive() { + local command=$1 + echo ${command} + local wait_period=$2 + while true; do + ${command} + sleep ${wait_period} + done +} + +# readiness_check checks readiness of a daemon with specified command. +readiness_check() { + local command=$1 + local MAX_ATTEMPTS=5 + local attempt_num=1 + until ${command} &> /dev/null || (( attempt_num == MAX_ATTEMPTS )) + do + echo "$attempt_num attempt \"$command\"! Trying again in $attempt_num seconds..." + sleep $(( attempt_num++ )) + done +} diff -Nru containerd-1.2.6/services/containers/local.go containerd-1.5.9/services/containers/local.go --- containerd-1.2.6/services/containers/local.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/containers/local.go 2022-01-05 17:30:58.000000000 +0000 @@ -48,8 +48,11 @@ if err != nil { return nil, err } + + db := m.(*metadata.DB) return &local{ - db: m.(*metadata.DB), + Store: metadata.NewContainerStore(db), + db: db, publisher: ic.Events, }, nil }, @@ -57,6 +60,7 @@ } type local struct { + containers.Store db *metadata.DB publisher events.Publisher } @@ -66,8 +70,8 @@ func (l *local) Get(ctx context.Context, req *api.GetContainerRequest, _ ...grpc.CallOption) (*api.GetContainerResponse, error) { var resp api.GetContainerResponse - return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error { - container, err := store.Get(ctx, req.ID) + return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error { + container, err := l.Store.Get(ctx, req.ID) if err != nil { return err } @@ -80,8 +84,8 @@ func (l *local) List(ctx context.Context, req *api.ListContainersRequest, _ ...grpc.CallOption) (*api.ListContainersResponse, error) { var resp api.ListContainersResponse - return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error { - containers, err := store.List(ctx, req.Filters...) + return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error { + containers, err := l.Store.List(ctx, req.Filters...) if err != nil { return err } @@ -94,8 +98,8 @@ stream := &localStream{ ctx: ctx, } - return stream, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error { - containers, err := store.List(ctx, req.Filters...) + return stream, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error { + containers, err := l.Store.List(ctx, req.Filters...) if err != nil { return err } @@ -107,10 +111,10 @@ func (l *local) Create(ctx context.Context, req *api.CreateContainerRequest, _ ...grpc.CallOption) (*api.CreateContainerResponse, error) { var resp api.CreateContainerResponse - if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error { + if err := l.withStoreUpdate(ctx, func(ctx context.Context) error { container := containerFromProto(&req.Container) - created, err := store.Create(ctx, container) + created, err := l.Store.Create(ctx, container) if err != nil { return err } @@ -144,13 +148,13 @@ container = containerFromProto(&req.Container) ) - if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error { + if err := l.withStoreUpdate(ctx, func(ctx context.Context) error { var fieldpaths []string if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 { fieldpaths = append(fieldpaths, req.UpdateMask.Paths...) } - updated, err := store.Update(ctx, container, fieldpaths...) + updated, err := l.Store.Update(ctx, container, fieldpaths...) if err != nil { return err } @@ -174,8 +178,8 @@ } func (l *local) Delete(ctx context.Context, req *api.DeleteContainerRequest, _ ...grpc.CallOption) (*ptypes.Empty, error) { - if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error { - return store.Delete(ctx, req.ID) + if err := l.withStoreUpdate(ctx, func(ctx context.Context) error { + return l.Store.Delete(ctx, req.ID) }); err != nil { return &ptypes.Empty{}, errdefs.ToGRPC(err) } @@ -189,15 +193,17 @@ return &ptypes.Empty{}, nil } -func (l *local) withStore(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) func(tx *bolt.Tx) error { - return func(tx *bolt.Tx) error { return fn(ctx, metadata.NewContainerStore(tx)) } +func (l *local) withStore(ctx context.Context, fn func(ctx context.Context) error) func(tx *bolt.Tx) error { + return func(tx *bolt.Tx) error { + return fn(metadata.WithTransactionContext(ctx, tx)) + } } -func (l *local) withStoreView(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) error { +func (l *local) withStoreView(ctx context.Context, fn func(ctx context.Context) error) error { return l.db.View(l.withStore(ctx, fn)) } -func (l *local) withStoreUpdate(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) error { +func (l *local) withStoreUpdate(ctx context.Context, fn func(ctx context.Context) error) error { return l.db.Update(l.withStore(ctx, fn)) } diff -Nru containerd-1.2.6/services/containers/service.go containerd-1.5.9/services/containers/service.go --- containerd-1.2.6/services/containers/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/containers/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -94,7 +94,6 @@ } } } - return nil } func (s *service) Create(ctx context.Context, req *api.CreateContainerRequest) (*api.CreateContainerResponse, error) { diff -Nru containerd-1.2.6/services/content/contentserver/contentserver.go containerd-1.5.9/services/content/contentserver/contentserver.go --- containerd-1.2.6/services/content/contentserver/contentserver.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/content/contentserver/contentserver.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,463 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package contentserver + +import ( + "context" + "io" + "sync" + + api "github.com/containerd/containerd/api/services/content/v1" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + ptypes "github.com/gogo/protobuf/types" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type service struct { + store content.Store +} + +var bufPool = sync.Pool{ + New: func() interface{} { + buffer := make([]byte, 1<<20) + return &buffer + }, +} + +// New returns the content GRPC server +func New(cs content.Store) api.ContentServer { + return &service{store: cs} +} + +func (s *service) Register(server *grpc.Server) error { + api.RegisterContentServer(server, s) + return nil +} + +func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) { + if err := req.Digest.Validate(); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest) + } + + bi, err := s.store.Info(ctx, req.Digest) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &api.InfoResponse{ + Info: infoToGRPC(bi), + }, nil +} + +func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) { + if err := req.Info.Digest.Validate(); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest) + } + + info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &api.UpdateResponse{ + Info: infoToGRPC(info), + }, nil +} + +func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error { + var ( + buffer []api.Info + sendBlock = func(block []api.Info) error { + // send last block + return session.Send(&api.ListContentResponse{ + Info: block, + }) + } + ) + + if err := s.store.Walk(session.Context(), func(info content.Info) error { + buffer = append(buffer, api.Info{ + Digest: info.Digest, + Size_: info.Size, + CreatedAt: info.CreatedAt, + Labels: info.Labels, + }) + + if len(buffer) >= 100 { + if err := sendBlock(buffer); err != nil { + return err + } + + buffer = buffer[:0] + } + + return nil + }, req.Filters...); err != nil { + return errdefs.ToGRPC(err) + } + + if len(buffer) > 0 { + // send last block + if err := sendBlock(buffer); err != nil { + return err + } + } + + return nil +} + +func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) { + log.G(ctx).WithField("digest", req.Digest).Debugf("delete content") + if err := req.Digest.Validate(); err != nil { + return nil, status.Errorf(codes.InvalidArgument, err.Error()) + } + + if err := s.store.Delete(ctx, req.Digest); err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &ptypes.Empty{}, nil +} + +func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error { + if err := req.Digest.Validate(); err != nil { + return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err) + } + + oi, err := s.store.Info(session.Context(), req.Digest) + if err != nil { + return errdefs.ToGRPC(err) + } + + ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: req.Digest}) + if err != nil { + return errdefs.ToGRPC(err) + } + defer ra.Close() + + var ( + offset = req.Offset + // size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of. + // offset+size can be larger than oi.Size. + size = req.Size_ + + // TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably + // little inefficient for work over a fast network. We can tune this later. + p = bufPool.Get().(*[]byte) + ) + defer bufPool.Put(p) + + if offset < 0 { + offset = 0 + } + + if offset > oi.Size { + return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size) + } + + if size <= 0 || offset+size > oi.Size { + size = oi.Size - offset + } + + _, err = io.CopyBuffer( + &readResponseWriter{session: session}, + io.NewSectionReader(ra, offset, size), *p) + return errdefs.ToGRPC(err) +} + +// readResponseWriter is a writer that places the output into ReadContentRequest messages. +// +// This allows io.CopyBuffer to do the heavy lifting of chunking the responses +// into the buffer size. +type readResponseWriter struct { + offset int64 + session api.Content_ReadServer +} + +func (rw *readResponseWriter) Write(p []byte) (n int, err error) { + if err := rw.session.Send(&api.ReadContentResponse{ + Offset: rw.offset, + Data: p, + }); err != nil { + return 0, err + } + + rw.offset += int64(len(p)) + return len(p), nil +} + +func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) { + status, err := s.store.Status(ctx, req.Ref) + if err != nil { + return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref) + } + + var resp api.StatusResponse + resp.Status = &api.Status{ + StartedAt: status.StartedAt, + UpdatedAt: status.UpdatedAt, + Ref: status.Ref, + Offset: status.Offset, + Total: status.Total, + Expected: status.Expected, + } + + return &resp, nil +} + +func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) { + statuses, err := s.store.ListStatuses(ctx, req.Filters...) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + var resp api.ListStatusesResponse + for _, status := range statuses { + resp.Statuses = append(resp.Statuses, api.Status{ + StartedAt: status.StartedAt, + UpdatedAt: status.UpdatedAt, + Ref: status.Ref, + Offset: status.Offset, + Total: status.Total, + Expected: status.Expected, + }) + } + + return &resp, nil +} + +func (s *service) Write(session api.Content_WriteServer) (err error) { + var ( + ctx = session.Context() + msg api.WriteContentResponse + req *api.WriteContentRequest + ref string + total int64 + expected digest.Digest + ) + + defer func(msg *api.WriteContentResponse) { + // pump through the last message if no error was encountered + if err != nil { + if s, ok := status.FromError(err); ok && s.Code() != codes.AlreadyExists { + // TODO(stevvooe): Really need a log line here to track which + // errors are actually causing failure on the server side. May want + // to configure the service with an interceptor to make this work + // identically across all GRPC methods. + // + // This is pretty noisy, so we can remove it but leave it for now. + log.G(ctx).WithError(err).Error("(*service).Write failed") + } + + return + } + + err = session.Send(msg) + }(&msg) + + // handle the very first request! + req, err = session.Recv() + if err != nil { + return err + } + + ref = req.Ref + + if ref == "" { + return status.Errorf(codes.InvalidArgument, "first message must have a reference") + } + + fields := logrus.Fields{ + "ref": ref, + } + total = req.Total + expected = req.Expected + if total > 0 { + fields["total"] = total + } + + if expected != "" { + fields["expected"] = expected + } + + ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields)) + + log.G(ctx).Debug("(*service).Write started") + // this action locks the writer for the session. + wr, err := s.store.Writer(ctx, + content.WithRef(ref), + content.WithDescriptor(ocispec.Descriptor{Size: total, Digest: expected})) + if err != nil { + return errdefs.ToGRPC(err) + } + defer wr.Close() + + for { + msg.Action = req.Action + ws, err := wr.Status() + if err != nil { + return errdefs.ToGRPC(err) + } + + msg.Offset = ws.Offset // always set the offset. + + // NOTE(stevvooe): In general, there are two cases underwhich a remote + // writer is used. + // + // For pull, we almost always have this before fetching large content, + // through descriptors. We allow predeclaration of the expected size + // and digest. + // + // For push, it is more complex. If we want to cut through content into + // storage, we may have no expectation until we are done processing the + // content. The case here is the following: + // + // 1. Start writing content. + // 2. Compress inline. + // 3. Validate digest and size (maybe). + // + // Supporting these two paths is quite awkward but it lets both API + // users use the same writer style for each with a minimum of overhead. + if req.Expected != "" { + if expected != "" && expected != req.Expected { + log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", req.Expected, expected) + } + expected = req.Expected + + if _, err := s.store.Info(session.Context(), req.Expected); err == nil { + if err := wr.Close(); err != nil { + log.G(ctx).WithError(err).Error("failed to close writer") + } + if err := s.store.Abort(session.Context(), ref); err != nil { + log.G(ctx).WithError(err).Error("failed to abort write") + } + + return status.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected) + } + } + + if req.Total > 0 { + // Update the expected total. Typically, this could be seen at + // negotiation time or on a commit message. + if total > 0 && req.Total != total { + log.G(ctx).Debugf("commit size differs from writer size: %v != %v", req.Total, total) + } + total = req.Total + } + + switch req.Action { + case api.WriteActionStat: + msg.Digest = wr.Digest() + msg.StartedAt = ws.StartedAt + msg.UpdatedAt = ws.UpdatedAt + msg.Total = total + case api.WriteActionWrite, api.WriteActionCommit: + if req.Offset > 0 { + // validate the offset if provided + if req.Offset != ws.Offset { + return status.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset) + } + } + + if req.Offset == 0 && ws.Offset > 0 { + if err := wr.Truncate(req.Offset); err != nil { + return errors.Wrapf(err, "truncate failed") + } + msg.Offset = req.Offset + } + + // issue the write if we actually have data. + if len(req.Data) > 0 { + // While this looks like we could use io.WriterAt here, because we + // maintain the offset as append only, we just issue the write. + n, err := wr.Write(req.Data) + if err != nil { + return errdefs.ToGRPC(err) + } + + if n != len(req.Data) { + // TODO(stevvooe): Perhaps, we can recover this by including it + // in the offset on the write return. + return status.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data)) + } + + msg.Offset += int64(n) + } + + if req.Action == api.WriteActionCommit { + var opts []content.Opt + if req.Labels != nil { + opts = append(opts, content.WithLabels(req.Labels)) + } + if err := wr.Commit(ctx, total, expected, opts...); err != nil { + return errdefs.ToGRPC(err) + } + } + + msg.Digest = wr.Digest() + } + + if err := session.Send(&msg); err != nil { + return err + } + + req, err = session.Recv() + if err != nil { + if err == io.EOF { + return nil + } + + return err + } + } +} + +func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*ptypes.Empty, error) { + if err := s.store.Abort(ctx, req.Ref); err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &ptypes.Empty{}, nil +} + +func infoToGRPC(info content.Info) api.Info { + return api.Info{ + Digest: info.Digest, + Size_: info.Size, + CreatedAt: info.CreatedAt, + UpdatedAt: info.UpdatedAt, + Labels: info.Labels, + } +} + +func infoFromGRPC(info api.Info) content.Info { + return content.Info{ + Digest: info.Digest, + Size: info.Size_, + CreatedAt: info.CreatedAt, + UpdatedAt: info.UpdatedAt, + Labels: info.Labels, + } +} diff -Nru containerd-1.2.6/services/content/service.go containerd-1.5.9/services/content/service.go --- containerd-1.2.6/services/content/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/content/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,39 +17,13 @@ package content import ( - "context" - "io" - "sync" - - api "github.com/containerd/containerd/api/services/content/v1" "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/log" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" - ptypes "github.com/gogo/protobuf/types" - digest "github.com/opencontainers/go-digest" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containerd/containerd/services/content/contentserver" "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) -type service struct { - store content.Store -} - -var bufPool = sync.Pool{ - New: func() interface{} { - buffer := make([]byte, 1<<20) - return &buffer - }, -} - -var _ api.ContentServer = &service{} - func init() { plugin.Register(&plugin.Registration{ Type: plugin.GRPCPlugin, @@ -70,423 +44,7 @@ if err != nil { return nil, err } - return NewService(cs.(content.Store)), nil + return contentserver.New(cs.(content.Store)), nil }, }) } - -// NewService returns the content GRPC server -func NewService(cs content.Store) api.ContentServer { - return &service{store: cs} -} - -func (s *service) Register(server *grpc.Server) error { - api.RegisterContentServer(server, s) - return nil -} - -func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) { - if err := req.Digest.Validate(); err != nil { - return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest) - } - - bi, err := s.store.Info(ctx, req.Digest) - if err != nil { - return nil, errdefs.ToGRPC(err) - } - - return &api.InfoResponse{ - Info: infoToGRPC(bi), - }, nil -} - -func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) { - if err := req.Info.Digest.Validate(); err != nil { - return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest) - } - - info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...) - if err != nil { - return nil, errdefs.ToGRPC(err) - } - - return &api.UpdateResponse{ - Info: infoToGRPC(info), - }, nil -} - -func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error { - var ( - buffer []api.Info - sendBlock = func(block []api.Info) error { - // send last block - return session.Send(&api.ListContentResponse{ - Info: block, - }) - } - ) - - if err := s.store.Walk(session.Context(), func(info content.Info) error { - buffer = append(buffer, api.Info{ - Digest: info.Digest, - Size_: info.Size, - CreatedAt: info.CreatedAt, - Labels: info.Labels, - }) - - if len(buffer) >= 100 { - if err := sendBlock(buffer); err != nil { - return err - } - - buffer = buffer[:0] - } - - return nil - }, req.Filters...); err != nil { - return err - } - - if len(buffer) > 0 { - // send last block - if err := sendBlock(buffer); err != nil { - return err - } - } - - return nil -} - -func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) { - log.G(ctx).WithField("digest", req.Digest).Debugf("delete content") - if err := req.Digest.Validate(); err != nil { - return nil, status.Errorf(codes.InvalidArgument, err.Error()) - } - - if err := s.store.Delete(ctx, req.Digest); err != nil { - return nil, errdefs.ToGRPC(err) - } - - return &ptypes.Empty{}, nil -} - -func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error { - if err := req.Digest.Validate(); err != nil { - return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err) - } - - oi, err := s.store.Info(session.Context(), req.Digest) - if err != nil { - return errdefs.ToGRPC(err) - } - - ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: req.Digest}) - if err != nil { - return errdefs.ToGRPC(err) - } - defer ra.Close() - - var ( - offset = req.Offset - // size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of. - // offset+size can be larger than oi.Size. - size = req.Size_ - - // TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably - // little inefficient for work over a fast network. We can tune this later. - p = bufPool.Get().(*[]byte) - ) - defer bufPool.Put(p) - - if offset < 0 { - offset = 0 - } - - if offset > oi.Size { - return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size) - } - - if size <= 0 || offset+size > oi.Size { - size = oi.Size - offset - } - - _, err = io.CopyBuffer( - &readResponseWriter{session: session}, - io.NewSectionReader(ra, offset, size), *p) - return errdefs.ToGRPC(err) -} - -// readResponseWriter is a writer that places the output into ReadContentRequest messages. -// -// This allows io.CopyBuffer to do the heavy lifting of chunking the responses -// into the buffer size. -type readResponseWriter struct { - offset int64 - session api.Content_ReadServer -} - -func (rw *readResponseWriter) Write(p []byte) (n int, err error) { - if err := rw.session.Send(&api.ReadContentResponse{ - Offset: rw.offset, - Data: p, - }); err != nil { - return 0, err - } - - rw.offset += int64(len(p)) - return len(p), nil -} - -func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) { - status, err := s.store.Status(ctx, req.Ref) - if err != nil { - return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref) - } - - var resp api.StatusResponse - resp.Status = &api.Status{ - StartedAt: status.StartedAt, - UpdatedAt: status.UpdatedAt, - Ref: status.Ref, - Offset: status.Offset, - Total: status.Total, - Expected: status.Expected, - } - - return &resp, nil -} - -func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) { - statuses, err := s.store.ListStatuses(ctx, req.Filters...) - if err != nil { - return nil, errdefs.ToGRPC(err) - } - - var resp api.ListStatusesResponse - for _, status := range statuses { - resp.Statuses = append(resp.Statuses, api.Status{ - StartedAt: status.StartedAt, - UpdatedAt: status.UpdatedAt, - Ref: status.Ref, - Offset: status.Offset, - Total: status.Total, - Expected: status.Expected, - }) - } - - return &resp, nil -} - -func (s *service) Write(session api.Content_WriteServer) (err error) { - var ( - ctx = session.Context() - msg api.WriteContentResponse - req *api.WriteContentRequest - ref string - total int64 - expected digest.Digest - ) - - defer func(msg *api.WriteContentResponse) { - // pump through the last message if no error was encountered - if err != nil { - if s, ok := status.FromError(err); ok && s.Code() != codes.AlreadyExists { - // TODO(stevvooe): Really need a log line here to track which - // errors are actually causing failure on the server side. May want - // to configure the service with an interceptor to make this work - // identically across all GRPC methods. - // - // This is pretty noisy, so we can remove it but leave it for now. - log.G(ctx).WithError(err).Error("(*service).Write failed") - } - - return - } - - err = session.Send(msg) - }(&msg) - - // handle the very first request! - req, err = session.Recv() - if err != nil { - return err - } - - ref = req.Ref - - if ref == "" { - return status.Errorf(codes.InvalidArgument, "first message must have a reference") - } - - fields := logrus.Fields{ - "ref": ref, - } - total = req.Total - expected = req.Expected - if total > 0 { - fields["total"] = total - } - - if expected != "" { - fields["expected"] = expected - } - - ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields)) - - log.G(ctx).Debug("(*service).Write started") - // this action locks the writer for the session. - wr, err := s.store.Writer(ctx, - content.WithRef(ref), - content.WithDescriptor(ocispec.Descriptor{Size: total, Digest: expected})) - if err != nil { - return errdefs.ToGRPC(err) - } - defer wr.Close() - - for { - msg.Action = req.Action - ws, err := wr.Status() - if err != nil { - return errdefs.ToGRPC(err) - } - - msg.Offset = ws.Offset // always set the offset. - - // NOTE(stevvooe): In general, there are two cases underwhich a remote - // writer is used. - // - // For pull, we almost always have this before fetching large content, - // through descriptors. We allow predeclaration of the expected size - // and digest. - // - // For push, it is more complex. If we want to cut through content into - // storage, we may have no expectation until we are done processing the - // content. The case here is the following: - // - // 1. Start writing content. - // 2. Compress inline. - // 3. Validate digest and size (maybe). - // - // Supporting these two paths is quite awkward but it lets both API - // users use the same writer style for each with a minimum of overhead. - if req.Expected != "" { - if expected != "" && expected != req.Expected { - log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", req.Expected, expected) - } - expected = req.Expected - - if _, err := s.store.Info(session.Context(), req.Expected); err == nil { - if err := wr.Close(); err != nil { - log.G(ctx).WithError(err).Error("failed to close writer") - } - if err := s.store.Abort(session.Context(), ref); err != nil { - log.G(ctx).WithError(err).Error("failed to abort write") - } - - return status.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected) - } - } - - if req.Total > 0 { - // Update the expected total. Typically, this could be seen at - // negotiation time or on a commit message. - if total > 0 && req.Total != total { - log.G(ctx).Debugf("commit size differs from writer size: %v != %v", req.Total, total) - } - total = req.Total - } - - switch req.Action { - case api.WriteActionStat: - msg.Digest = wr.Digest() - msg.StartedAt = ws.StartedAt - msg.UpdatedAt = ws.UpdatedAt - msg.Total = total - case api.WriteActionWrite, api.WriteActionCommit: - if req.Offset > 0 { - // validate the offset if provided - if req.Offset != ws.Offset { - return status.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset) - } - } - - if req.Offset == 0 && ws.Offset > 0 { - if err := wr.Truncate(req.Offset); err != nil { - return errors.Wrapf(err, "truncate failed") - } - msg.Offset = req.Offset - } - - // issue the write if we actually have data. - if len(req.Data) > 0 { - // While this looks like we could use io.WriterAt here, because we - // maintain the offset as append only, we just issue the write. - n, err := wr.Write(req.Data) - if err != nil { - return errdefs.ToGRPC(err) - } - - if n != len(req.Data) { - // TODO(stevvooe): Perhaps, we can recover this by including it - // in the offset on the write return. - return status.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data)) - } - - msg.Offset += int64(n) - } - - if req.Action == api.WriteActionCommit { - var opts []content.Opt - if req.Labels != nil { - opts = append(opts, content.WithLabels(req.Labels)) - } - if err := wr.Commit(ctx, total, expected, opts...); err != nil { - return errdefs.ToGRPC(err) - } - } - - msg.Digest = wr.Digest() - } - - if err := session.Send(&msg); err != nil { - return err - } - - req, err = session.Recv() - if err != nil { - if err == io.EOF { - return nil - } - - return err - } - } -} - -func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*ptypes.Empty, error) { - if err := s.store.Abort(ctx, req.Ref); err != nil { - return nil, errdefs.ToGRPC(err) - } - - return &ptypes.Empty{}, nil -} - -func infoToGRPC(info content.Info) api.Info { - return api.Info{ - Digest: info.Digest, - Size_: info.Size, - CreatedAt: info.CreatedAt, - UpdatedAt: info.UpdatedAt, - Labels: info.Labels, - } -} - -func infoFromGRPC(info api.Info) content.Info { - return content.Info{ - Digest: info.Digest, - Size: info.Size_, - CreatedAt: info.CreatedAt, - UpdatedAt: info.UpdatedAt, - Labels: info.Labels, - } -} diff -Nru containerd-1.2.6/services/diff/local.go containerd-1.5.9/services/diff/local.go --- containerd-1.2.6/services/diff/local.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/diff/local.go 2022-01-05 17:30:58.000000000 +0000 @@ -99,8 +99,13 @@ mounts = toMounts(er.Mounts) ) + var opts []diff.ApplyOpt + if er.Payloads != nil { + opts = append(opts, diff.WithPayloads(er.Payloads)) + } + for _, differ := range l.differs { - ocidesc, err = differ.Apply(ctx, desc, mounts) + ocidesc, err = differ.Apply(ctx, desc, mounts, opts...) if !errdefs.IsNotImplemented(err) { break } @@ -164,16 +169,18 @@ func toDescriptor(d *types.Descriptor) ocispec.Descriptor { return ocispec.Descriptor{ - MediaType: d.MediaType, - Digest: d.Digest, - Size: d.Size_, + MediaType: d.MediaType, + Digest: d.Digest, + Size: d.Size_, + Annotations: d.Annotations, } } func fromDescriptor(d ocispec.Descriptor) *types.Descriptor { return &types.Descriptor{ - MediaType: d.MediaType, - Digest: d.Digest, - Size_: d.Size, + MediaType: d.MediaType, + Digest: d.Digest, + Size_: d.Size, + Annotations: d.Annotations, } } diff -Nru containerd-1.2.6/services/events/service.go containerd-1.5.9/services/events/service.go --- containerd-1.2.6/services/events/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/events/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,10 +20,12 @@ "context" api "github.com/containerd/containerd/api/services/events/v1" + apittrpc "github.com/containerd/containerd/api/services/ttrpc/events/v1" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/events" "github.com/containerd/containerd/events/exchange" "github.com/containerd/containerd/plugin" + "github.com/containerd/ttrpc" ptypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" "google.golang.org/grpc" @@ -40,12 +42,18 @@ } type service struct { - events *exchange.Exchange + ttService *ttrpcService + events *exchange.Exchange } // NewService returns the GRPC events server func NewService(events *exchange.Exchange) api.EventsServer { - return &service{events: events} + return &service{ + ttService: &ttrpcService{ + events: events, + }, + events: events, + } } func (s *service) Register(server *grpc.Server) error { @@ -53,6 +61,11 @@ return nil } +func (s *service) RegisterTTRPC(server *ttrpc.Server) error { + apittrpc.RegisterEventsService(server, s.ttService) + return nil +} + func (s *service) Publish(ctx context.Context, r *api.PublishRequest) (*ptypes.Empty, error) { if err := s.events.Publish(ctx, r.Topic, r.Event); err != nil { return nil, errdefs.ToGRPC(err) diff -Nru containerd-1.2.6/services/events/ttrpc.go containerd-1.5.9/services/events/ttrpc.go --- containerd-1.2.6/services/events/ttrpc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/events/ttrpc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package events + +import ( + "context" + + api "github.com/containerd/containerd/api/services/ttrpc/events/v1" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/events" + "github.com/containerd/containerd/events/exchange" + ptypes "github.com/gogo/protobuf/types" +) + +type ttrpcService struct { + events *exchange.Exchange +} + +func (s *ttrpcService) Forward(ctx context.Context, r *api.ForwardRequest) (*ptypes.Empty, error) { + if err := s.events.Forward(ctx, fromTProto(r.Envelope)); err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &ptypes.Empty{}, nil +} + +func fromTProto(env *api.Envelope) *events.Envelope { + return &events.Envelope{ + Timestamp: env.Timestamp, + Namespace: env.Namespace, + Topic: env.Topic, + Event: env.Event, + } +} diff -Nru containerd-1.2.6/services/images/helpers.go containerd-1.5.9/services/images/helpers.go --- containerd-1.2.6/services/images/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/images/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -55,16 +55,18 @@ func descFromProto(desc *types.Descriptor) ocispec.Descriptor { return ocispec.Descriptor{ - MediaType: desc.MediaType, - Size: desc.Size_, - Digest: desc.Digest, + MediaType: desc.MediaType, + Size: desc.Size_, + Digest: desc.Digest, + Annotations: desc.Annotations, } } func descToProto(desc *ocispec.Descriptor) types.Descriptor { return types.Descriptor{ - MediaType: desc.MediaType, - Size_: desc.Size, - Digest: desc.Digest, + MediaType: desc.MediaType, + Size_: desc.Size, + Digest: desc.Digest, + Annotations: desc.Annotations, } } diff -Nru containerd-1.2.6/services/introspection/introspection.go containerd-1.5.9/services/introspection/introspection.go --- containerd-1.2.6/services/introspection/introspection.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/introspection/introspection.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package introspection + +import ( + context "context" + + api "github.com/containerd/containerd/api/services/introspection/v1" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + ptypes "github.com/gogo/protobuf/types" +) + +// Service defines the instrospection service interface +type Service interface { + Plugins(context.Context, []string) (*api.PluginsResponse, error) + Server(context.Context, *ptypes.Empty) (*api.ServerResponse, error) +} + +type introspectionRemote struct { + client api.IntrospectionClient +} + +var _ = (Service)(&introspectionRemote{}) + +// NewIntrospectionServiceFromClient creates a new introspection service from an API client +func NewIntrospectionServiceFromClient(c api.IntrospectionClient) Service { + return &introspectionRemote{client: c} +} + +func (i *introspectionRemote) Plugins(ctx context.Context, filters []string) (*api.PluginsResponse, error) { + log.G(ctx).WithField("filters", filters).Debug("remote introspection plugin filters") + resp, err := i.client.Plugins(ctx, &api.PluginsRequest{ + Filters: filters, + }) + + if err != nil { + return nil, errdefs.FromGRPC(err) + } + + return resp, nil +} + +func (i *introspectionRemote) Server(ctx context.Context, in *ptypes.Empty) (*api.ServerResponse, error) { + resp, err := i.client.Server(ctx, in) + + if err != nil { + return nil, errdefs.FromGRPC(err) + } + + return resp, nil +} diff -Nru containerd-1.2.6/services/introspection/local.go containerd-1.5.9/services/introspection/local.go --- containerd-1.2.6/services/introspection/local.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/introspection/local.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,231 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package introspection + +import ( + context "context" + "io/ioutil" + "os" + "path/filepath" + "sync" + + api "github.com/containerd/containerd/api/services/introspection/v1" + "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/filters" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/services" + "github.com/gogo/googleapis/google/rpc" + ptypes "github.com/gogo/protobuf/types" + "github.com/google/uuid" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.ServicePlugin, + ID: services.IntrospectionService, + Requires: []plugin.Type{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + // this service works by using the plugin context up till the point + // this service is initialized. Since we require this service last, + // it should provide the full set of plugins. + pluginsPB := pluginsToPB(ic.GetAll()) + return &Local{ + plugins: pluginsPB, + root: ic.Root, + }, nil + }, + }) +} + +// Local is a local implementation of the introspection service +type Local struct { + mu sync.Mutex + plugins []api.Plugin + root string +} + +var _ = (api.IntrospectionClient)(&Local{}) + +// UpdateLocal updates the local introspection service +func (l *Local) UpdateLocal(root string, plugins []api.Plugin) { + l.mu.Lock() + defer l.mu.Unlock() + l.root = root + l.plugins = plugins +} + +// Plugins returns the locally defined plugins +func (l *Local) Plugins(ctx context.Context, req *api.PluginsRequest, _ ...grpc.CallOption) (*api.PluginsResponse, error) { + filter, err := filters.ParseAll(req.Filters...) + if err != nil { + return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, err.Error()) + } + + var plugins []api.Plugin + allPlugins := l.getPlugins() + for _, p := range allPlugins { + if !filter.Match(adaptPlugin(p)) { + continue + } + + plugins = append(plugins, p) + } + + return &api.PluginsResponse{ + Plugins: plugins, + }, nil +} + +func (l *Local) getPlugins() []api.Plugin { + l.mu.Lock() + defer l.mu.Unlock() + return l.plugins +} + +// Server returns the local server information +func (l *Local) Server(ctx context.Context, _ *ptypes.Empty, _ ...grpc.CallOption) (*api.ServerResponse, error) { + u, err := l.getUUID() + if err != nil { + return nil, errdefs.ToGRPC(err) + } + return &api.ServerResponse{ + UUID: u, + }, nil +} + +func (l *Local) getUUID() (string, error) { + l.mu.Lock() + defer l.mu.Unlock() + + data, err := ioutil.ReadFile(l.uuidPath()) + if err != nil { + if os.IsNotExist(err) { + return l.generateUUID() + } + return "", err + } + u := string(data) + if _, err := uuid.Parse(u); err != nil { + return "", err + } + return u, nil +} + +func (l *Local) generateUUID() (string, error) { + u, err := uuid.NewRandom() + if err != nil { + return "", err + } + path := l.uuidPath() + if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { + return "", err + } + uu := u.String() + if err := ioutil.WriteFile(path, []byte(uu), 0666); err != nil { + return "", err + } + return uu, nil +} + +func (l *Local) uuidPath() string { + return filepath.Join(l.root, "uuid") +} + +func adaptPlugin(o interface{}) filters.Adaptor { + obj := o.(api.Plugin) + return filters.AdapterFunc(func(fieldpath []string) (string, bool) { + if len(fieldpath) == 0 { + return "", false + } + + switch fieldpath[0] { + case "type": + return obj.Type, len(obj.Type) > 0 + case "id": + return obj.ID, len(obj.ID) > 0 + case "platforms": + // TODO(stevvooe): Another case here where have multiple values. + // May need to refactor the filter system to allow filtering by + // platform, if this is required. + case "capabilities": + // TODO(stevvooe): Need a better way to match against + // collections. We can only return "the value" but really it + // would be best if we could return a set of values for the + // path, any of which could match. + } + + return "", false + }) +} + +func pluginsToPB(plugins []*plugin.Plugin) []api.Plugin { + var pluginsPB []api.Plugin + for _, p := range plugins { + var platforms []types.Platform + for _, p := range p.Meta.Platforms { + platforms = append(platforms, types.Platform{ + OS: p.OS, + Architecture: p.Architecture, + Variant: p.Variant, + }) + } + + var requires []string + for _, r := range p.Registration.Requires { + requires = append(requires, r.String()) + } + + var initErr *rpc.Status + if err := p.Err(); err != nil { + st, ok := status.FromError(errdefs.ToGRPC(err)) + if ok { + var details []*ptypes.Any + for _, d := range st.Proto().Details { + details = append(details, &ptypes.Any{ + TypeUrl: d.TypeUrl, + Value: d.Value, + }) + } + initErr = &rpc.Status{ + Code: int32(st.Code()), + Message: st.Message(), + Details: details, + } + } else { + initErr = &rpc.Status{ + Code: int32(rpc.UNKNOWN), + Message: err.Error(), + } + } + } + + pluginsPB = append(pluginsPB, api.Plugin{ + Type: p.Registration.Type.String(), + ID: p.Registration.ID, + Requires: requires, + Platforms: platforms, + Capabilities: p.Meta.Capabilities, + Exports: p.Meta.Exports, + InitErr: initErr, + }) + } + + return pluginsPB +} diff -Nru containerd-1.2.6/services/introspection/service.go containerd-1.5.9/services/introspection/service.go --- containerd-1.2.6/services/introspection/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/introspection/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,14 +20,11 @@ context "context" api "github.com/containerd/containerd/api/services/introspection/v1" - "github.com/containerd/containerd/api/types" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/filters" "github.com/containerd/containerd/plugin" - "github.com/gogo/googleapis/google/rpc" + "github.com/containerd/containerd/services" ptypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" "google.golang.org/grpc" - "google.golang.org/grpc/status" ) func init() { @@ -39,126 +36,50 @@ // this service works by using the plugin context up till the point // this service is initialized. Since we require this service last, // it should provide the full set of plugins. - pluginsPB := pluginsToPB(ic.GetAll()) - return NewService(pluginsPB), nil + plugins, err := ic.GetByType(plugin.ServicePlugin) + if err != nil { + return nil, err + } + p, ok := plugins[services.IntrospectionService] + if !ok { + return nil, errors.New("introspection service not found") + } + + i, err := p.Instance() + if err != nil { + return nil, err + } + + allPluginsPB := pluginsToPB(ic.GetAll()) + + localClient, ok := i.(*Local) + if !ok { + return nil, errors.Errorf("Could not create a local client for introspection service") + } + localClient.UpdateLocal(ic.Root, allPluginsPB) + + return &server{ + local: localClient, + }, nil }, }) } -type service struct { - plugins []api.Plugin +type server struct { + local api.IntrospectionClient } -// NewService returns the GRPC introspection server -func NewService(plugins []api.Plugin) api.IntrospectionServer { - return &service{ - plugins: plugins, - } -} +var _ = (api.IntrospectionServer)(&server{}) -func (s *service) Register(server *grpc.Server) error { +func (s *server) Register(server *grpc.Server) error { api.RegisterIntrospectionServer(server, s) return nil } -func (s *service) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) { - filter, err := filters.ParseAll(req.Filters...) - if err != nil { - return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, err.Error()) - } - - var plugins []api.Plugin - for _, p := range s.plugins { - if !filter.Match(adaptPlugin(p)) { - continue - } - - plugins = append(plugins, p) - } - - return &api.PluginsResponse{ - Plugins: plugins, - }, nil -} - -func adaptPlugin(o interface{}) filters.Adaptor { - obj := o.(api.Plugin) - return filters.AdapterFunc(func(fieldpath []string) (string, bool) { - if len(fieldpath) == 0 { - return "", false - } - - switch fieldpath[0] { - case "type": - return obj.Type, len(obj.Type) > 0 - case "id": - return obj.ID, len(obj.ID) > 0 - case "platforms": - // TODO(stevvooe): Another case here where have multiple values. - // May need to refactor the filter system to allow filtering by - // platform, if this is required. - case "capabilities": - // TODO(stevvooe): Need a better way to match against - // collections. We can only return "the value" but really it - // would be best if we could return a set of values for the - // path, any of which could match. - } - - return "", false - }) +func (s *server) Plugins(ctx context.Context, req *api.PluginsRequest) (*api.PluginsResponse, error) { + return s.local.Plugins(ctx, req) } -func pluginsToPB(plugins []*plugin.Plugin) []api.Plugin { - var pluginsPB []api.Plugin - for _, p := range plugins { - var platforms []types.Platform - for _, p := range p.Meta.Platforms { - platforms = append(platforms, types.Platform{ - OS: p.OS, - Architecture: p.Architecture, - Variant: p.Variant, - }) - } - - var requires []string - for _, r := range p.Registration.Requires { - requires = append(requires, r.String()) - } - - var initErr *rpc.Status - if err := p.Err(); err != nil { - st, ok := status.FromError(errdefs.ToGRPC(err)) - if ok { - var details []*ptypes.Any - for _, d := range st.Proto().Details { - details = append(details, &ptypes.Any{ - TypeUrl: d.TypeUrl, - Value: d.Value, - }) - } - initErr = &rpc.Status{ - Code: int32(st.Code()), - Message: st.Message(), - Details: details, - } - } else { - initErr = &rpc.Status{ - Code: int32(rpc.UNKNOWN), - Message: err.Error(), - } - } - } - - pluginsPB = append(pluginsPB, api.Plugin{ - Type: p.Registration.Type.String(), - ID: p.Registration.ID, - Requires: requires, - Platforms: platforms, - Capabilities: p.Meta.Capabilities, - Exports: p.Meta.Exports, - InitErr: initErr, - }) - } - - return pluginsPB +func (s *server) Server(ctx context.Context, empty *ptypes.Empty) (*api.ServerResponse, error) { + return s.local.Server(ctx, empty) } diff -Nru containerd-1.2.6/services/leases/local.go containerd-1.5.9/services/leases/local.go --- containerd-1.2.6/services/leases/local.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/leases/local.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,7 +24,6 @@ "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/services" - bolt "go.etcd.io/bbolt" ) func init() { @@ -44,8 +43,8 @@ return nil, err } return &local{ - db: m.(*metadata.DB), - gc: g.(gcScheduler), + Manager: metadata.NewLeaseManager(m.(*metadata.DB)), + gc: g.(gcScheduler), }, nil }, }) @@ -56,22 +55,10 @@ } type local struct { - db *metadata.DB + leases.Manager gc gcScheduler } -func (l *local) Create(ctx context.Context, opts ...leases.Opt) (leases.Lease, error) { - var lease leases.Lease - if err := l.db.Update(func(tx *bolt.Tx) error { - var err error - lease, err = metadata.NewLeaseManager(tx).Create(ctx, opts...) - return err - }); err != nil { - return leases.Lease{}, err - } - return lease, nil -} - func (l *local) Delete(ctx context.Context, lease leases.Lease, opts ...leases.DeleteOpt) error { var do leases.DeleteOptions for _, opt := range opts { @@ -80,9 +67,7 @@ } } - if err := l.db.Update(func(tx *bolt.Tx) error { - return metadata.NewLeaseManager(tx).Delete(ctx, lease) - }); err != nil { + if err := l.Manager.Delete(ctx, lease); err != nil { return err } @@ -95,15 +80,3 @@ return nil } - -func (l *local) List(ctx context.Context, filters ...string) ([]leases.Lease, error) { - var ll []leases.Lease - if err := l.db.View(func(tx *bolt.Tx) error { - var err error - ll, err = metadata.NewLeaseManager(tx).List(ctx, filters...) - return err - }); err != nil { - return nil, err - } - return ll, nil -} diff -Nru containerd-1.2.6/services/leases/service.go containerd-1.5.9/services/leases/service.go --- containerd-1.2.6/services/leases/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/leases/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -113,6 +113,56 @@ }, nil } +func (s *service) AddResource(ctx context.Context, r *api.AddResourceRequest) (*ptypes.Empty, error) { + lease := leases.Lease{ + ID: r.ID, + } + + if err := s.lm.AddResource(ctx, lease, leases.Resource{ + ID: r.Resource.ID, + Type: r.Resource.Type, + }); err != nil { + return nil, errdefs.ToGRPC(err) + } + return &ptypes.Empty{}, nil +} + +func (s *service) DeleteResource(ctx context.Context, r *api.DeleteResourceRequest) (*ptypes.Empty, error) { + lease := leases.Lease{ + ID: r.ID, + } + + if err := s.lm.DeleteResource(ctx, lease, leases.Resource{ + ID: r.Resource.ID, + Type: r.Resource.Type, + }); err != nil { + return nil, errdefs.ToGRPC(err) + } + return &ptypes.Empty{}, nil +} + +func (s *service) ListResources(ctx context.Context, r *api.ListResourcesRequest) (*api.ListResourcesResponse, error) { + lease := leases.Lease{ + ID: r.ID, + } + + rs, err := s.lm.ListResources(ctx, lease) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + apiResources := make([]api.Resource, 0, len(rs)) + for _, i := range rs { + apiResources = append(apiResources, api.Resource{ + ID: i.ID, + Type: i.Type, + }) + } + return &api.ListResourcesResponse{ + Resources: apiResources, + }, nil +} + func leaseToGRPC(l leases.Lease) *api.Lease { return &api.Lease{ ID: l.ID, diff -Nru containerd-1.2.6/services/opt/service.go containerd-1.5.9/services/opt/service.go --- containerd-1.2.6/services/opt/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/opt/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,6 @@ "fmt" "os" "path/filepath" - "runtime" "github.com/containerd/containerd/plugin" "github.com/pkg/errors" @@ -42,22 +41,20 @@ InitFn: func(ic *plugin.InitContext) (interface{}, error) { path := ic.Config.(*Config).Path ic.Meta.Exports["path"] = path - bin := filepath.Join(path, "bin") if err := os.MkdirAll(bin, 0711); err != nil { return nil, err } - if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", bin, os.Getenv("PATH"))); err != nil { + if err := os.Setenv("PATH", fmt.Sprintf("%s%c%s", bin, os.PathListSeparator, os.Getenv("PATH"))); err != nil { return nil, errors.Wrapf(err, "set binary image directory in path %s", bin) } - if runtime.GOOS != "windows" { - lib := filepath.Join(path, "lib") - if err := os.MkdirAll(lib, 0711); err != nil { - return nil, err - } - if err := os.Setenv("LD_LIBRARY_PATH", fmt.Sprintf("%s:%s", os.Getenv("LD_LIBRARY_PATH"), lib)); err != nil { - return nil, errors.Wrapf(err, "set binary lib directory in path %s", lib) - } + + lib := filepath.Join(path, "lib") + if err := os.MkdirAll(lib, 0711); err != nil { + return nil, err + } + if err := os.Setenv("LD_LIBRARY_PATH", fmt.Sprintf("%s%c%s", lib, os.PathListSeparator, os.Getenv("LD_LIBRARY_PATH"))); err != nil { + return nil, errors.Wrapf(err, "set binary lib directory in path %s", lib) } return &manager{}, nil }, diff -Nru containerd-1.2.6/services/server/config/config.go containerd-1.5.9/services/server/config/config.go --- containerd-1.2.6/services/server/config/config.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/config/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,19 +17,34 @@ package config import ( - "github.com/BurntSushi/toml" - "github.com/containerd/containerd/errdefs" + "path/filepath" + "strings" + + "github.com/imdario/mergo" + "github.com/pelletier/go-toml" "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/plugin" ) +// NOTE: Any new map fields added also need to be handled in mergeConfig. + // Config provides containerd configuration data for the server type Config struct { + // Version of the config file + Version int `toml:"version"` // Root is the path to a directory where containerd will store persistent data Root string `toml:"root"` // State is the path to a directory where containerd will store transient data State string `toml:"state"` + // PluginDir is the directory for dynamic plugins to be stored + PluginDir string `toml:"plugin_dir"` // GRPC configuration settings GRPC GRPCConfig `toml:"grpc"` + // TTRPC configuration settings + TTRPC TTRPCConfig `toml:"ttrpc"` // Debug and profiling settings Debug Debug `toml:"debug"` // Metrics and monitoring settings @@ -37,33 +52,99 @@ // DisabledPlugins are IDs of plugins to disable. Disabled plugins won't be // initialized and started. DisabledPlugins []string `toml:"disabled_plugins"` + // RequiredPlugins are IDs of required plugins. Containerd exits if any + // required plugin doesn't exist or fails to be initialized or started. + RequiredPlugins []string `toml:"required_plugins"` // Plugins provides plugin specific configuration for the initialization of a plugin - Plugins map[string]toml.Primitive `toml:"plugins"` + Plugins map[string]toml.Tree `toml:"plugins"` // OOMScore adjust the containerd's oom score OOMScore int `toml:"oom_score"` // Cgroup specifies cgroup information for the containerd daemon process Cgroup CgroupConfig `toml:"cgroup"` // ProxyPlugins configures plugins which are communicated to over GRPC ProxyPlugins map[string]ProxyPlugin `toml:"proxy_plugins"` + // Timeouts specified as a duration + Timeouts map[string]string `toml:"timeouts"` + // Imports are additional file path list to config files that can overwrite main config file fields + Imports []string `toml:"imports"` + + StreamProcessors map[string]StreamProcessor `toml:"stream_processors"` +} + +// StreamProcessor provides configuration for diff content processors +type StreamProcessor struct { + // Accepts specific media-types + Accepts []string `toml:"accepts"` + // Returns the media-type + Returns string `toml:"returns"` + // Path or name of the binary + Path string `toml:"path"` + // Args to the binary + Args []string `toml:"args"` + // Environment variables for the binary + Env []string `toml:"env"` +} - md toml.MetaData +// GetVersion returns the config file's version +func (c *Config) GetVersion() int { + if c.Version == 0 { + return 1 + } + return c.Version +} + +// ValidateV2 validates the config for a v2 file +func (c *Config) ValidateV2() error { + version := c.GetVersion() + if version < 2 { + logrus.Warnf("deprecated version : `%d`, please switch to version `2`", version) + return nil + } + for _, p := range c.DisabledPlugins { + if len(strings.Split(p, ".")) < 4 { + return errors.Errorf("invalid disabled plugin URI %q expect io.containerd.x.vx", p) + } + } + for _, p := range c.RequiredPlugins { + if len(strings.Split(p, ".")) < 4 { + return errors.Errorf("invalid required plugin URI %q expect io.containerd.x.vx", p) + } + } + for p := range c.Plugins { + if len(strings.Split(p, ".")) < 4 { + return errors.Errorf("invalid plugin key URI %q expect io.containerd.x.vx", p) + } + } + return nil } // GRPCConfig provides GRPC configuration for the socket type GRPCConfig struct { Address string `toml:"address"` + TCPAddress string `toml:"tcp_address"` + TCPTLSCert string `toml:"tcp_tls_cert"` + TCPTLSKey string `toml:"tcp_tls_key"` UID int `toml:"uid"` GID int `toml:"gid"` MaxRecvMsgSize int `toml:"max_recv_message_size"` MaxSendMsgSize int `toml:"max_send_message_size"` } +// TTRPCConfig provides TTRPC configuration for the socket +type TTRPCConfig struct { + Address string `toml:"address"` + UID int `toml:"uid"` + GID int `toml:"gid"` +} + // Debug provides debug configuration type Debug struct { Address string `toml:"address"` UID int `toml:"uid"` GID int `toml:"gid"` Level string `toml:"level"` + // Format represents the logging format + Format string `toml:"format"` } // MetricsConfig provides metrics configuration @@ -83,27 +164,209 @@ Address string `toml:"address"` } +// BoltConfig defines the configuration values for the bolt plugin, which is +// loaded here, rather than back registered in the metadata package. +type BoltConfig struct { + // ContentSharingPolicy sets the sharing policy for content between + // namespaces. + // + // The default mode "shared" will make blobs available in all + // namespaces once it is pulled into any namespace. The blob will be pulled + // into the namespace if a writer is opened with the "Expected" digest that + // is already present in the backend. + // + // The alternative mode, "isolated" requires that clients prove they have + // access to the content by providing all of the content to the ingest + // before the blob is added to the namespace. + // + // Both modes share backing data, while "shared" will reduce total + // bandwidth across namespaces, at the cost of allowing access to any blob + // just by knowing its digest. + ContentSharingPolicy string `toml:"content_sharing_policy"` +} + +const ( + // SharingPolicyShared represents the "shared" sharing policy + SharingPolicyShared = "shared" + // SharingPolicyIsolated represents the "isolated" sharing policy + SharingPolicyIsolated = "isolated" +) + +// Validate validates if BoltConfig is valid +func (bc *BoltConfig) Validate() error { + switch bc.ContentSharingPolicy { + case SharingPolicyShared, SharingPolicyIsolated: + return nil + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "unknown policy: %s", bc.ContentSharingPolicy) + } +} + // Decode unmarshals a plugin specific configuration by plugin id -func (c *Config) Decode(id string, v interface{}) (interface{}, error) { +func (c *Config) Decode(p *plugin.Registration) (interface{}, error) { + id := p.URI() + if c.GetVersion() == 1 { + id = p.ID + } data, ok := c.Plugins[id] if !ok { - return v, nil + return p.Config, nil } - if err := c.md.PrimitiveDecode(data, v); err != nil { + if err := data.Unmarshal(p.Config); err != nil { return nil, err } - return v, nil + return p.Config, nil } // LoadConfig loads the containerd server config from the provided path -func LoadConfig(path string, v *Config) error { - if v == nil { - return errors.Wrapf(errdefs.ErrInvalidArgument, "argument v must not be nil") +func LoadConfig(path string, out *Config) error { + if out == nil { + return errors.Wrapf(errdefs.ErrInvalidArgument, "argument out must not be nil") + } + + var ( + loaded = map[string]bool{} + pending = []string{path} + ) + + for len(pending) > 0 { + path, pending = pending[0], pending[1:] + + // Check if a file at the given path already loaded to prevent circular imports + if _, ok := loaded[path]; ok { + continue + } + + config, err := loadConfigFile(path) + if err != nil { + return err + } + + if err := mergeConfig(out, config); err != nil { + return err + } + + imports, err := resolveImports(path, config.Imports) + if err != nil { + return err + } + + loaded[path] = true + pending = append(pending, imports...) } - md, err := toml.DecodeFile(path, v) + + // Fix up the list of config files loaded + out.Imports = []string{} + for path := range loaded { + out.Imports = append(out.Imports, path) + } + + err := out.ValidateV2() + if err != nil { + return errors.Wrapf(err, "failed to load TOML from %s", path) + } + return nil +} + +// loadConfigFile decodes a TOML file at the given path +func loadConfigFile(path string) (*Config, error) { + config := &Config{} + + file, err := toml.LoadFile(path) + if err != nil { + return nil, errors.Wrapf(err, "failed to load TOML: %s", path) + } + + if err := file.Unmarshal(config); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal TOML") + } + + return config, nil +} + +// resolveImports resolves import strings list to absolute paths list: +// - If path contains *, glob pattern matching applied +// - Non abs path is relative to parent config file directory +// - Abs paths returned as is +func resolveImports(parent string, imports []string) ([]string, error) { + var out []string + + for _, path := range imports { + if strings.Contains(path, "*") { + matches, err := filepath.Glob(path) + if err != nil { + return nil, err + } + + out = append(out, matches...) + } else { + path = filepath.Clean(path) + if !filepath.IsAbs(path) { + path = filepath.Join(filepath.Dir(parent), path) + } + + out = append(out, path) + } + } + + return out, nil +} + +// mergeConfig merges Config structs with the following rules: +// 'to' 'from' 'result' +// "" "value" "value" +// "value" "" "value" +// 1 0 1 +// 0 1 1 +// []{"1"} []{"2"} []{"1","2"} +// []{"1"} []{} []{"1"} +// Maps merged by keys, but values are replaced entirely. +func mergeConfig(to, from *Config) error { + err := mergo.Merge(to, from, mergo.WithOverride, mergo.WithAppendSlice) if err != nil { return err } - v.md = md + + // Replace entire sections instead of merging map's values. + for k, v := range from.Plugins { + to.Plugins[k] = v + } + + for k, v := range from.StreamProcessors { + to.StreamProcessors[k] = v + } + + for k, v := range from.ProxyPlugins { + to.ProxyPlugins[k] = v + } + + for k, v := range from.Timeouts { + to.Timeouts[k] = v + } + return nil } + +// V1DisabledFilter matches based on ID +func V1DisabledFilter(list []string) plugin.DisableFilter { + set := make(map[string]struct{}, len(list)) + for _, l := range list { + set[l] = struct{}{} + } + return func(r *plugin.Registration) bool { + _, ok := set[r.ID] + return ok + } +} + +// V2DisabledFilter matches based on URI +func V2DisabledFilter(list []string) plugin.DisableFilter { + set := make(map[string]struct{}, len(list)) + for _, l := range list { + set[l] = struct{}{} + } + return func(r *plugin.Registration) bool { + _, ok := set[r.URI()] + return ok + } +} diff -Nru containerd-1.2.6/services/server/config/config_test.go containerd-1.5.9/services/server/config/config_test.go --- containerd-1.2.6/services/server/config/config_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/server/config/config_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,235 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "io/ioutil" + "os" + "path/filepath" + "sort" + "testing" + + "gotest.tools/v3/assert" + + "github.com/containerd/containerd/plugin" +) + +func TestMergeConfigs(t *testing.T) { + a := &Config{ + Version: 2, + Root: "old_root", + RequiredPlugins: []string{"old_plugin"}, + DisabledPlugins: []string{"old_plugin"}, + State: "old_state", + OOMScore: 1, + Timeouts: map[string]string{"a": "1"}, + StreamProcessors: map[string]StreamProcessor{"1": {Path: "2", Returns: "4"}, "2": {Path: "5"}}, + } + + b := &Config{ + Root: "new_root", + RequiredPlugins: []string{"new_plugin1", "new_plugin2"}, + OOMScore: 2, + Timeouts: map[string]string{"b": "2"}, + StreamProcessors: map[string]StreamProcessor{"1": {Path: "3"}}, + } + + err := mergeConfig(a, b) + assert.NilError(t, err) + + assert.Equal(t, a.Version, 2) + assert.Equal(t, a.Root, "new_root") + assert.Equal(t, a.State, "old_state") + assert.Equal(t, a.OOMScore, 2) + assert.DeepEqual(t, a.RequiredPlugins, []string{"old_plugin", "new_plugin1", "new_plugin2"}) + assert.DeepEqual(t, a.DisabledPlugins, []string{"old_plugin"}) + assert.DeepEqual(t, a.Timeouts, map[string]string{"a": "1", "b": "2"}) + assert.DeepEqual(t, a.StreamProcessors, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}}) +} + +func TestResolveImports(t *testing.T) { + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + for _, filename := range []string{"config_1.toml", "config_2.toml", "test.toml"} { + err = ioutil.WriteFile(filepath.Join(tempDir, filename), []byte(""), 0600) + assert.NilError(t, err) + } + + imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{ + filepath.Join(tempDir, "config_*.toml"), // Glob + filepath.Join(tempDir, "./test.toml"), // Path clean up + "current.toml", // Resolve current working dir + }) + assert.NilError(t, err) + + assert.DeepEqual(t, imports, []string{ + filepath.Join(tempDir, "config_1.toml"), + filepath.Join(tempDir, "config_2.toml"), + filepath.Join(tempDir, "test.toml"), + filepath.Join(tempDir, "current.toml"), + }) +} + +func TestLoadSingleConfig(t *testing.T) { + data := ` +version = 2 +root = "/var/lib/containerd" + +[stream_processors] + [stream_processors."io.containerd.processor.v1.pigz"] + accepts = ["application/vnd.docker.image.rootfs.diff.tar.gzip"] + path = "unpigz" +` + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + path := filepath.Join(tempDir, "config.toml") + err = ioutil.WriteFile(path, []byte(data), 0600) + assert.NilError(t, err) + + var out Config + err = LoadConfig(path, &out) + assert.NilError(t, err) + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.DeepEqual(t, map[string]StreamProcessor{ + "io.containerd.processor.v1.pigz": { + Accepts: []string{"application/vnd.docker.image.rootfs.diff.tar.gzip"}, + Path: "unpigz", + }, + }, out.StreamProcessors) +} + +func TestLoadConfigWithImports(t *testing.T) { + data1 := ` +version = 2 +root = "/var/lib/containerd" +imports = ["data2.toml"] +` + + data2 := ` +disabled_plugins = ["io.containerd.v1.xyz"] +` + + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + err = ioutil.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600) + assert.NilError(t, err) + + err = ioutil.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600) + assert.NilError(t, err) + + var out Config + err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out) + assert.NilError(t, err) + + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins) +} + +func TestLoadConfigWithCircularImports(t *testing.T) { + data1 := ` +version = 2 +root = "/var/lib/containerd" +imports = ["data2.toml", "data1.toml"] +` + + data2 := ` +disabled_plugins = ["io.containerd.v1.xyz"] +imports = ["data1.toml", "data2.toml"] +` + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + err = ioutil.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600) + assert.NilError(t, err) + + err = ioutil.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600) + assert.NilError(t, err) + + var out Config + err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out) + assert.NilError(t, err) + + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins) + + sort.Strings(out.Imports) + assert.DeepEqual(t, []string{ + filepath.Join(tempDir, "data1.toml"), + filepath.Join(tempDir, "data2.toml"), + }, out.Imports) +} + +func TestDecodePlugin(t *testing.T) { + data := ` +version = 2 +[plugins."io.containerd.runtime.v1.linux"] + shim_debug = true +` + + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + path := filepath.Join(tempDir, "config.toml") + err = ioutil.WriteFile(path, []byte(data), 0600) + assert.NilError(t, err) + + var out Config + err = LoadConfig(path, &out) + assert.NilError(t, err) + + pluginConfig := map[string]interface{}{} + _, err = out.Decode(&plugin.Registration{Type: "io.containerd.runtime.v1", ID: "linux", Config: &pluginConfig}) + assert.NilError(t, err) + assert.Equal(t, true, pluginConfig["shim_debug"]) +} + +// TestDecodePluginInV1Config tests decoding non-versioned +// config (should be parsed as V1 config). +func TestDecodePluginInV1Config(t *testing.T) { + data := ` +[plugins.linux] + shim_debug = true +` + + tempDir, err := ioutil.TempDir("", "containerd_") + assert.NilError(t, err) + defer os.RemoveAll(tempDir) + + path := filepath.Join(tempDir, "config.toml") + err = ioutil.WriteFile(path, []byte(data), 0600) + assert.NilError(t, err) + + var out Config + err = LoadConfig(path, &out) + assert.NilError(t, err) + + pluginConfig := map[string]interface{}{} + _, err = out.Decode(&plugin.Registration{ID: "linux", Config: &pluginConfig}) + assert.NilError(t, err) + assert.Equal(t, true, pluginConfig["shim_debug"]) +} diff -Nru containerd-1.2.6/services/server/server.go containerd-1.5.9/services/server/server.go --- containerd-1.2.6/services/server/server.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server.go 2022-01-05 17:30:58.000000000 +0000 @@ -35,45 +35,64 @@ "github.com/containerd/containerd/content/local" csproxy "github.com/containerd/containerd/content/proxy" "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/diff" "github.com/containerd/containerd/events/exchange" "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/pkg/dialer" + "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/plugin" srvconfig "github.com/containerd/containerd/services/server/config" "github.com/containerd/containerd/snapshots" ssproxy "github.com/containerd/containerd/snapshots/proxy" + "github.com/containerd/containerd/sys" + "github.com/containerd/ttrpc" metrics "github.com/docker/go-metrics" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/pkg/errors" bolt "go.etcd.io/bbolt" "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" ) -// New creates and initializes a new containerd server -func New(ctx context.Context, config *srvconfig.Config) (*Server, error) { +// CreateTopLevelDirectories creates the top-level root and state directories. +func CreateTopLevelDirectories(config *srvconfig.Config) error { switch { case config.Root == "": - return nil, errors.New("root must be specified") + return errors.New("root must be specified") case config.State == "": - return nil, errors.New("state must be specified") + return errors.New("state must be specified") case config.Root == config.State: - return nil, errors.New("root and state must be different paths") + return errors.New("root and state must be different paths") } - if err := os.MkdirAll(config.Root, 0711); err != nil { - return nil, err - } - if err := os.MkdirAll(config.State, 0711); err != nil { - return nil, err + if err := sys.MkdirAllWithACL(config.Root, 0711); err != nil { + return err } + + return sys.MkdirAllWithACL(config.State, 0711) +} + +// New creates and initializes a new containerd server +func New(ctx context.Context, config *srvconfig.Config) (*Server, error) { if err := apply(ctx, config); err != nil { return nil, err } + for key, sec := range config.Timeouts { + d, err := time.ParseDuration(sec) + if err != nil { + return nil, errors.Errorf("unable to parse %s into a time duration", sec) + } + timeout.Set(key, d) + } plugins, err := LoadPlugins(ctx, config) if err != nil { return nil, err } + for id, p := range config.StreamProcessors { + diff.RegisterProcessor(diff.BinaryHandler(id, p.Returns, p.Accepts, p.Path, p.Args, p.Env)) + } serverOpts := []grpc.ServerOption{ grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor), @@ -85,18 +104,46 @@ if config.GRPC.MaxSendMsgSize > 0 { serverOpts = append(serverOpts, grpc.MaxSendMsgSize(config.GRPC.MaxSendMsgSize)) } - rpc := grpc.NewServer(serverOpts...) + ttrpcServer, err := newTTRPCServer() + if err != nil { + return nil, err + } + tcpServerOpts := serverOpts + if config.GRPC.TCPTLSCert != "" { + log.G(ctx).Info("setting up tls on tcp GRPC services...") + creds, err := credentials.NewServerTLSFromFile(config.GRPC.TCPTLSCert, config.GRPC.TCPTLSKey) + if err != nil { + return nil, err + } + tcpServerOpts = append(tcpServerOpts, grpc.Creds(creds)) + } var ( - services []plugin.Service - s = &Server{ - rpc: rpc, - events: exchange.NewExchange(), - config: config, + grpcServer = grpc.NewServer(serverOpts...) + tcpServer = grpc.NewServer(tcpServerOpts...) + + grpcServices []plugin.Service + tcpServices []plugin.TCPService + ttrpcServices []plugin.TTRPCService + + s = &Server{ + grpcServer: grpcServer, + tcpServer: tcpServer, + ttrpcServer: ttrpcServer, + events: exchange.NewExchange(), + config: config, } initialized = plugin.NewPluginSet() + required = make(map[string]struct{}) ) + for _, r := range config.RequiredPlugins { + required[r] = struct{}{} + } for _, p := range plugins { id := p.URI() + reqID := id + if config.GetVersion() == 1 { + reqID = p.ID + } log.G(ctx).WithField("type", p.Type).Infof("loading plugin %q...", id) initContext := plugin.NewContext( @@ -108,14 +155,15 @@ ) initContext.Events = s.events initContext.Address = config.GRPC.Address + initContext.TTRPCAddress = config.TTRPC.Address // load the plugin specific configuration if it is provided if p.Config != nil { - pluginConfig, err := config.Decode(p.ID, p.Config) + pc, err := config.Decode(p) if err != nil { return nil, err } - initContext.Config = pluginConfig + initContext.Config = pc } result := p.Init(initContext) if err := initialized.Add(result); err != nil { @@ -125,21 +173,51 @@ instance, err := result.Instance() if err != nil { if plugin.IsSkipPlugin(err) { - log.G(ctx).WithField("type", p.Type).Infof("skip loading plugin %q...", id) + log.G(ctx).WithError(err).WithField("type", p.Type).Infof("skip loading plugin %q...", id) } else { log.G(ctx).WithError(err).Warnf("failed to load plugin %s", id) } + if _, ok := required[reqID]; ok { + return nil, errors.Wrapf(err, "load required plugin %s", id) + } continue } + + delete(required, reqID) // check for grpc services that should be registered with the server - if service, ok := instance.(plugin.Service); ok { - services = append(services, service) + if src, ok := instance.(plugin.Service); ok { + grpcServices = append(grpcServices, src) } + if src, ok := instance.(plugin.TTRPCService); ok { + ttrpcServices = append(ttrpcServices, src) + } + if service, ok := instance.(plugin.TCPService); ok { + tcpServices = append(tcpServices, service) + } + s.plugins = append(s.plugins, result) } + if len(required) != 0 { + var missing []string + for id := range required { + missing = append(missing, id) + } + return nil, errors.Errorf("required plugin %s not included", missing) + } + // register services after all plugins have been initialized - for _, service := range services { - if err := service.Register(rpc); err != nil { + for _, service := range grpcServices { + if err := service.Register(grpcServer); err != nil { + return nil, err + } + } + for _, service := range ttrpcServices { + if err := service.RegisterTTRPC(ttrpcServer); err != nil { + return nil, err + } + } + for _, service := range tcpServices { + if err := service.RegisterTCP(tcpServer); err != nil { return nil, err } } @@ -148,10 +226,12 @@ // Server is the containerd main daemon type Server struct { - rpc *grpc.Server - events *exchange.Exchange - config *srvconfig.Config - plugins []*plugin.Plugin + grpcServer *grpc.Server + ttrpcServer *ttrpc.Server + tcpServer *grpc.Server + events *exchange.Exchange + config *srvconfig.Config + plugins []*plugin.Plugin } // ServeGRPC provides the containerd grpc APIs on the provided listener @@ -163,8 +243,13 @@ // before we start serving the grpc API register the grpc_prometheus metrics // handler. This needs to be the last service registered so that it can collect // metrics for every other service - grpc_prometheus.Register(s.rpc) - return trapClosedConnErr(s.rpc.Serve(l)) + grpc_prometheus.Register(s.grpcServer) + return trapClosedConnErr(s.grpcServer.Serve(l)) +} + +// ServeTTRPC provides the containerd ttrpc APIs on the provided listener +func (s *Server) ServeTTRPC(l net.Listener) error { + return trapClosedConnErr(s.ttrpcServer.Serve(context.Background(), l)) } // ServeMetrics provides a prometheus endpoint for exposing metrics @@ -174,6 +259,12 @@ return trapClosedConnErr(http.Serve(l, m)) } +// ServeTCP allows services to serve over tcp +func (s *Server) ServeTCP(l net.Listener) error { + grpc_prometheus.Register(s.tcpServer) + return trapClosedConnErr(s.tcpServer.Serve(l)) +} + // ServeDebug provides a debug endpoint func (s *Server) ServeDebug(l net.Listener) error { // don't use the default http server mux to make sure nothing gets registered @@ -190,12 +281,12 @@ // Stop the containerd server canceling any open connections func (s *Server) Stop() { - s.rpc.Stop() + s.grpcServer.Stop() for i := len(s.plugins) - 1; i >= 0; i-- { p := s.plugins[i] instance, err := p.Instance() if err != nil { - log.L.WithError(err).WithField("id", p.Registration.ID). + log.L.WithError(err).WithField("id", p.Registration.URI()). Errorf("could not get plugin instance") continue } @@ -204,7 +295,7 @@ continue } if err := closer.Close(); err != nil { - log.L.WithError(err).WithField("id", p.Registration.ID). + log.L.WithError(err).WithField("id", p.Registration.URI()). Errorf("failed to close plugin") } } @@ -214,7 +305,11 @@ // of all plugins. func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]*plugin.Registration, error) { // load all plugins into containerd - if err := plugin.Load(filepath.Join(config.Root, "plugins")); err != nil { + path := config.PluginDir + if path == "" { + path = filepath.Join(config.Root, "plugins") + } + if err := plugin.Load(path); err != nil { return nil, err } // load additional plugins that don't automatically register themselves @@ -233,6 +328,9 @@ plugin.ContentPlugin, plugin.SnapshotPlugin, }, + Config: &srvconfig.BoltConfig{ + ContentSharingPolicy: srvconfig.SharingPolicyShared, + }, InitFn: func(ic *plugin.InitContext) (interface{}, error) { if err := os.MkdirAll(ic.Root, 0711); err != nil { return nil, err @@ -251,13 +349,31 @@ for name, sn := range snapshottersRaw { sn, err := sn.Instance() if err != nil { - log.G(ic.Context).WithError(err). - Warnf("could not use snapshotter %v in metadata plugin", name) + if !plugin.IsSkipPlugin(err) { + log.G(ic.Context).WithError(err). + Warnf("could not use snapshotter %v in metadata plugin", name) + } continue } snapshotters[name] = sn.(snapshots.Snapshotter) } + shared := true + ic.Meta.Exports["policy"] = srvconfig.SharingPolicyShared + if cfg, ok := ic.Config.(*srvconfig.BoltConfig); ok { + if cfg.ContentSharingPolicy != "" { + if err := cfg.Validate(); err != nil { + return nil, err + } + if cfg.ContentSharingPolicy == srvconfig.SharingPolicyIsolated { + ic.Meta.Exports["policy"] = srvconfig.SharingPolicyIsolated + shared = false + } + + log.L.WithField("policy", cfg.ContentSharingPolicy).Info("metadata content store policy set") + } + } + path := filepath.Join(ic.Root, "meta.db") ic.Meta.Exports["path"] = path @@ -265,7 +381,12 @@ if err != nil { return nil, err } - mdb := metadata.NewDB(db, cs.(content.Store), snapshotters) + + var dbopts []metadata.DBOpt + if !shared { + dbopts = append(dbopts, metadata.WithPolicyIsolated) + } + mdb := metadata.NewDB(db, cs.(content.Store), snapshotters, dbopts...) if err := mdb.Init(ic.Context); err != nil { return nil, err } @@ -314,8 +435,12 @@ } + filter := srvconfig.V2DisabledFilter + if config.GetVersion() == 1 { + filter = srvconfig.V1DisabledFilter + } // return the ordered graph for plugins - return plugin.Graph(config.DisabledPlugins), nil + return plugin.Graph(filter(config.DisabledPlugins)), nil } type proxyClients struct { @@ -332,10 +457,15 @@ return c, nil } + backoffConfig := backoff.DefaultConfig + backoffConfig.MaxDelay = 3 * time.Second + connParams := grpc.ConnectParams{ + Backoff: backoffConfig, + } gopts := []grpc.DialOption{ grpc.WithInsecure(), - grpc.WithBackoffMaxDelay(3 * time.Second), - grpc.WithDialer(dialer.Dialer), + grpc.WithConnectParams(connParams), + grpc.WithContextDialer(dialer.ContextDialer), // TODO(stevvooe): We may need to allow configuration of this on the client. grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), diff -Nru containerd-1.2.6/services/server/server_linux.go containerd-1.5.9/services/server/server_linux.go --- containerd-1.2.6/services/server/server_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,9 +21,11 @@ "os" "github.com/containerd/cgroups" + cgroupsv2 "github.com/containerd/cgroups/v2" "github.com/containerd/containerd/log" srvconfig "github.com/containerd/containerd/services/server/config" "github.com/containerd/containerd/sys" + "github.com/containerd/ttrpc" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -36,20 +38,39 @@ } } if config.Cgroup.Path != "" { - cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path)) - if err != nil { - if err != cgroups.ErrCgroupDeleted { + if cgroups.Mode() == cgroups.Unified { + cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", config.Cgroup.Path) + if err != nil { + if err != cgroupsv2.ErrCgroupDeleted { + return err + } + if cg, err = cgroupsv2.NewManager("/sys/fs/cgroup", config.Cgroup.Path, nil); err != nil { + return err + } + } + if err := cg.AddProc(uint64(os.Getpid())); err != nil { return err } - if cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path), &specs.LinuxResources{}); err != nil { + } else { + cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path)) + if err != nil { + if err != cgroups.ErrCgroupDeleted { + return err + } + if cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path), &specs.LinuxResources{}); err != nil { + return err + } + } + if err := cg.Add(cgroups.Process{ + Pid: os.Getpid(), + }); err != nil { return err } } - if err := cg.Add(cgroups.Process{ - Pid: os.Getpid(), - }); err != nil { - return err - } } return nil } + +func newTTRPCServer() (*ttrpc.Server, error) { + return ttrpc.NewServer(ttrpc.WithServerHandshaker(ttrpc.UnixSocketRequireSameUser())) +} diff -Nru containerd-1.2.6/services/server/server_solaris.go containerd-1.5.9/services/server/server_solaris.go --- containerd-1.2.6/services/server/server_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server_solaris.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,7 @@ import ( "context" - srvconfig "github.com/containerd/containerd/server/config" + srvconfig "github.com/containerd/containerd/services/server/config" ) func apply(_ context.Context, _ *srvconfig.Config) error { diff -Nru containerd-1.2.6/services/server/server_test.go containerd-1.5.9/services/server/server_test.go --- containerd-1.2.6/services/server/server_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,19 +17,38 @@ package server import ( - "context" "testing" srvconfig "github.com/containerd/containerd/services/server/config" - "gotest.tools/assert" - is "gotest.tools/assert/cmp" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) -func TestNewErrorsWithSamePathForRootAndState(t *testing.T) { +func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T) { path := "/tmp/path/for/testing" - _, err := New(context.Background(), &srvconfig.Config{ + err := CreateTopLevelDirectories(&srvconfig.Config{ Root: path, State: path, }) assert.Check(t, is.Error(err, "root and state must be different paths")) } + +func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) { + statePath := "" + rootPath := "/tmp/path/for/testing" + err := CreateTopLevelDirectories(&srvconfig.Config{ + Root: rootPath, + State: statePath, + }) + assert.Check(t, is.Error(err, "state must be specified")) +} + +func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) { + statePath := "/tmp/path/for/testing" + rootPath := "" + err := CreateTopLevelDirectories(&srvconfig.Config{ + Root: rootPath, + State: statePath, + }) + assert.Check(t, is.Error(err, "root must be specified")) +} diff -Nru containerd-1.2.6/services/server/server_unsupported.go containerd-1.5.9/services/server/server_unsupported.go --- containerd-1.2.6/services/server/server_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,8 +22,13 @@ "context" srvconfig "github.com/containerd/containerd/services/server/config" + "github.com/containerd/ttrpc" ) func apply(_ context.Context, _ *srvconfig.Config) error { return nil } + +func newTTRPCServer() (*ttrpc.Server, error) { + return ttrpc.NewServer() +} diff -Nru containerd-1.2.6/services/server/server_windows.go containerd-1.5.9/services/server/server_windows.go --- containerd-1.2.6/services/server/server_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/server/server_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,8 +22,13 @@ "context" srvconfig "github.com/containerd/containerd/services/server/config" + "github.com/containerd/ttrpc" ) func apply(_ context.Context, _ *srvconfig.Config) error { return nil } + +func newTTRPCServer() (*ttrpc.Server, error) { + return ttrpc.NewServer() +} diff -Nru containerd-1.2.6/services/services.go containerd-1.5.9/services/services.go --- containerd-1.2.6/services/services.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/services.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,4 +33,6 @@ LeasesService = "leases-service" // DiffService is id of diff service. DiffService = "diff-service" + // IntrospectionService is the id of introspection service + IntrospectionService = "introspection-service" ) diff -Nru containerd-1.2.6/services/snapshots/service.go containerd-1.5.9/services/snapshots/service.go --- containerd-1.2.6/services/snapshots/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/snapshots/service.go 2022-01-05 17:30:58.000000000 +0000 @@ -227,7 +227,7 @@ } return nil - }) + }, sr.Filters...) if err != nil { return err } @@ -255,6 +255,25 @@ return fromUsage(usage), nil } +func (s *service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) { + sn, err := s.getSnapshotter(cr.Snapshotter) + if err != nil { + return nil, err + } + + c, ok := sn.(snapshots.Cleaner) + if !ok { + return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method") + } + + err = c.Cleanup(ctx) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + return empty, nil +} + func fromKind(kind snapshots.Kind) snapshotsapi.Kind { if kind == snapshots.KindActive { return snapshotsapi.KindActive diff -Nru containerd-1.2.6/services/tasks/local_freebsd.go containerd-1.5.9/services/tasks/local_freebsd.go --- containerd-1.2.6/services/tasks/local_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/tasks/local_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package tasks + +import ( + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/runtime" +) + +var tasksServiceRequires = []plugin.Type{ + plugin.RuntimePluginV2, + plugin.MetadataPlugin, + plugin.TaskMonitorPlugin, +} + +// loadV1Runtimes on FreeBSD returns an empty map. There are no v1 runtimes +func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { + return make(map[string]runtime.PlatformRuntime), nil +} diff -Nru containerd-1.2.6/services/tasks/local.go containerd-1.5.9/services/tasks/local.go --- containerd-1.2.6/services/tasks/local.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/tasks/local.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,6 +24,7 @@ "io/ioutil" "os" "path/filepath" + "strings" "time" api "github.com/containerd/containerd/api/services/tasks/v1" @@ -39,15 +40,17 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/runtime" - "github.com/containerd/containerd/runtime/v2" + "github.com/containerd/containerd/runtime/linux/runctypes" + v2 "github.com/containerd/containerd/runtime/v2" + "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/containerd/containerd/services" "github.com/containerd/typeurl" ptypes "github.com/gogo/protobuf/types" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - bolt "go.etcd.io/bbolt" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -58,6 +61,10 @@ empty = &ptypes.Empty{} ) +const ( + stateTimeout = "io.containerd.timeout.task.state" +) + func init() { plugin.Register(&plugin.Registration{ Type: plugin.ServicePlugin, @@ -65,6 +72,8 @@ Requires: tasksServiceRequires, InitFn: initFunc, }) + + timeout.Set(stateTimeout, 2*time.Second) } func initFunc(ic *plugin.InitContext) (interface{}, error) { @@ -91,14 +100,14 @@ monitor = runtime.NewNoopMonitor() } - cs := m.(*metadata.DB).ContentStore() + db := m.(*metadata.DB) l := &local{ - runtimes: runtimes, - db: m.(*metadata.DB), - store: cs, - publisher: ic.Events, - monitor: monitor.(runtime.TaskMonitor), - v2Runtime: v2r.(*v2.TaskManager), + runtimes: runtimes, + containers: metadata.NewContainerStore(db), + store: db.ContentStore(), + publisher: ic.Events, + monitor: monitor.(runtime.TaskMonitor), + v2Runtime: v2r.(*v2.TaskManager), } for _, r := range runtimes { tasks, err := r.Tasks(ic.Context, true) @@ -109,25 +118,37 @@ l.monitor.Monitor(t) } } + v2Tasks, err := l.v2Runtime.Tasks(ic.Context, true) + if err != nil { + return nil, err + } + for _, t := range v2Tasks { + l.monitor.Monitor(t) + } return l, nil } type local struct { - runtimes map[string]runtime.PlatformRuntime - db *metadata.DB - store content.Store - publisher events.Publisher + runtimes map[string]runtime.PlatformRuntime + containers containers.Store + store content.Store + publisher events.Publisher monitor runtime.TaskMonitor v2Runtime *v2.TaskManager } func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc.CallOption) (*api.CreateTaskResponse, error) { - var ( - checkpointPath string - err error - ) - if r.Checkpoint != nil { + container, err := l.getContainer(ctx, r.ContainerID) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + checkpointPath, err := getRestorePath(container.Runtime.Name, r.Options) + if err != nil { + return nil, err + } + // jump get checkpointPath from checkpoint image + if checkpointPath == "" && r.Checkpoint != nil { checkpointPath, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctrd-checkpoint") if err != nil { return nil, err @@ -136,9 +157,10 @@ return nil, fmt.Errorf("unsupported checkpoint type %q", r.Checkpoint.MediaType) } reader, err := l.store.ReaderAt(ctx, ocispec.Descriptor{ - MediaType: r.Checkpoint.MediaType, - Digest: r.Checkpoint.Digest, - Size: r.Checkpoint.Size_, + MediaType: r.Checkpoint.MediaType, + Digest: r.Checkpoint.Digest, + Size: r.Checkpoint.Size_, + Annotations: r.Checkpoint.Annotations, }) if err != nil { return nil, err @@ -149,10 +171,6 @@ return nil, err } } - container, err := l.getContainer(ctx, r.ContainerID) - if err != nil { - return nil, errdefs.ToGRPC(err) - } opts := runtime.CreateOpts{ Spec: container.Spec, IO: runtime.IO{ @@ -173,25 +191,32 @@ Options: m.Options, }) } - runtime, err := l.getRuntime(container.Runtime.Name) + if strings.HasPrefix(container.Runtime.Name, "io.containerd.runtime.v1.") { + log.G(ctx).Warn("runtime v1 is deprecated since containerd v1.4, consider using runtime v2") + } else if container.Runtime.Name == plugin.RuntimeRuncV1 { + log.G(ctx).Warnf("%q is deprecated since containerd v1.4, consider using %q", plugin.RuntimeRuncV1, plugin.RuntimeRuncV2) + } + rtime, err := l.getRuntime(container.Runtime.Name) if err != nil { return nil, err } - c, err := runtime.Create(ctx, r.ContainerID, opts) + _, err = rtime.Get(ctx, r.ContainerID) + if err != nil && err != runtime.ErrTaskNotExists { + return nil, errdefs.ToGRPC(err) + } + if err == nil { + return nil, errdefs.ToGRPC(fmt.Errorf("task %s already exists", r.ContainerID)) + } + c, err := rtime.Create(ctx, r.ContainerID, opts) if err != nil { return nil, errdefs.ToGRPC(err) } - // TODO: fast path for getting pid on create if err := l.monitor.Monitor(c); err != nil { return nil, errors.Wrap(err, "monitor task") } - state, err := c.State(ctx) - if err != nil { - log.G(ctx).Error(err) - } return &api.CreateTaskResponse{ ContainerID: r.ContainerID, - Pid: state.Pid, + Pid: c.PID(), }, nil } @@ -228,7 +253,7 @@ } exit, err := t.Delete(ctx) if err != nil { - return nil, err + return nil, errdefs.ToGRPC(err) } return &api.DeleteResponse{ ExitStatus: exit.Status, @@ -244,7 +269,7 @@ } process, err := t.Process(ctx, r.ExecID) if err != nil { - return nil, err + return nil, errdefs.ToGRPC(err) } exit, err := process.Delete(ctx) if err != nil { @@ -258,12 +283,18 @@ }, nil } -func processFromContainerd(ctx context.Context, p runtime.Process) (*task.Process, error) { +func getProcessState(ctx context.Context, p runtime.Process) (*task.Process, error) { + ctx, cancel := timeout.WithContext(ctx, stateTimeout) + defer cancel() + state, err := p.State(ctx) if err != nil { - return nil, err + if errdefs.IsNotFound(err) { + return nil, err + } + log.G(ctx).WithError(err).Errorf("get state for %s", p.ID()) } - var status task.Status + status := task.StatusUnknown switch state.Status { case runtime.CreatedStatus: status = task.StatusCreated @@ -302,7 +333,7 @@ return nil, errdefs.ToGRPC(err) } } - t, err := processFromContainerd(ctx, p) + t, err := getProcessState(ctx, p) if err != nil { return nil, errdefs.ToGRPC(err) } @@ -325,7 +356,7 @@ func addTasks(ctx context.Context, r *api.ListTasksResponse, tasks []runtime.Task) { for _, t := range tasks { - tt, err := processFromContainerd(ctx, t) + tt, err := getProcessState(ctx, t) if err != nil { if !errdefs.IsNotFound(err) { // handle race with deletion log.G(ctx).WithError(err).WithField("id", t.ID()).Error("converting task to protobuf") @@ -460,7 +491,7 @@ } if r.Stdin { if err := p.CloseIO(ctx); err != nil { - return nil, err + return nil, errdefs.ToGRPC(err) } } return empty, nil @@ -475,14 +506,27 @@ if err != nil { return nil, err } - image, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctd-checkpoint") + image, err := getCheckpointPath(container.Runtime.Name, r.Options) if err != nil { - return nil, errdefs.ToGRPC(err) + return nil, err + } + checkpointImageExists := false + if image == "" { + checkpointImageExists = true + image, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctd-checkpoint") + if err != nil { + return nil, errdefs.ToGRPC(err) + } + defer os.RemoveAll(image) } - defer os.RemoveAll(image) if err := t.Checkpoint(ctx, image, r.Options); err != nil { return nil, errdefs.ToGRPC(err) } + // do not commit checkpoint image if checkpoint ImagePath is passed, + // return if checkpointImageExists is false + if !checkpointImageExists { + return &api.CheckpointTaskResponse{}, nil + } // write checkpoint to the content store tar := archive.Diff(ctx, "", image) cp, err := l.writeContent(ctx, images.MediaTypeContainerd1Checkpoint, image, tar) @@ -516,7 +560,7 @@ if err != nil { return nil, err } - if err := t.Update(ctx, r.Resources); err != nil { + if err := t.Update(ctx, r.Resources, r.Annotations); err != nil { return nil, errdefs.ToGRPC(err) } return empty, nil @@ -605,20 +649,17 @@ return nil, err } return &types.Descriptor{ - MediaType: mediaType, - Digest: writer.Digest(), - Size_: size, + MediaType: mediaType, + Digest: writer.Digest(), + Size_: size, + Annotations: make(map[string]string), }, nil } func (l *local) getContainer(ctx context.Context, id string) (*containers.Container, error) { var container containers.Container - if err := l.db.View(func(tx *bolt.Tx) error { - store := metadata.NewContainerStore(tx) - var err error - container, err = store.Get(ctx, id) - return err - }); err != nil { + container, err := l.containers.Get(ctx, id) + if err != nil { return nil, errdefs.ToGRPC(err) } return &container, nil @@ -660,3 +701,87 @@ o = append(o, l.v2Runtime) return o } + +// getCheckpointPath only suitable for runc runtime now +func getCheckpointPath(runtime string, option *ptypes.Any) (string, error) { + if option == nil { + return "", nil + } + + var checkpointPath string + switch { + case checkRuntime(runtime, "io.containerd.runc"): + v, err := typeurl.UnmarshalAny(option) + if err != nil { + return "", err + } + opts, ok := v.(*options.CheckpointOptions) + if !ok { + return "", fmt.Errorf("invalid task checkpoint option for %s", runtime) + } + checkpointPath = opts.ImagePath + + case runtime == plugin.RuntimeLinuxV1: + v, err := typeurl.UnmarshalAny(option) + if err != nil { + return "", err + } + opts, ok := v.(*runctypes.CheckpointOptions) + if !ok { + return "", fmt.Errorf("invalid task checkpoint option for %s", runtime) + } + checkpointPath = opts.ImagePath + } + + return checkpointPath, nil +} + +// getRestorePath only suitable for runc runtime now +func getRestorePath(runtime string, option *ptypes.Any) (string, error) { + if option == nil { + return "", nil + } + + var restorePath string + switch { + case checkRuntime(runtime, "io.containerd.runc"): + v, err := typeurl.UnmarshalAny(option) + if err != nil { + return "", err + } + opts, ok := v.(*options.Options) + if !ok { + return "", fmt.Errorf("invalid task create option for %s", runtime) + } + restorePath = opts.CriuImagePath + case runtime == plugin.RuntimeLinuxV1: + v, err := typeurl.UnmarshalAny(option) + if err != nil { + return "", err + } + opts, ok := v.(*runctypes.CreateOptions) + if !ok { + return "", fmt.Errorf("invalid task create option for %s", runtime) + } + restorePath = opts.CriuImagePath + } + + return restorePath, nil +} + +// checkRuntime returns true if the current runtime matches the expected +// runtime. Providing various parts of the runtime schema will match those +// parts of the expected runtime +func checkRuntime(current, expected string) bool { + cp := strings.Split(current, ".") + l := len(cp) + for i, p := range strings.Split(expected, ".") { + if i > l { + return false + } + if p != cp[i] { + return false + } + } + return true +} diff -Nru containerd-1.2.6/services/tasks/local_unix.go containerd-1.5.9/services/tasks/local_unix.go --- containerd-1.2.6/services/tasks/local_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/tasks/local_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !windows_v2 +// +build !windows,!freebsd /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/services/tasks/local_windows.go containerd-1.5.9/services/tasks/local_windows.go --- containerd-1.2.6/services/tasks/local_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/services/tasks/local_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package tasks + +import ( + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/runtime" +) + +var tasksServiceRequires = []plugin.Type{ + plugin.RuntimePluginV2, + plugin.MetadataPlugin, + plugin.TaskMonitorPlugin, +} + +// loadV1Runtimes on Windows V2 returns an empty map. There are no v1 runtimes +func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { + return make(map[string]runtime.PlatformRuntime), nil +} diff -Nru containerd-1.2.6/services/tasks/local_windows_v2.go containerd-1.5.9/services/tasks/local_windows_v2.go --- containerd-1.2.6/services/tasks/local_windows_v2.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services/tasks/local_windows_v2.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -// +build windows,windows_v2 - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package tasks - -import ( - "github.com/containerd/containerd/plugin" - "github.com/containerd/containerd/runtime" -) - -var tasksServiceRequires = []plugin.Type{ - plugin.RuntimePluginV2, - plugin.MetadataPlugin, - plugin.TaskMonitorPlugin, -} - -// loadV1Runtimes on Windows V2 returns an empty map. There are no v1 runtimes -func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { - return make(map[string]runtime.PlatformRuntime), nil -} diff -Nru containerd-1.2.6/services.go containerd-1.5.9/services.go --- containerd-1.2.6/services.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/services.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ containersapi "github.com/containerd/containerd/api/services/containers/v1" "github.com/containerd/containerd/api/services/diff/v1" imagesapi "github.com/containerd/containerd/api/services/images/v1" + introspectionapi "github.com/containerd/containerd/api/services/introspection/v1" namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1" "github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/containers" @@ -27,19 +28,21 @@ "github.com/containerd/containerd/images" "github.com/containerd/containerd/leases" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/services/introspection" "github.com/containerd/containerd/snapshots" ) type services struct { - contentStore content.Store - imageStore images.Store - containerStore containers.Store - namespaceStore namespaces.Store - snapshotters map[string]snapshots.Snapshotter - taskService tasks.TasksClient - diffService DiffService - eventService EventService - leasesService leases.Manager + contentStore content.Store + imageStore images.Store + containerStore containers.Store + namespaceStore namespaces.Store + snapshotters map[string]snapshots.Snapshotter + taskService tasks.TasksClient + diffService DiffService + eventService EventService + leasesService leases.Manager + introspectionService introspection.Service } // ServicesOpt allows callers to set options on the services @@ -110,3 +113,10 @@ s.leasesService = leasesService } } + +// WithIntrospectionService sets the introspection service. +func WithIntrospectionService(in introspectionapi.IntrospectionClient) ServicesOpt { + return func(s *services) { + s.introspectionService = introspection.NewIntrospectionServiceFromClient(in) + } +} diff -Nru containerd-1.2.6/signal_map_linux.go containerd-1.5.9/signal_map_linux.go --- containerd-1.2.6/signal_map_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/signal_map_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -var signalMap = map[string]syscall.Signal{ - "ABRT": unix.SIGABRT, - "ALRM": unix.SIGALRM, - "BUS": unix.SIGBUS, - "CHLD": unix.SIGCHLD, - "CLD": unix.SIGCLD, - "CONT": unix.SIGCONT, - "FPE": unix.SIGFPE, - "HUP": unix.SIGHUP, - "ILL": unix.SIGILL, - "INT": unix.SIGINT, - "IO": unix.SIGIO, - "IOT": unix.SIGIOT, - "KILL": unix.SIGKILL, - "PIPE": unix.SIGPIPE, - "POLL": unix.SIGPOLL, - "PROF": unix.SIGPROF, - "PWR": unix.SIGPWR, - "QUIT": unix.SIGQUIT, - "SEGV": unix.SIGSEGV, - "STKFLT": unix.SIGSTKFLT, - "STOP": unix.SIGSTOP, - "SYS": unix.SIGSYS, - "TERM": unix.SIGTERM, - "TRAP": unix.SIGTRAP, - "TSTP": unix.SIGTSTP, - "TTIN": unix.SIGTTIN, - "TTOU": unix.SIGTTOU, - "URG": unix.SIGURG, - "USR1": unix.SIGUSR1, - "USR2": unix.SIGUSR2, - "VTALRM": unix.SIGVTALRM, - "WINCH": unix.SIGWINCH, - "XCPU": unix.SIGXCPU, - "XFSZ": unix.SIGXFSZ, -} diff -Nru containerd-1.2.6/signal_map_unix.go containerd-1.5.9/signal_map_unix.go --- containerd-1.2.6/signal_map_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/signal_map_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -// +build darwin freebsd solaris - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -var signalMap = map[string]syscall.Signal{ - "ABRT": unix.SIGABRT, - "ALRM": unix.SIGALRM, - "BUS": unix.SIGBUS, - "CHLD": unix.SIGCHLD, - "CONT": unix.SIGCONT, - "FPE": unix.SIGFPE, - "HUP": unix.SIGHUP, - "ILL": unix.SIGILL, - "INT": unix.SIGINT, - "IO": unix.SIGIO, - "IOT": unix.SIGIOT, - "KILL": unix.SIGKILL, - "PIPE": unix.SIGPIPE, - "PROF": unix.SIGPROF, - "QUIT": unix.SIGQUIT, - "SEGV": unix.SIGSEGV, - "STOP": unix.SIGSTOP, - "SYS": unix.SIGSYS, - "TERM": unix.SIGTERM, - "TRAP": unix.SIGTRAP, - "TSTP": unix.SIGTSTP, - "TTIN": unix.SIGTTIN, - "TTOU": unix.SIGTTOU, - "URG": unix.SIGURG, - "USR1": unix.SIGUSR1, - "USR2": unix.SIGUSR2, - "VTALRM": unix.SIGVTALRM, - "WINCH": unix.SIGWINCH, - "XCPU": unix.SIGXCPU, - "XFSZ": unix.SIGXFSZ, -} diff -Nru containerd-1.2.6/signal_map_windows.go containerd-1.5.9/signal_map_windows.go --- containerd-1.2.6/signal_map_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/signal_map_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "syscall" - - "golang.org/x/sys/windows" -) - -var signalMap = map[string]syscall.Signal{ - "HUP": syscall.Signal(windows.SIGHUP), - "INT": syscall.Signal(windows.SIGINT), - "QUIT": syscall.Signal(windows.SIGQUIT), - "SIGILL": syscall.Signal(windows.SIGILL), - "TRAP": syscall.Signal(windows.SIGTRAP), - "ABRT": syscall.Signal(windows.SIGABRT), - "BUS": syscall.Signal(windows.SIGBUS), - "FPE": syscall.Signal(windows.SIGFPE), - "KILL": syscall.Signal(windows.SIGKILL), - "SEGV": syscall.Signal(windows.SIGSEGV), - "PIPE": syscall.Signal(windows.SIGPIPE), - "ALRM": syscall.Signal(windows.SIGALRM), - "TERM": syscall.Signal(windows.SIGTERM), -} diff -Nru containerd-1.2.6/signals.go containerd-1.5.9/signals.go --- containerd-1.2.6/signals.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/signals.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,13 +20,11 @@ "context" "encoding/json" "fmt" - "strconv" - "strings" "syscall" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" ) // StopSignalLabel is a well-known containerd label for storing the stop @@ -83,23 +81,3 @@ return config.StopSignal, nil } - -// ParseSignal parses a given string into a syscall.Signal -// it checks that the signal exists in the platform-appropriate signalMap -func ParseSignal(rawSignal string) (syscall.Signal, error) { - s, err := strconv.Atoi(rawSignal) - if err == nil { - sig := syscall.Signal(s) - for _, msig := range signalMap { - if sig == msig { - return sig, nil - } - } - return -1, fmt.Errorf("unknown signal %q", rawSignal) - } - signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] - if !ok { - return -1, fmt.Errorf("unknown signal %q", rawSignal) - } - return signal, nil -} diff -Nru containerd-1.2.6/signals_unix.go containerd-1.5.9/signals_unix.go --- containerd-1.2.6/signals_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/signals_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,43 @@ +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "fmt" + "strconv" + "strings" + "syscall" + + "golang.org/x/sys/unix" +) + +// ParseSignal parses a given string into a syscall.Signal +// the rawSignal can be a string with "SIG" prefix, +// or a signal number in string format. +func ParseSignal(rawSignal string) (syscall.Signal, error) { + s, err := strconv.Atoi(rawSignal) + if err == nil { + return syscall.Signal(s), nil + } + signal := unix.SignalNum(strings.ToUpper(rawSignal)) + if signal == 0 { + return -1, fmt.Errorf("unknown signal %q", rawSignal) + } + return signal, nil +} diff -Nru containerd-1.2.6/signals_windows.go containerd-1.5.9/signals_windows.go --- containerd-1.2.6/signals_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/signals_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,63 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "fmt" + "strconv" + "strings" + "syscall" + + "golang.org/x/sys/windows" +) + +var signalMap = map[string]syscall.Signal{ + "HUP": syscall.Signal(windows.SIGHUP), + "INT": syscall.Signal(windows.SIGINT), + "QUIT": syscall.Signal(windows.SIGQUIT), + "SIGILL": syscall.Signal(windows.SIGILL), + "TRAP": syscall.Signal(windows.SIGTRAP), + "ABRT": syscall.Signal(windows.SIGABRT), + "BUS": syscall.Signal(windows.SIGBUS), + "FPE": syscall.Signal(windows.SIGFPE), + "KILL": syscall.Signal(windows.SIGKILL), + "SEGV": syscall.Signal(windows.SIGSEGV), + "PIPE": syscall.Signal(windows.SIGPIPE), + "ALRM": syscall.Signal(windows.SIGALRM), + "TERM": syscall.Signal(windows.SIGTERM), +} + +// ParseSignal parses a given string into a syscall.Signal +// the rawSignal can be a string with "SIG" prefix, +// or a signal number in string format. +func ParseSignal(rawSignal string) (syscall.Signal, error) { + s, err := strconv.Atoi(rawSignal) + if err == nil { + sig := syscall.Signal(s) + for _, msig := range signalMap { + if sig == msig { + return sig, nil + } + } + return -1, fmt.Errorf("unknown signal %q", rawSignal) + } + signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] + if !ok { + return -1, fmt.Errorf("unknown signal %q", rawSignal) + } + return signal, nil +} diff -Nru containerd-1.2.6/snapshots/benchsuite/benchmark.go containerd-1.5.9/snapshots/benchsuite/benchmark.go --- containerd-1.2.6/snapshots/benchsuite/benchmark.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/benchsuite/benchmark.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,19 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package benchsuite diff -Nru containerd-1.2.6/snapshots/benchsuite/benchmark_test.go containerd-1.5.9/snapshots/benchsuite/benchmark_test.go --- containerd-1.2.6/snapshots/benchsuite/benchmark_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/benchsuite/benchmark_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,312 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package benchsuite + +import ( + "context" + "crypto/rand" + "flag" + "fmt" + "os" + "path/filepath" + "sync/atomic" + "testing" + "time" + + "github.com/containerd/continuity/fs/fstest" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "gotest.tools/v3/assert" + + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/snapshots/devmapper" + "github.com/containerd/containerd/snapshots/native" + "github.com/containerd/containerd/snapshots/overlay" +) + +var ( + dmPoolDev string + dmRootPath string + overlayRootPath string + nativeRootPath string +) + +func init() { + flag.StringVar(&dmPoolDev, "dm.thinPoolDev", "", "Pool device to run benchmark on") + flag.StringVar(&dmRootPath, "dm.rootPath", "", "Root dir for devmapper snapshotter") + flag.StringVar(&overlayRootPath, "overlay.rootPath", "", "Root dir for overlay snapshotter") + flag.StringVar(&nativeRootPath, "native.rootPath", "", "Root dir for native snapshotter") + + // Avoid mixing benchmark output and INFO messages + logrus.SetLevel(logrus.ErrorLevel) +} + +func BenchmarkNative(b *testing.B) { + if nativeRootPath == "" { + b.Skip("native root dir must be provided") + } + + snapshotter, err := native.NewSnapshotter(nativeRootPath) + assert.NilError(b, err) + + defer func() { + err = snapshotter.Close() + assert.NilError(b, err) + + err = os.RemoveAll(nativeRootPath) + assert.NilError(b, err) + }() + + benchmarkSnapshotter(b, snapshotter) +} + +func BenchmarkOverlay(b *testing.B) { + if overlayRootPath == "" { + b.Skip("overlay root dir must be provided") + } + + snapshotter, err := overlay.NewSnapshotter(overlayRootPath) + assert.NilError(b, err, "failed to create overlay snapshotter") + + defer func() { + err = snapshotter.Close() + assert.NilError(b, err) + + err = os.RemoveAll(overlayRootPath) + assert.NilError(b, err) + }() + + benchmarkSnapshotter(b, snapshotter) +} + +func BenchmarkDeviceMapper(b *testing.B) { + if dmPoolDev == "" { + b.Skip("devmapper benchmark requires thin-pool device to be prepared in advance and provided") + } + + if dmRootPath == "" { + b.Skip("devmapper snapshotter root dir must be provided") + } + + config := &devmapper.Config{ + PoolName: dmPoolDev, + RootPath: dmRootPath, + BaseImageSize: "16Mb", + } + + ctx := context.Background() + + snapshotter, err := devmapper.NewSnapshotter(ctx, config) + assert.NilError(b, err) + + defer func() { + err := snapshotter.ResetPool(ctx) + assert.NilError(b, err) + + err = snapshotter.Close() + assert.NilError(b, err) + + err = os.RemoveAll(dmRootPath) + assert.NilError(b, err) + }() + + benchmarkSnapshotter(b, snapshotter) +} + +// benchmarkSnapshotter tests snapshotter performance. +// It writes 16 layers with randomly created, modified, or removed files. +// Depending on layer index different sets of files are modified. +// In addition to total snapshotter execution time, benchmark outputs a few additional +// details - time taken to Prepare layer, mount, write data and unmount time, +// and Commit snapshot time. +func benchmarkSnapshotter(b *testing.B, snapshotter snapshots.Snapshotter) { + const ( + layerCount = 16 + fileSizeBytes = int64(1 * 1024 * 1024) // 1 MB + ) + + var ( + total = 0 + layers = make([]fstest.Applier, 0, layerCount) + layerIndex = int64(0) + ) + + for i := 1; i <= layerCount; i++ { + appliers := makeApplier(i, fileSizeBytes) + layers = append(layers, fstest.Apply(appliers...)) + total += len(appliers) + } + + var ( + benchN int + prepareDuration time.Duration + writeDuration time.Duration + commitDuration time.Duration + ) + + // Wrap test with Run so additional details output will be added right below the benchmark result + b.Run("run", func(b *testing.B) { + var ( + ctx = context.Background() + parent string + current string + ) + + // Reset durations since test might be ran multiple times + prepareDuration = 0 + writeDuration = 0 + commitDuration = 0 + benchN = b.N + + b.SetBytes(int64(total) * fileSizeBytes) + + var timer time.Time + for i := 0; i < b.N; i++ { + for l := 0; l < layerCount; l++ { + current = fmt.Sprintf("prepare-layer-%d", atomic.AddInt64(&layerIndex, 1)) + + timer = time.Now() + mounts, err := snapshotter.Prepare(ctx, current, parent) + assert.NilError(b, err) + prepareDuration += time.Since(timer) + + timer = time.Now() + err = mount.WithTempMount(ctx, mounts, layers[l].Apply) + assert.NilError(b, err) + writeDuration += time.Since(timer) + + parent = fmt.Sprintf("committed-%d", atomic.AddInt64(&layerIndex, 1)) + + timer = time.Now() + err = snapshotter.Commit(ctx, parent, current) + assert.NilError(b, err) + commitDuration += time.Since(timer) + } + } + }) + + // Output extra measurements - total time taken to Prepare, mount and write data, and Commit + const outputFormat = "%-25s\t%s\n" + fmt.Fprintf(os.Stdout, + outputFormat, + b.Name()+"/prepare", + testing.BenchmarkResult{N: benchN, T: prepareDuration}) + + fmt.Fprintf(os.Stdout, + outputFormat, + b.Name()+"/write", + testing.BenchmarkResult{N: benchN, T: writeDuration}) + + fmt.Fprintf(os.Stdout, + outputFormat, + b.Name()+"/commit", + testing.BenchmarkResult{N: benchN, T: commitDuration}) + + fmt.Fprintln(os.Stdout) +} + +// makeApplier returns a slice of fstest.Applier where files are written randomly. +// Depending on layer index, the returned layers will overwrite some files with the +// same generated names with new contents or deletions. +func makeApplier(layerIndex int, fileSizeBytes int64) []fstest.Applier { + seed := time.Now().UnixNano() + + switch { + case layerIndex%3 == 0: + return []fstest.Applier{ + updateFile("/a"), + updateFile("/b"), + fstest.CreateRandomFile("/c", seed, fileSizeBytes, 0777), + updateFile("/d"), + fstest.CreateRandomFile("/f", seed, fileSizeBytes, 0777), + updateFile("/e"), + fstest.RemoveAll("/g"), + fstest.CreateRandomFile("/h", seed, fileSizeBytes, 0777), + updateFile("/i"), + fstest.CreateRandomFile("/j", seed, fileSizeBytes, 0777), + } + case layerIndex%2 == 0: + return []fstest.Applier{ + updateFile("/a"), + fstest.CreateRandomFile("/b", seed, fileSizeBytes, 0777), + fstest.RemoveAll("/c"), + fstest.CreateRandomFile("/d", seed, fileSizeBytes, 0777), + updateFile("/e"), + fstest.RemoveAll("/f"), + fstest.CreateRandomFile("/g", seed, fileSizeBytes, 0777), + updateFile("/h"), + fstest.CreateRandomFile("/i", seed, fileSizeBytes, 0777), + updateFile("/j"), + } + default: + return []fstest.Applier{ + fstest.CreateRandomFile("/a", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/b", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/c", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/d", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/e", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/f", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/g", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/h", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/i", seed, fileSizeBytes, 0777), + fstest.CreateRandomFile("/j", seed, fileSizeBytes, 0777), + } + } +} + +// applierFn represents helper func that implements fstest.Applier +type applierFn func(root string) error + +func (fn applierFn) Apply(root string) error { + return fn(root) +} + +// updateFile modifies a few bytes in the middle in order to demonstrate the difference in performance +// for block-based snapshotters (like devicemapper) against file-based snapshotters (like overlay, which need to +// perform a copy-up of the full file any time a single bit is modified). +func updateFile(name string) applierFn { + return func(root string) error { + path := filepath.Join(root, name) + file, err := os.OpenFile(path, os.O_WRONLY, 0600) + if err != nil { + return errors.Wrapf(err, "failed to open %q", path) + } + + info, err := file.Stat() + if err != nil { + return err + } + + var ( + offset = info.Size() / 2 + buf = make([]byte, 4) + ) + + if _, err := rand.Read(buf); err != nil { + return err + } + + if _, err := file.WriteAt(buf, offset); err != nil { + return errors.Wrapf(err, "failed to write %q at offset %d", path, offset) + } + + return file.Close() + } +} diff -Nru containerd-1.2.6/snapshots/btrfs/btrfs.go containerd-1.5.9/snapshots/btrfs/btrfs.go --- containerd-1.2.6/snapshots/btrfs/btrfs.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/btrfs/btrfs.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build linux,!no_btrfs +// +build linux,!no_btrfs,cgo /* Copyright The containerd Authors. @@ -26,31 +26,18 @@ "strings" "github.com/containerd/btrfs" + "github.com/containerd/continuity/fs" + "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" - "github.com/containerd/continuity/fs" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -func init() { - plugin.Register(&plugin.Registration{ - ID: "btrfs", - Type: plugin.SnapshotPlugin, - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = []ocispec.Platform{platforms.DefaultSpec()} - ic.Meta.Exports = map[string]string{"root": ic.Root} - return NewSnapshotter(ic.Root) - }, - }) -} - type snapshotter struct { device string // device of the root root string // root provides paths for internal storage. @@ -63,11 +50,15 @@ // root needs to be a mount point of btrfs. func NewSnapshotter(root string) (snapshots.Snapshotter, error) { // If directory does not exist, create it - if _, err := os.Stat(root); err != nil { + if st, err := os.Stat(root); err != nil { if !os.IsNotExist(err) { return nil, err } - if err := os.Mkdir(root, 0755); err != nil { + if err := os.Mkdir(root, 0700); err != nil { + return nil, err + } + } else if st.Mode()&os.ModePerm != 0700 { + if err := os.Chmod(root, 0700); err != nil { return nil, err } } @@ -77,7 +68,7 @@ return nil, err } if mnt.FSType != "btrfs" { - return nil, fmt.Errorf("path %s must be a btrfs filesystem to be used with the btrfs snapshotter", root) + return nil, errors.Wrapf(plugin.ErrSkipPlugin, "path %s (%s) must be a btrfs filesystem to be used with the btrfs snapshotter", root, mnt.FSType) } var ( active = filepath.Join(root, "active") @@ -186,13 +177,13 @@ } // Walk the committed snapshots. -func (b *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (b *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := b.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, fs...) } func (b *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { diff -Nru containerd-1.2.6/snapshots/btrfs/btrfs_test.go containerd-1.5.9/snapshots/btrfs/btrfs_test.go --- containerd-1.2.6/snapshots/btrfs/btrfs_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/btrfs/btrfs_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build linux,!no_btrfs +// +build linux,!no_btrfs,cgo /* Copyright The containerd Authors. @@ -26,9 +26,11 @@ "path/filepath" "strings" "testing" + "time" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/testsuite" "github.com/containerd/continuity/testutil/loopback" @@ -52,25 +54,44 @@ if os.Getpagesize() > 4096 { loopbackSize = int64(650 << 20) // 650 MB } - deviceName, cleanupDevice, err := loopback.New(loopbackSize) + loop, err := loopback.New(loopbackSize) if err != nil { return nil, nil, err } - if out, err := exec.Command(mkbtrfs, deviceName).CombinedOutput(); err != nil { - cleanupDevice() + if out, err := exec.Command(mkbtrfs, loop.Device).CombinedOutput(); err != nil { + loop.Close() return nil, nil, errors.Wrapf(err, "failed to make btrfs filesystem (out: %q)", out) } - if out, err := exec.Command("mount", deviceName, root).CombinedOutput(); err != nil { - cleanupDevice() - return nil, nil, errors.Wrapf(err, "failed to mount device %s (out: %q)", deviceName, out) - } + // sync after a mkfs on the loopback before trying to mount the device + unix.Sync() - snapshotter, err := NewSnapshotter(root) - if err != nil { - cleanupDevice() - return nil, nil, errors.Wrap(err, "failed to create new snapshotter") + var snapshotter snapshots.Snapshotter + for i := 0; i < 5; i++ { + if out, err := exec.Command("mount", loop.Device, root).CombinedOutput(); err != nil { + loop.Close() + return nil, nil, errors.Wrapf(err, "failed to mount device %s (out: %q)", loop.Device, out) + } + + if i > 0 { + time.Sleep(10 * time.Duration(i) * time.Millisecond) + } + + snapshotter, err = NewSnapshotter(root) + if err == nil { + break + } else if !errors.Is(err, plugin.ErrSkipPlugin) { + return nil, nil, err + } + + t.Logf("Attempt %d to create btrfs snapshotter failed: %#v", i+1, err) + + // unmount and try again + unix.Unmount(root, 0) + } + if snapshotter == nil { + return nil, nil, errors.Wrap(err, "failed to successfully create snapshotter after 5 attempts") } return snapshotter, func() error { @@ -78,7 +99,7 @@ return err } err := mount.UnmountAll(root, unix.MNT_DETACH) - if cerr := cleanupDevice(); cerr != nil { + if cerr := loop.Close(); cerr != nil { err = errors.Wrap(cerr, "device cleanup failed") } return err diff -Nru containerd-1.2.6/snapshots/btrfs/plugin/plugin.go containerd-1.5.9/snapshots/btrfs/plugin/plugin.go --- containerd-1.2.6/snapshots/btrfs/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/btrfs/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,59 @@ +// +build linux,!no_btrfs,cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package plugin + +import ( + "errors" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/snapshots/btrfs" +) + +// Config represents configuration for the btrfs plugin. +type Config struct { + // Root directory for the plugin + RootPath string `toml:"root_path"` +} + +func init() { + plugin.Register(&plugin.Registration{ + ID: "btrfs", + Type: plugin.SnapshotPlugin, + Config: &Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = []ocispec.Platform{platforms.DefaultSpec()} + + config, ok := ic.Config.(*Config) + if !ok { + return nil, errors.New("invalid btrfs configuration") + } + + root := ic.Root + if len(config.RootPath) != 0 { + root = config.RootPath + } + + ic.Meta.Exports = map[string]string{"root": root} + return btrfs.NewSnapshotter(root) + }, + }) +} diff -Nru containerd-1.2.6/snapshots/devmapper/config.go containerd-1.5.9/snapshots/devmapper/config.go --- containerd-1.2.6/snapshots/devmapper/config.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,106 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "fmt" + "os" + + "github.com/docker/go-units" + "github.com/hashicorp/go-multierror" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" +) + +// Config represents device mapper configuration loaded from file. +// Size units can be specified in human-readable string format (like "32KIB", "32GB", "32Tb") +type Config struct { + // Device snapshotter root directory for metadata + RootPath string `toml:"root_path"` + + // Name for 'thin-pool' device to be used by snapshotter (without /dev/mapper/ prefix) + PoolName string `toml:"pool_name"` + + // Defines how much space to allocate when creating base image for container + BaseImageSize string `toml:"base_image_size"` + BaseImageSizeBytes uint64 `toml:"-"` + + // Flag to async remove device using Cleanup() callback in snapshots GC + AsyncRemove bool `toml:"async_remove"` +} + +// LoadConfig reads devmapper configuration file from disk in TOML format +func LoadConfig(path string) (*Config, error) { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return nil, os.ErrNotExist + } + + return nil, err + } + + config := Config{} + file, err := toml.LoadFile(path) + if err != nil { + return nil, errors.Wrapf(err, "failed to open devmapepr TOML: %s", path) + } + + if err := file.Unmarshal(&config); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal devmapper TOML") + } + + if err := config.parse(); err != nil { + return nil, err + } + + if err := config.Validate(); err != nil { + return nil, err + } + + return &config, nil +} + +func (c *Config) parse() error { + baseImageSize, err := units.RAMInBytes(c.BaseImageSize) + if err != nil { + return errors.Wrapf(err, "failed to parse base image size: '%s'", c.BaseImageSize) + } + + c.BaseImageSizeBytes = uint64(baseImageSize) + return nil +} + +// Validate makes sure configuration fields are valid +func (c *Config) Validate() error { + var result *multierror.Error + + if c.PoolName == "" { + result = multierror.Append(result, fmt.Errorf("pool_name is required")) + } + + if c.RootPath == "" { + result = multierror.Append(result, fmt.Errorf("root_path is required")) + } + + if c.BaseImageSize == "" { + result = multierror.Append(result, fmt.Errorf("base_image_size is required")) + } + + return result.ErrorOrNil() +} diff -Nru containerd-1.2.6/snapshots/devmapper/config_test.go containerd-1.5.9/snapshots/devmapper/config_test.go --- containerd-1.2.6/snapshots/devmapper/config_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/config_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,103 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/hashicorp/go-multierror" + "github.com/pelletier/go-toml" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestLoadConfig(t *testing.T) { + expected := Config{ + RootPath: "/tmp", + PoolName: "test", + BaseImageSize: "128Mb", + } + + file, err := ioutil.TempFile("", "devmapper-config-") + assert.NilError(t, err) + + encoder := toml.NewEncoder(file) + err = encoder.Encode(&expected) + assert.NilError(t, err) + + defer func() { + err := file.Close() + assert.NilError(t, err) + + err = os.Remove(file.Name()) + assert.NilError(t, err) + }() + + loaded, err := LoadConfig(file.Name()) + assert.NilError(t, err) + + assert.Equal(t, loaded.RootPath, expected.RootPath) + assert.Equal(t, loaded.PoolName, expected.PoolName) + assert.Equal(t, loaded.BaseImageSize, expected.BaseImageSize) + + assert.Assert(t, loaded.BaseImageSizeBytes == 128*1024*1024) +} + +func TestLoadConfigInvalidPath(t *testing.T) { + _, err := LoadConfig("") + assert.Equal(t, os.ErrNotExist, err) + + _, err = LoadConfig("/dev/null") + assert.Assert(t, err != nil) +} + +func TestParseInvalidData(t *testing.T) { + config := Config{ + BaseImageSize: "y", + } + + err := config.parse() + assert.Error(t, err, "failed to parse base image size: 'y': invalid size: 'y'") +} + +func TestFieldValidation(t *testing.T) { + config := &Config{} + err := config.Validate() + assert.Assert(t, err != nil) + + multErr := (err).(*multierror.Error) + assert.Assert(t, is.Len(multErr.Errors, 3)) + + assert.Assert(t, multErr.Errors[0] != nil, "pool_name is empty") + assert.Assert(t, multErr.Errors[1] != nil, "root_path is empty") + assert.Assert(t, multErr.Errors[2] != nil, "base_image_size is empty") +} + +func TestExistingPoolFieldValidation(t *testing.T) { + config := &Config{ + PoolName: "test", + RootPath: "test", + BaseImageSize: "10mb", + } + + err := config.Validate() + assert.NilError(t, err) +} diff -Nru containerd-1.2.6/snapshots/devmapper/device_info.go containerd-1.5.9/snapshots/devmapper/device_info.go --- containerd-1.2.6/snapshots/devmapper/device_info.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/device_info.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,110 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "fmt" +) + +const ( + maxDeviceID = 0xffffff // Device IDs are 24-bit numbers +) + +// DeviceState represents current devmapper device state reflected in meta store +type DeviceState int + +const ( + // Unknown means that device just allocated and no operations were performed + Unknown DeviceState = iota + // Creating means that device is going to be created + Creating + // Created means that devices successfully created + Created + // Activating means that device is going to be activated + Activating + // Activated means that device successfully activated + Activated + // Suspending means that device is going to be suspended + Suspending + // Suspended means that device successfully suspended + Suspended + // Resuming means that device is going to be resumed from suspended state + Resuming + // Resumed means that device successfully resumed + Resumed + // Deactivating means that device is going to be deactivated + Deactivating + // Deactivated means that device successfully deactivated + Deactivated + // Removing means that device is going to be removed + Removing + // Removed means that device successfully removed but not yet deleted from meta store + Removed + // Faulty means that the device is errored and the snapshotter failed to rollback it + Faulty +) + +func (s DeviceState) String() string { + switch s { + case Creating: + return "Creating" + case Created: + return "Created" + case Activating: + return "Activating" + case Activated: + return "Activated" + case Suspending: + return "Suspending" + case Suspended: + return "Suspended" + case Resuming: + return "Resuming" + case Resumed: + return "Resumed" + case Deactivating: + return "Deactivating" + case Deactivated: + return "Deactivated" + case Removing: + return "Removing" + case Removed: + return "Removed" + case Faulty: + return "Faulty" + default: + return fmt.Sprintf("unknown %d", s) + } +} + +// DeviceInfo represents metadata for thin device within thin-pool +type DeviceInfo struct { + // DeviceID is a 24-bit number assigned to a device within thin-pool device + DeviceID uint32 `json:"device_id"` + // Size is a thin device size + Size uint64 `json:"size"` + // Name is a device name to be used in /dev/mapper/ + Name string `json:"name"` + // ParentName is a name of parent device (if snapshot) + ParentName string `json:"parent_name"` + // State represents current device state + State DeviceState `json:"state"` + // Error details if device state change failed + Error string `json:"error"` +} diff -Nru containerd-1.2.6/snapshots/devmapper/dmsetup/dmsetup.go containerd-1.5.9/snapshots/devmapper/dmsetup/dmsetup.go --- containerd-1.2.6/snapshots/devmapper/dmsetup/dmsetup.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/dmsetup/dmsetup.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,408 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package dmsetup + +import ( + "fmt" + "io" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const ( + // DevMapperDir represents devmapper devices location + DevMapperDir = "/dev/mapper/" + // SectorSize represents the number of bytes in one sector on devmapper devices + SectorSize = 512 +) + +// DeviceInfo represents device info returned by "dmsetup info". +// dmsetup(8) provides more information on each of these fields. +type DeviceInfo struct { + Name string + BlockDeviceName string + TableLive bool + TableInactive bool + Suspended bool + ReadOnly bool + Major uint32 + Minor uint32 + OpenCount uint32 // Open reference count + TargetCount uint32 // Number of targets in the live table + EventNumber uint32 // Last event sequence number (used by wait) +} + +var errTable map[string]unix.Errno + +func init() { + // Precompute map of = for optimal lookup + errTable = make(map[string]unix.Errno) + for errno := unix.EPERM; errno <= unix.EHWPOISON; errno++ { + errTable[errno.Error()] = errno + } +} + +// CreatePool creates a device with the given name, data and metadata file and block size (see "dmsetup create") +func CreatePool(poolName, dataFile, metaFile string, blockSizeSectors uint32) error { + thinPool, err := makeThinPoolMapping(dataFile, metaFile, blockSizeSectors) + if err != nil { + return err + } + + _, err = dmsetup("create", poolName, "--table", thinPool) + return err +} + +// ReloadPool reloads existing thin-pool (see "dmsetup reload") +func ReloadPool(deviceName, dataFile, metaFile string, blockSizeSectors uint32) error { + thinPool, err := makeThinPoolMapping(dataFile, metaFile, blockSizeSectors) + if err != nil { + return err + } + + _, err = dmsetup("reload", deviceName, "--table", thinPool) + return err +} + +const ( + lowWaterMark = 32768 // Picked arbitrary, might need tuning + skipZeroing = "skip_block_zeroing" // Skipping zeroing to reduce latency for device creation +) + +// makeThinPoolMapping makes thin-pool table entry +func makeThinPoolMapping(dataFile, metaFile string, blockSizeSectors uint32) (string, error) { + dataDeviceSizeBytes, err := BlockDeviceSize(dataFile) + if err != nil { + return "", errors.Wrapf(err, "failed to get block device size: %s", dataFile) + } + + // Thin-pool mapping target has the following format: + // start - starting block in virtual device + // length - length of this segment + // metadata_dev - the metadata device + // data_dev - the data device + // data_block_size - the data block size in sectors + // low_water_mark - the low water mark, expressed in blocks of size data_block_size + // feature_args - the number of feature arguments + // args + lengthSectors := dataDeviceSizeBytes / SectorSize + target := fmt.Sprintf("0 %d thin-pool %s %s %d %d 1 %s", + lengthSectors, + metaFile, + dataFile, + blockSizeSectors, + lowWaterMark, + skipZeroing) + + return target, nil +} + +// CreateDevice sends "create_thin " message to the given thin-pool +func CreateDevice(poolName string, deviceID uint32) error { + _, err := dmsetup("message", poolName, "0", fmt.Sprintf("create_thin %d", deviceID)) + return err +} + +// ActivateDevice activates the given thin-device using the 'thin' target +func ActivateDevice(poolName string, deviceName string, deviceID uint32, size uint64, external string) error { + mapping := makeThinMapping(poolName, deviceID, size, external) + _, err := dmsetup("create", deviceName, "--table", mapping) + return err +} + +// makeThinMapping makes thin target table entry +func makeThinMapping(poolName string, deviceID uint32, sizeBytes uint64, externalOriginDevice string) string { + lengthSectors := sizeBytes / SectorSize + + // Thin target has the following format: + // start - starting block in virtual device + // length - length of this segment + // pool_dev - the thin-pool device, can be /dev/mapper/pool_name or 253:0 + // dev_id - the internal device id of the device to be activated + // external_origin_dev - an optional block device outside the pool to be treated as a read-only snapshot origin. + target := fmt.Sprintf("0 %d thin %s %d %s", lengthSectors, GetFullDevicePath(poolName), deviceID, externalOriginDevice) + return strings.TrimSpace(target) +} + +// SuspendDevice suspends the given device (see "dmsetup suspend") +func SuspendDevice(deviceName string) error { + _, err := dmsetup("suspend", deviceName) + return err +} + +// ResumeDevice resumes the given device (see "dmsetup resume") +func ResumeDevice(deviceName string) error { + _, err := dmsetup("resume", deviceName) + return err +} + +// Table returns the current table for the device +func Table(deviceName string) (string, error) { + return dmsetup("table", deviceName) +} + +// CreateSnapshot sends "create_snap" message to the given thin-pool. +// Caller needs to suspend and resume device if it is active. +func CreateSnapshot(poolName string, deviceID uint32, baseDeviceID uint32) error { + _, err := dmsetup("message", poolName, "0", fmt.Sprintf("create_snap %d %d", deviceID, baseDeviceID)) + return err +} + +// DeleteDevice sends "delete " message to the given thin-pool +func DeleteDevice(poolName string, deviceID uint32) error { + _, err := dmsetup("message", poolName, "0", fmt.Sprintf("delete %d", deviceID)) + return err +} + +// RemoveDeviceOpt represents command line arguments for "dmsetup remove" command +type RemoveDeviceOpt string + +const ( + // RemoveWithForce flag replaces the table with one that fails all I/O if + // open device can't be removed + RemoveWithForce RemoveDeviceOpt = "--force" + // RemoveWithRetries option will cause the operation to be retried + // for a few seconds before failing + RemoveWithRetries RemoveDeviceOpt = "--retry" + // RemoveDeferred flag will enable deferred removal of open devices, + // the device will be removed when the last user closes it + RemoveDeferred RemoveDeviceOpt = "--deferred" +) + +// RemoveDevice removes a device (see "dmsetup remove") +func RemoveDevice(deviceName string, opts ...RemoveDeviceOpt) error { + args := []string{ + "remove", + } + + for _, opt := range opts { + args = append(args, string(opt)) + } + + args = append(args, GetFullDevicePath(deviceName)) + + _, err := dmsetup(args...) + if err == unix.ENXIO { + // Ignore "No such device or address" error because we dmsetup + // remove with "deferred" option, there is chance for the device + // having been removed. + return nil + } + + return err +} + +// Info outputs device information (see "dmsetup info"). +// If device name is empty, all device infos will be returned. +func Info(deviceName string) ([]*DeviceInfo, error) { + output, err := dmsetup( + "info", + "--columns", + "--noheadings", + "-o", + "name,blkdevname,attr,major,minor,open,segments,events", + "--separator", + " ", + deviceName) + + if err != nil { + return nil, err + } + + var ( + lines = strings.Split(output, "\n") + devices = make([]*DeviceInfo, len(lines)) + ) + + for i, line := range lines { + var ( + attr = "" + info = &DeviceInfo{} + ) + + _, err := fmt.Sscan(line, + &info.Name, + &info.BlockDeviceName, + &attr, + &info.Major, + &info.Minor, + &info.OpenCount, + &info.TargetCount, + &info.EventNumber) + + if err != nil { + return nil, errors.Wrapf(err, "failed to parse line %q", line) + } + + // Parse attributes (see "man 8 dmsetup" for details) + info.Suspended = strings.Contains(attr, "s") + info.ReadOnly = strings.Contains(attr, "r") + info.TableLive = strings.Contains(attr, "L") + info.TableInactive = strings.Contains(attr, "I") + + devices[i] = info + } + + return devices, nil +} + +// Version returns "dmsetup version" output +func Version() (string, error) { + return dmsetup("version") +} + +// DeviceStatus represents devmapper device status information +type DeviceStatus struct { + RawOutput string + Offset int64 + Length int64 + Target string + Params []string +} + +// Status provides status information for devmapper device +func Status(deviceName string) (*DeviceStatus, error) { + var ( + err error + status DeviceStatus + ) + + output, err := dmsetup("status", deviceName) + if err != nil { + return nil, err + } + status.RawOutput = output + + // Status output format: + // Offset (int64) + // Length (int64) + // Target type (string) + // Params (Array of strings) + const MinParseCount = 4 + parts := strings.Split(output, " ") + if len(parts) < MinParseCount { + return nil, errors.Errorf("failed to parse output: %q", output) + } + + status.Offset, err = strconv.ParseInt(parts[0], 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse offset: %q", parts[0]) + } + + status.Length, err = strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse length: %q", parts[1]) + } + + status.Target = parts[2] + status.Params = parts[3:] + + return &status, nil +} + +// GetFullDevicePath returns full path for the given device name (like "/dev/mapper/name") +func GetFullDevicePath(deviceName string) string { + if strings.HasPrefix(deviceName, DevMapperDir) { + return deviceName + } + + return DevMapperDir + deviceName +} + +// BlockDeviceSize returns size of block device in bytes +func BlockDeviceSize(path string) (int64, error) { + f, err := os.Open(path) + if err != nil { + return 0, err + } + defer f.Close() + + size, err := f.Seek(0, io.SeekEnd) + if err != nil { + return 0, errors.Wrapf(err, "failed to seek on %q", path) + } + return size, nil +} + +func dmsetup(args ...string) (string, error) { + data, err := exec.Command("dmsetup", args...).CombinedOutput() + output := string(data) + if err != nil { + // Try find Linux error code otherwise return generic error with dmsetup output + if errno, ok := tryGetUnixError(output); ok { + return "", errno + } + + return "", errors.Wrapf(err, "dmsetup %s\nerror: %s\n", strings.Join(args, " "), output) + } + + output = strings.TrimSuffix(output, "\n") + output = strings.TrimSpace(output) + + return output, nil +} + +// tryGetUnixError tries to find Linux error code from dmsetup output +func tryGetUnixError(output string) (unix.Errno, bool) { + // It's useful to have Linux error codes like EBUSY, EPERM, ..., instead of just text. + // Unfortunately there is no better way than extracting/comparing error text. + text := parseDmsetupError(output) + if text == "" { + return 0, false + } + + err, ok := errTable[text] + return err, ok +} + +// dmsetup returns error messages in format: +// device-mapper: message ioctl on failed: File exists\n +// Command failed\n +// parseDmsetupError extracts text between "failed: " and "\n" +func parseDmsetupError(output string) string { + lines := strings.SplitN(output, "\n", 2) + if len(lines) < 2 { + return "" + } + + line := lines[0] + // Handle output like "Device /dev/mapper/snapshotter-suite-pool-snap-1 not found" + if strings.HasSuffix(line, "not found") { + return unix.ENXIO.Error() + } + + const failedSubstr = "failed: " + idx := strings.LastIndex(line, failedSubstr) + if idx == -1 { + return "" + } + + str := line[idx:] + + // Strip "failed: " prefix + str = strings.TrimPrefix(str, failedSubstr) + + str = strings.ToLower(str) + return str +} diff -Nru containerd-1.2.6/snapshots/devmapper/dmsetup/dmsetup_test.go containerd-1.5.9/snapshots/devmapper/dmsetup/dmsetup_test.go --- containerd-1.2.6/snapshots/devmapper/dmsetup/dmsetup_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/dmsetup/dmsetup_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,205 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package dmsetup + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + "github.com/docker/go-units" + "golang.org/x/sys/unix" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" + + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/testutil" +) + +const ( + testPoolName = "test-pool" + testDeviceName = "test-device" + deviceID = 1 + snapshotID = 2 +) + +func TestDMSetup(t *testing.T) { + testutil.RequiresRoot(t) + + tempDir, err := ioutil.TempDir("", "dmsetup-tests-") + assert.NilError(t, err, "failed to make temp dir for tests") + + defer func() { + err := os.RemoveAll(tempDir) + assert.NilError(t, err) + }() + + dataImage, loopDataDevice := createLoopbackDevice(t, tempDir) + metaImage, loopMetaDevice := createLoopbackDevice(t, tempDir) + + defer func() { + err = mount.DetachLoopDevice(loopDataDevice, loopMetaDevice) + assert.NilError(t, err, "failed to detach loop devices for data image: %s and meta image: %s", dataImage, metaImage) + }() + + t.Run("CreatePool", func(t *testing.T) { + err := CreatePool(testPoolName, loopDataDevice, loopMetaDevice, 128) + assert.NilError(t, err, "failed to create thin-pool with %s %s", loopDataDevice, loopMetaDevice) + + table, err := Table(testPoolName) + t.Logf("table: %s", table) + assert.NilError(t, err) + assert.Assert(t, strings.HasPrefix(table, "0 32768 thin-pool")) + assert.Assert(t, strings.HasSuffix(table, "128 32768 1 skip_block_zeroing")) + }) + + t.Run("ReloadPool", func(t *testing.T) { + err := ReloadPool(testPoolName, loopDataDevice, loopMetaDevice, 256) + assert.NilError(t, err, "failed to reload thin-pool") + }) + + t.Run("CreateDevice", testCreateDevice) + + t.Run("CreateSnapshot", testCreateSnapshot) + t.Run("DeleteSnapshot", testDeleteSnapshot) + + t.Run("ActivateDevice", testActivateDevice) + t.Run("DeviceStatus", testDeviceStatus) + t.Run("SuspendResumeDevice", testSuspendResumeDevice) + t.Run("RemoveDevice", testRemoveDevice) + + t.Run("RemovePool", func(t *testing.T) { + err = RemoveDevice(testPoolName, RemoveWithForce, RemoveWithRetries) + assert.NilError(t, err, "failed to remove thin-pool") + }) + + t.Run("Version", testVersion) +} + +func testCreateDevice(t *testing.T) { + err := CreateDevice(testPoolName, deviceID) + assert.NilError(t, err, "failed to create test device") + + err = CreateDevice(testPoolName, deviceID) + assert.Assert(t, err == unix.EEXIST) + + infos, err := Info(testPoolName) + assert.NilError(t, err) + assert.Assert(t, is.Len(infos, 1), "got unexpected number of device infos") +} + +func testCreateSnapshot(t *testing.T) { + err := CreateSnapshot(testPoolName, snapshotID, deviceID) + assert.NilError(t, err) +} + +func testDeleteSnapshot(t *testing.T) { + err := DeleteDevice(testPoolName, snapshotID) + assert.NilError(t, err, "failed to send delete message") + + err = DeleteDevice(testPoolName, snapshotID) + assert.Assert(t, err == unix.ENODATA) +} + +func testActivateDevice(t *testing.T) { + err := ActivateDevice(testPoolName, testDeviceName, 1, 1024, "") + assert.NilError(t, err, "failed to activate device") + + err = ActivateDevice(testPoolName, testDeviceName, 1, 1024, "") + assert.Equal(t, err, unix.EBUSY) + + if _, err := os.Stat("/dev/mapper/" + testDeviceName); err != nil && !os.IsExist(err) { + assert.NilError(t, err, "failed to stat device") + } + + list, err := Info(testPoolName) + assert.NilError(t, err) + assert.Assert(t, is.Len(list, 1)) + + info := list[0] + assert.Equal(t, testPoolName, info.Name) + assert.Assert(t, info.TableLive) +} + +func testDeviceStatus(t *testing.T) { + status, err := Status(testDeviceName) + assert.NilError(t, err) + + assert.Equal(t, int64(0), status.Offset) + assert.Equal(t, int64(2), status.Length) + assert.Equal(t, "thin", status.Target) + assert.DeepEqual(t, status.Params, []string{"0", "-"}) +} + +func testSuspendResumeDevice(t *testing.T) { + err := SuspendDevice(testDeviceName) + assert.NilError(t, err) + + err = SuspendDevice(testDeviceName) + assert.NilError(t, err) + + list, err := Info(testDeviceName) + assert.NilError(t, err) + assert.Assert(t, is.Len(list, 1)) + + info := list[0] + assert.Assert(t, info.Suspended) + + err = ResumeDevice(testDeviceName) + assert.NilError(t, err) + + err = ResumeDevice(testDeviceName) + assert.NilError(t, err) +} + +func testRemoveDevice(t *testing.T) { + err := RemoveDevice(testPoolName) + assert.Assert(t, err == unix.EBUSY, "removing thin-pool with dependencies shouldn't be allowed") + + err = RemoveDevice(testDeviceName, RemoveWithRetries) + assert.NilError(t, err, "failed to remove thin-device") +} + +func testVersion(t *testing.T) { + version, err := Version() + assert.NilError(t, err) + assert.Assert(t, version != "") +} + +func createLoopbackDevice(t *testing.T, dir string) (string, string) { + file, err := ioutil.TempFile(dir, "dmsetup-tests-") + assert.NilError(t, err) + + size, err := units.RAMInBytes("16Mb") + assert.NilError(t, err) + + err = file.Truncate(size) + assert.NilError(t, err) + + err = file.Close() + assert.NilError(t, err) + + imagePath := file.Name() + + loopDevice, err := mount.AttachLoopDevice(imagePath) + assert.NilError(t, err) + + return imagePath, loopDevice +} diff -Nru containerd-1.2.6/snapshots/devmapper/metadata.go containerd-1.5.9/snapshots/devmapper/metadata.go --- containerd-1.2.6/snapshots/devmapper/metadata.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/metadata.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,370 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + + "github.com/pkg/errors" + bolt "go.etcd.io/bbolt" +) + +type ( + // DeviceInfoCallback is a callback used for device updates + DeviceInfoCallback func(deviceInfo *DeviceInfo) error +) + +type deviceIDState byte + +const ( + deviceFree deviceIDState = iota + deviceTaken + deviceFaulty +) + +// Bucket names +var ( + devicesBucketName = []byte("devices") // Contains thin devices metadata = + deviceIDBucketName = []byte("device_ids") // Tracks used device ids = +) + +var ( + // ErrNotFound represents an error returned when object not found in meta store + ErrNotFound = errors.New("not found") + // ErrAlreadyExists represents an error returned when object can't be duplicated in meta store + ErrAlreadyExists = errors.New("object already exists") +) + +// PoolMetadata keeps device info for the given thin-pool device, it also responsible for +// generating next available device ids and tracking devmapper transaction numbers +type PoolMetadata struct { + db *bolt.DB +} + +// NewPoolMetadata creates new or open existing pool metadata database +func NewPoolMetadata(dbfile string) (*PoolMetadata, error) { + db, err := bolt.Open(dbfile, 0600, nil) + if err != nil { + return nil, err + } + + metadata := &PoolMetadata{db: db} + if err := metadata.ensureDatabaseInitialized(); err != nil { + return nil, errors.Wrap(err, "failed to initialize database") + } + + return metadata, nil +} + +// ensureDatabaseInitialized creates buckets required for metadata store in order +// to avoid bucket existence checks across the code +func (m *PoolMetadata) ensureDatabaseInitialized() error { + return m.db.Update(func(tx *bolt.Tx) error { + if _, err := tx.CreateBucketIfNotExists(devicesBucketName); err != nil { + return err + } + + if _, err := tx.CreateBucketIfNotExists(deviceIDBucketName); err != nil { + return err + } + + return nil + }) +} + +// AddDevice saves device info to database. +func (m *PoolMetadata) AddDevice(ctx context.Context, info *DeviceInfo) error { + err := m.db.Update(func(tx *bolt.Tx) error { + devicesBucket := tx.Bucket(devicesBucketName) + + // Make sure device name is unique. If there is already a device with the same name, + // but in Faulty state, give it a try with another devmapper device ID. + // See https://github.com/containerd/containerd/pull/3436 for more context. + var existing DeviceInfo + if err := getObject(devicesBucket, info.Name, &existing); err == nil && existing.State != Faulty { + return errors.Wrapf(ErrAlreadyExists, "device %q is already there %+v", info.Name, existing) + } + + // Find next available device ID + deviceID, err := getNextDeviceID(tx) + if err != nil { + return err + } + + info.DeviceID = deviceID + + return putObject(devicesBucket, info.Name, info, true) + }) + + if err != nil { + return errors.Wrapf(err, "failed to save metadata for device %q (parent: %q)", info.Name, info.ParentName) + } + + return nil +} + +// ChangeDeviceState changes the device state given the device name in devices bucket. +func (m *PoolMetadata) ChangeDeviceState(ctx context.Context, name string, state DeviceState) error { + return m.UpdateDevice(ctx, name, func(deviceInfo *DeviceInfo) error { + deviceInfo.State = state + return nil + }) +} + +// MarkFaulty marks the given device and corresponding devmapper device ID as faulty. +// The snapshotter might attempt to recreate a device in 'Faulty' state with another devmapper ID in +// subsequent calls, and in case of success it's status will be changed to 'Created' or 'Activated'. +// The devmapper dev ID will remain in 'deviceFaulty' state until manually handled by a user. +func (m *PoolMetadata) MarkFaulty(ctx context.Context, name string) error { + return m.db.Update(func(tx *bolt.Tx) error { + var ( + device = DeviceInfo{} + devBucket = tx.Bucket(devicesBucketName) + ) + + if err := getObject(devBucket, name, &device); err != nil { + return err + } + + device.State = Faulty + + if err := putObject(devBucket, name, &device, true); err != nil { + return err + } + + return markDeviceID(tx, device.DeviceID, deviceFaulty) + }) +} + +// getNextDeviceID finds the next free device ID by taking a cursor +// through the deviceIDBucketName bucket and finding the next sequentially +// unassigned ID. Device ID state is marked by a byte deviceFree or +// deviceTaken. Low device IDs will be reused sooner. +func getNextDeviceID(tx *bolt.Tx) (uint32, error) { + bucket := tx.Bucket(deviceIDBucketName) + cursor := bucket.Cursor() + + // Check if any device id can be reused. + // Bolt stores its keys in byte-sorted order within a bucket. + // This makes sequential iteration extremely fast. + for key, taken := cursor.First(); key != nil; key, taken = cursor.Next() { + isFree := taken[0] == byte(deviceFree) + if !isFree { + continue + } + + parsedID, err := strconv.ParseUint(string(key), 10, 32) + if err != nil { + return 0, err + } + + id := uint32(parsedID) + if err := markDeviceID(tx, id, deviceTaken); err != nil { + return 0, err + } + + return id, nil + } + + // Try allocate new device ID + seq, err := bucket.NextSequence() + if err != nil { + return 0, err + } + + if seq >= maxDeviceID { + return 0, errors.Errorf("dm-meta: couldn't find free device key") + } + + id := uint32(seq) + if err := markDeviceID(tx, id, deviceTaken); err != nil { + return 0, err + } + + return id, nil +} + +// markDeviceID marks a device as deviceFree or deviceTaken +func markDeviceID(tx *bolt.Tx, deviceID uint32, state deviceIDState) error { + var ( + bucket = tx.Bucket(deviceIDBucketName) + key = strconv.FormatUint(uint64(deviceID), 10) + value = []byte{byte(state)} + ) + + if err := bucket.Put([]byte(key), value); err != nil { + return errors.Wrapf(err, "failed to free device id %q", key) + } + + return nil +} + +// UpdateDevice updates device info in metadata store. +// The callback should be used to indicate whether device info update was successful or not. +// An error returned from the callback will rollback the update transaction in the database. +// Name and Device ID are not allowed to change. +func (m *PoolMetadata) UpdateDevice(ctx context.Context, name string, fn DeviceInfoCallback) error { + return m.db.Update(func(tx *bolt.Tx) error { + var ( + device = &DeviceInfo{} + bucket = tx.Bucket(devicesBucketName) + ) + + if err := getObject(bucket, name, device); err != nil { + return err + } + + // Don't allow changing these values, keep things in sync with devmapper + name := device.Name + devID := device.DeviceID + + if err := fn(device); err != nil { + return err + } + + if name != device.Name { + return fmt.Errorf("failed to update device info, name didn't match: %q %q", name, device.Name) + } + + if devID != device.DeviceID { + return fmt.Errorf("failed to update device info, device id didn't match: %d %d", devID, device.DeviceID) + } + + return putObject(bucket, name, device, true) + }) +} + +// GetDevice retrieves device info by name from database +func (m *PoolMetadata) GetDevice(ctx context.Context, name string) (*DeviceInfo, error) { + var ( + dev DeviceInfo + err error + ) + + err = m.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(devicesBucketName) + return getObject(bucket, name, &dev) + }) + + return &dev, err +} + +// RemoveDevice removes device info from store. +func (m *PoolMetadata) RemoveDevice(ctx context.Context, name string) error { + return m.db.Update(func(tx *bolt.Tx) error { + var ( + device = &DeviceInfo{} + bucket = tx.Bucket(devicesBucketName) + ) + + if err := getObject(bucket, name, device); err != nil { + return err + } + + if err := bucket.Delete([]byte(name)); err != nil { + return errors.Wrapf(err, "failed to delete device info for %q", name) + } + + return markDeviceID(tx, device.DeviceID, deviceFree) + }) +} + +// WalkDevices walks all devmapper devices in metadata store and invokes the callback with device info. +// The provided callback function must not modify the bucket. +func (m *PoolMetadata) WalkDevices(ctx context.Context, cb func(info *DeviceInfo) error) error { + return m.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(devicesBucketName) + return bucket.ForEach(func(key, value []byte) error { + device := &DeviceInfo{} + if err := json.Unmarshal(value, device); err != nil { + return errors.Wrapf(err, "failed to unmarshal %s", key) + } + + return cb(device) + }) + }) +} + +// GetDeviceNames retrieves the list of device names currently stored in database +func (m *PoolMetadata) GetDeviceNames(ctx context.Context) ([]string, error) { + var ( + names []string + err error + ) + + err = m.db.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket(devicesBucketName) + return bucket.ForEach(func(k, _ []byte) error { + names = append(names, string(k)) + return nil + }) + }) + + if err != nil { + return nil, err + } + + return names, nil +} + +// Close closes metadata store +func (m *PoolMetadata) Close() error { + if err := m.db.Close(); err != nil && err != bolt.ErrDatabaseNotOpen { + return err + } + + return nil +} + +func putObject(bucket *bolt.Bucket, key string, obj interface{}, overwrite bool) error { + keyBytes := []byte(key) + + if !overwrite && bucket.Get(keyBytes) != nil { + return errors.Errorf("object with key %q already exists", key) + } + + data, err := json.Marshal(obj) + if err != nil { + return errors.Wrapf(err, "failed to marshal object with key %q", key) + } + + if err := bucket.Put(keyBytes, data); err != nil { + return errors.Wrapf(err, "failed to insert object with key %q", key) + } + + return nil +} + +func getObject(bucket *bolt.Bucket, key string, obj interface{}) error { + data := bucket.Get([]byte(key)) + if data == nil { + return ErrNotFound + } + + if obj != nil { + if err := json.Unmarshal(data, obj); err != nil { + return errors.Wrapf(err, "failed to unmarshal object with key %q", key) + } + } + + return nil +} diff -Nru containerd-1.2.6/snapshots/devmapper/metadata_test.go containerd-1.5.9/snapshots/devmapper/metadata_test.go --- containerd-1.2.6/snapshots/devmapper/metadata_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/metadata_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,251 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "context" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "testing" + + "github.com/pkg/errors" + "go.etcd.io/bbolt" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +var ( + testCtx = context.Background() +) + +func TestPoolMetadata_AddDevice(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + expected := &DeviceInfo{ + Name: "test2", + ParentName: "test1", + Size: 1, + State: Activated, + } + + err := store.AddDevice(testCtx, expected) + assert.NilError(t, err) + + result, err := store.GetDevice(testCtx, "test2") + assert.NilError(t, err) + + assert.Equal(t, expected.Name, result.Name) + assert.Equal(t, expected.ParentName, result.ParentName) + assert.Equal(t, expected.Size, result.Size) + assert.Equal(t, expected.State, result.State) + assert.Assert(t, result.DeviceID != 0) + assert.Equal(t, expected.DeviceID, result.DeviceID) +} + +func TestPoolMetadata_AddDeviceRollback(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: ""}) + assert.Assert(t, err != nil) + + _, err = store.GetDevice(testCtx, "") + assert.Equal(t, ErrNotFound, err) +} + +func TestPoolMetadata_AddDeviceDuplicate(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) + assert.NilError(t, err) + + err = store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) + assert.Assert(t, errors.Is(err, ErrAlreadyExists)) +} + +func TestPoolMetadata_ReuseDeviceID(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + info1 := &DeviceInfo{Name: "test1"} + err := store.AddDevice(testCtx, info1) + assert.NilError(t, err) + + info2 := &DeviceInfo{Name: "test2"} + err = store.AddDevice(testCtx, info2) + assert.NilError(t, err) + + assert.Assert(t, info1.DeviceID != info2.DeviceID) + assert.Assert(t, info1.DeviceID != 0) + + err = store.RemoveDevice(testCtx, info2.Name) + assert.NilError(t, err) + + info3 := &DeviceInfo{Name: "test3"} + err = store.AddDevice(testCtx, info3) + assert.NilError(t, err) + + assert.Equal(t, info2.DeviceID, info3.DeviceID) +} + +func TestPoolMetadata_RemoveDevice(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"}) + assert.NilError(t, err) + + err = store.RemoveDevice(testCtx, "test") + assert.NilError(t, err) + + _, err = store.GetDevice(testCtx, "test") + assert.Equal(t, ErrNotFound, err) +} + +func TestPoolMetadata_UpdateDevice(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + oldInfo := &DeviceInfo{ + Name: "test1", + ParentName: "test2", + Size: 3, + State: Activated, + } + + err := store.AddDevice(testCtx, oldInfo) + assert.NilError(t, err) + + err = store.UpdateDevice(testCtx, oldInfo.Name, func(info *DeviceInfo) error { + info.ParentName = "test5" + info.Size = 6 + info.State = Created + return nil + }) + + assert.NilError(t, err) + + newInfo, err := store.GetDevice(testCtx, "test1") + assert.NilError(t, err) + + assert.Equal(t, "test1", newInfo.Name) + assert.Equal(t, "test5", newInfo.ParentName) + assert.Assert(t, newInfo.Size == 6) + assert.Equal(t, Created, newInfo.State) +} + +func TestPoolMetadata_MarkFaulty(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + info := &DeviceInfo{Name: "test"} + err := store.AddDevice(testCtx, info) + assert.NilError(t, err) + + err = store.MarkFaulty(testCtx, "test") + assert.NilError(t, err) + + saved, err := store.GetDevice(testCtx, info.Name) + assert.NilError(t, err) + assert.Equal(t, saved.State, Faulty) + assert.Assert(t, saved.DeviceID > 0) + + // Make sure a device ID marked as faulty as well + err = store.db.View(func(tx *bbolt.Tx) error { + bucket := tx.Bucket(deviceIDBucketName) + key := strconv.FormatUint(uint64(saved.DeviceID), 10) + value := bucket.Get([]byte(key)) + assert.Equal(t, value[0], byte(deviceFaulty)) + return nil + }) + assert.NilError(t, err) +} + +func TestPoolMetadata_WalkDevices(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: "device1", DeviceID: 1, State: Created}) + assert.NilError(t, err) + + err = store.AddDevice(testCtx, &DeviceInfo{Name: "device2", DeviceID: 2, State: Faulty}) + assert.NilError(t, err) + + called := 0 + err = store.WalkDevices(testCtx, func(info *DeviceInfo) error { + called++ + switch called { + case 1: + assert.Equal(t, "device1", info.Name) + assert.Equal(t, uint32(1), info.DeviceID) + assert.Equal(t, Created, info.State) + case 2: + assert.Equal(t, "device2", info.Name) + assert.Equal(t, uint32(2), info.DeviceID) + assert.Equal(t, Faulty, info.State) + default: + t.Error("unexpected walk call") + } + + return nil + }) + assert.NilError(t, err) + assert.Equal(t, called, 2) +} + +func TestPoolMetadata_GetDeviceNames(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: "test1"}) + assert.NilError(t, err) + + err = store.AddDevice(testCtx, &DeviceInfo{Name: "test2"}) + assert.NilError(t, err) + + names, err := store.GetDeviceNames(testCtx) + assert.NilError(t, err) + assert.Assert(t, is.Len(names, 2)) + + assert.Equal(t, "test1", names[0]) + assert.Equal(t, "test2", names[1]) +} + +func createStore(t *testing.T) (tempDir string, store *PoolMetadata) { + tempDir, err := ioutil.TempDir("", "pool-metadata-") + assert.NilError(t, err, "couldn't create temp directory for metadata tests") + + path := filepath.Join(tempDir, "test.db") + metadata, err := NewPoolMetadata(path) + assert.NilError(t, err) + + return tempDir, metadata +} + +func cleanupStore(t *testing.T, tempDir string, store *PoolMetadata) { + err := store.Close() + assert.NilError(t, err, "failed to close metadata store") + + err = os.RemoveAll(tempDir) + assert.NilError(t, err, "failed to cleanup temp directory") +} diff -Nru containerd-1.2.6/snapshots/devmapper/plugin/plugin.go containerd-1.5.9/snapshots/devmapper/plugin/plugin.go --- containerd-1.2.6/snapshots/devmapper/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package plugin + +import ( + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/snapshots/devmapper" + "github.com/pkg/errors" +) + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.SnapshotPlugin, + ID: "devmapper", + Config: &devmapper.Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) + + config, ok := ic.Config.(*devmapper.Config) + if !ok { + return nil, errors.New("invalid devmapper configuration") + } + + if config.PoolName == "" { + return nil, errors.New("devmapper not configured") + } + + if config.RootPath == "" { + config.RootPath = ic.Root + } + + return devmapper.NewSnapshotter(ic.Context, config) + }, + }) +} diff -Nru containerd-1.2.6/snapshots/devmapper/pool_device.go containerd-1.5.9/snapshots/devmapper/pool_device.go --- containerd-1.2.6/snapshots/devmapper/pool_device.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/pool_device.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,561 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "context" + "path/filepath" + "strconv" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" + "golang.org/x/sys/unix" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/snapshots/devmapper/dmsetup" +) + +// PoolDevice ties together data and metadata volumes, represents thin-pool and manages volumes, snapshots and device ids. +type PoolDevice struct { + poolName string + metadata *PoolMetadata +} + +// NewPoolDevice creates new thin-pool from existing data and metadata volumes. +// If pool 'poolName' already exists, it'll be reloaded with new parameters. +func NewPoolDevice(ctx context.Context, config *Config) (*PoolDevice, error) { + log.G(ctx).Infof("initializing pool device %q", config.PoolName) + + version, err := dmsetup.Version() + if err != nil { + log.G(ctx).Errorf("dmsetup not available") + return nil, err + } + + log.G(ctx).Infof("using dmsetup:\n%s", version) + + dbpath := filepath.Join(config.RootPath, config.PoolName+".db") + poolMetaStore, err := NewPoolMetadata(dbpath) + if err != nil { + return nil, err + } + + // Make sure pool exists and available + poolPath := dmsetup.GetFullDevicePath(config.PoolName) + if _, err := dmsetup.Info(poolPath); err != nil { + return nil, errors.Wrapf(err, "failed to query pool %q", poolPath) + } + + poolDevice := &PoolDevice{ + poolName: config.PoolName, + metadata: poolMetaStore, + } + + if err := poolDevice.ensureDeviceStates(ctx); err != nil { + return nil, errors.Wrap(err, "failed to check devices state") + } + + return poolDevice, nil +} + +func retry(ctx context.Context, f func() error) error { + var ( + maxRetries = 100 + retryDelay = 100 * time.Millisecond + retryErr error + ) + + for attempt := 1; attempt <= maxRetries; attempt++ { + retryErr = f() + if retryErr == nil { + return nil + } else if retryErr != unix.EBUSY { + return retryErr + } + + // Don't spam logs + if attempt%10 == 0 { + log.G(ctx).WithError(retryErr).Warnf("retrying... (%d of %d)", attempt, maxRetries) + } + + // Devmapper device is busy, give it a bit of time and retry removal + time.Sleep(retryDelay) + } + + return retryErr +} + +// ensureDeviceStates updates devices to their real state: +// - marks devices with incomplete states (after crash) as 'Faulty' +// - activates devices if they are marked as 'Activated' but the dm +// device is not active, which can happen to a stopped container +// after a reboot +func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error { + var faultyDevices []*DeviceInfo + var activatedDevices []*DeviceInfo + + if err := p.WalkDevices(ctx, func(info *DeviceInfo) error { + switch info.State { + case Suspended, Resumed, Deactivated, Removed, Faulty: + case Activated: + activatedDevices = append(activatedDevices, info) + default: + faultyDevices = append(faultyDevices, info) + } + return nil + }); err != nil { + return errors.Wrap(err, "failed to query devices from metastore") + } + + var result *multierror.Error + for _, dev := range activatedDevices { + if p.IsActivated(dev.Name) { + continue + } + + log.G(ctx).Warnf("devmapper device %q marked as %q but not active, activating it", dev.Name, dev.State) + if err := p.activateDevice(ctx, dev); err != nil { + result = multierror.Append(result, err) + } + } + + for _, dev := range faultyDevices { + log.G(ctx). + WithField("dev_id", dev.DeviceID). + WithField("parent", dev.ParentName). + WithField("error", dev.Error). + Warnf("devmapper device %q has invalid state %q, marking as faulty", dev.Name, dev.State) + + if err := p.metadata.MarkFaulty(ctx, dev.Name); err != nil { + result = multierror.Append(result, err) + } + } + + return multierror.Prefix(result.ErrorOrNil(), "devmapper:") +} + +// transition invokes 'updateStateFn' callback to perform devmapper operation and reflects device state changes/errors in meta store. +// 'tryingState' will be set before invoking callback. If callback succeeded 'successState' will be set, otherwise +// error details will be recorded in meta store. +func (p *PoolDevice) transition(ctx context.Context, deviceName string, tryingState DeviceState, successState DeviceState, updateStateFn func() error) error { + // Set device to trying state + uerr := p.metadata.UpdateDevice(ctx, deviceName, func(deviceInfo *DeviceInfo) error { + deviceInfo.State = tryingState + return nil + }) + + if uerr != nil { + return errors.Wrapf(uerr, "failed to set device %q state to %q", deviceName, tryingState) + } + + var result *multierror.Error + + // Invoke devmapper operation + err := updateStateFn() + + if err != nil { + result = multierror.Append(result, err) + } + + // If operation succeeded transition to success state, otherwise save error details + uerr = p.metadata.UpdateDevice(ctx, deviceName, func(deviceInfo *DeviceInfo) error { + if err == nil { + deviceInfo.State = successState + deviceInfo.Error = "" + } else { + deviceInfo.Error = err.Error() + } + return nil + }) + + if uerr != nil { + result = multierror.Append(result, uerr) + } + + return unwrapError(result) +} + +// unwrapError converts multierror.Error to the original error when it is possible. +// multierror 1.1.0 has the similar function named Unwrap, but it requires Go 1.14. +func unwrapError(e *multierror.Error) error { + if e == nil { + return nil + } + + // If the error can be expressed without multierror, return the original error. + if len(e.Errors) == 1 { + return e.Errors[0] + } + + return e.ErrorOrNil() +} + +// CreateThinDevice creates new devmapper thin-device with given name and size. +// Device ID for thin-device will be allocated from metadata store. +// If allocation successful, device will be activated with /dev/mapper/ +func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, virtualSizeBytes uint64) (retErr error) { + info := &DeviceInfo{ + Name: deviceName, + Size: virtualSizeBytes, + State: Unknown, + } + + var ( + metaErr error + devErr error + activeErr error + ) + + defer func() { + // We've created a devmapper device, but failed to activate it, try rollback everything + if activeErr != nil { + retErr = p.rollbackActivate(ctx, info, activeErr) + return + } + + // We're unable to create the devmapper device, most likely something wrong with the deviceID + if devErr != nil { + retErr = multierror.Append(retErr, p.metadata.MarkFaulty(ctx, info.Name)) + return + } + }() + + // Save initial device metadata and allocate new device ID from store + metaErr = p.metadata.AddDevice(ctx, info) + if metaErr != nil { + return metaErr + } + + // Create thin device + devErr = p.createDevice(ctx, info) + if devErr != nil { + return devErr + } + + // Activate thin device + activeErr = p.activateDevice(ctx, info) + if activeErr != nil { + return activeErr + } + + return nil +} + +func (p *PoolDevice) rollbackActivate(ctx context.Context, info *DeviceInfo, activateErr error) error { + // Delete the device first. + delErr := p.deleteDevice(ctx, info) + if delErr != nil { + // Failed to rollback, mark the device as faulty and keep metadata in order to + // preserve the faulty device ID + return multierror.Append(activateErr, delErr, p.metadata.MarkFaulty(ctx, info.Name)) + } + + // The devmapper device has been successfully deleted, deallocate device ID + if err := p.RemoveDevice(ctx, info.Name); err != nil { + return multierror.Append(activateErr, err) + } + + return activateErr +} + +// createDevice creates thin device +func (p *PoolDevice) createDevice(ctx context.Context, info *DeviceInfo) error { + if err := p.transition(ctx, info.Name, Creating, Created, func() error { + return dmsetup.CreateDevice(p.poolName, info.DeviceID) + }); err != nil { + return errors.Wrapf(err, "failed to create new thin device %q (dev: %d)", info.Name, info.DeviceID) + } + + return nil +} + +// activateDevice activates thin device +func (p *PoolDevice) activateDevice(ctx context.Context, info *DeviceInfo) error { + if err := p.transition(ctx, info.Name, Activating, Activated, func() error { + return dmsetup.ActivateDevice(p.poolName, info.Name, info.DeviceID, info.Size, "") + }); err != nil { + return errors.Wrapf(err, "failed to activate new thin device %q (dev: %d)", info.Name, info.DeviceID) + } + + return nil +} + +// CreateSnapshotDevice creates and activates new thin-device from parent thin-device (makes snapshot) +func (p *PoolDevice) CreateSnapshotDevice(ctx context.Context, deviceName string, snapshotName string, virtualSizeBytes uint64) (retErr error) { + baseInfo, err := p.metadata.GetDevice(ctx, deviceName) + if err != nil { + return errors.Wrapf(err, "failed to query device metadata for %q", deviceName) + } + + snapInfo := &DeviceInfo{ + Name: snapshotName, + Size: virtualSizeBytes, + ParentName: deviceName, + State: Unknown, + } + + var ( + metaErr error + devErr error + activeErr error + ) + + defer func() { + // We've created a devmapper device, but failed to activate it, try rollback everything + if activeErr != nil { + retErr = p.rollbackActivate(ctx, snapInfo, activeErr) + return + } + + // We're unable to create the devmapper device, most likely something wrong with the deviceID + if devErr != nil { + retErr = multierror.Append(retErr, p.metadata.MarkFaulty(ctx, snapInfo.Name)) + return + } + }() + + // The base device must be suspend before taking a snapshot to + // avoid corruption. + // https://github.com/torvalds/linux/blob/v5.7/Documentation/admin-guide/device-mapper/thin-provisioning.rst#internal-snapshots + if p.IsLoaded(deviceName) { + log.G(ctx).Debugf("suspending %q before taking its snapshot", deviceName) + suspendErr := p.SuspendDevice(ctx, deviceName) + if suspendErr != nil { + return suspendErr + } + defer func() { + err := p.ResumeDevice(ctx, deviceName) + if err != nil { + log.G(ctx).WithError(err).Errorf("failed to resume base device %q after taking its snapshot", baseInfo.Name) + } + }() + } + + // Save snapshot metadata and allocate new device ID + metaErr = p.metadata.AddDevice(ctx, snapInfo) + if metaErr != nil { + return metaErr + } + + // Create thin device snapshot + devErr = p.createSnapshot(ctx, baseInfo, snapInfo) + if devErr != nil { + return devErr + } + + // Activate the snapshot device + activeErr = p.activateDevice(ctx, snapInfo) + if activeErr != nil { + return activeErr + } + + return nil +} + +func (p *PoolDevice) createSnapshot(ctx context.Context, baseInfo, snapInfo *DeviceInfo) error { + if err := p.transition(ctx, snapInfo.Name, Creating, Created, func() error { + return dmsetup.CreateSnapshot(p.poolName, snapInfo.DeviceID, baseInfo.DeviceID) + }); err != nil { + return errors.Wrapf(err, + "failed to create snapshot %q (dev: %d) from %q (dev: %d)", + snapInfo.Name, + snapInfo.DeviceID, + baseInfo.Name, + baseInfo.DeviceID) + } + + return nil +} + +// SuspendDevice flushes the outstanding IO and blocks the further IO +func (p *PoolDevice) SuspendDevice(ctx context.Context, deviceName string) error { + if err := p.transition(ctx, deviceName, Suspending, Suspended, func() error { + return dmsetup.SuspendDevice(deviceName) + }); err != nil { + return errors.Wrapf(err, "failed to suspend device %q", deviceName) + } + + return nil +} + +// ResumeDevice resumes IO for the given device +func (p *PoolDevice) ResumeDevice(ctx context.Context, deviceName string) error { + if err := p.transition(ctx, deviceName, Resuming, Resumed, func() error { + return dmsetup.ResumeDevice(deviceName) + }); err != nil { + return errors.Wrapf(err, "failed to resume device %q", deviceName) + } + + return nil +} + +// DeactivateDevice deactivates thin device +func (p *PoolDevice) DeactivateDevice(ctx context.Context, deviceName string, deferred, withForce bool) error { + if !p.IsLoaded(deviceName) { + return nil + } + + opts := []dmsetup.RemoveDeviceOpt{dmsetup.RemoveWithRetries} + if deferred { + opts = append(opts, dmsetup.RemoveDeferred) + } + if withForce { + opts = append(opts, dmsetup.RemoveWithForce) + } + + if err := p.transition(ctx, deviceName, Deactivating, Deactivated, func() error { + return retry(ctx, func() error { + if err := dmsetup.RemoveDevice(deviceName, opts...); err != nil { + return errors.Wrap(err, "failed to deactivate device") + } + + return nil + }) + }); err != nil { + return errors.Wrapf(err, "failed to deactivate device %q", deviceName) + } + + return nil +} + +// IsActivated returns true if thin-device is activated +func (p *PoolDevice) IsActivated(deviceName string) bool { + infos, err := dmsetup.Info(deviceName) + if err != nil || len(infos) != 1 { + // Couldn't query device info, device not active + return false + } + + if devInfo := infos[0]; devInfo.TableLive { + return true + } + + return false +} + +// IsLoaded returns true if thin-device is visible for dmsetup +func (p *PoolDevice) IsLoaded(deviceName string) bool { + _, err := dmsetup.Info(deviceName) + return err == nil +} + +// GetUsage reports total size in bytes consumed by a thin-device. +// It relies on the number of used blocks reported by 'dmsetup status'. +// The output looks like: +// device2: 0 204800 thin 17280 204799 +// Where 17280 is the number of used sectors +func (p *PoolDevice) GetUsage(deviceName string) (int64, error) { + status, err := dmsetup.Status(deviceName) + if err != nil { + return 0, errors.Wrapf(err, "can't get status for device %q", deviceName) + } + + if len(status.Params) == 0 { + return 0, errors.Errorf("failed to get the number of used blocks, unexpected output from dmsetup status") + } + + count, err := strconv.ParseInt(status.Params[0], 10, 64) + if err != nil { + return 0, errors.Wrapf(err, "failed to parse status params: %q", status.Params[0]) + } + + return count * dmsetup.SectorSize, nil +} + +// RemoveDevice completely wipes out thin device from thin-pool and frees it's device ID +func (p *PoolDevice) RemoveDevice(ctx context.Context, deviceName string) error { + info, err := p.metadata.GetDevice(ctx, deviceName) + if err != nil { + return errors.Wrapf(err, "can't query metadata for device %q", deviceName) + } + + if err := p.DeactivateDevice(ctx, deviceName, false, true); err != nil { + return err + } + + if err := p.deleteDevice(ctx, info); err != nil { + return err + } + + // Remove record from meta store and free device ID + if err := p.metadata.RemoveDevice(ctx, deviceName); err != nil { + return errors.Wrapf(err, "can't remove device %q metadata from store after removal", deviceName) + } + + return nil +} + +func (p *PoolDevice) deleteDevice(ctx context.Context, info *DeviceInfo) error { + if err := p.transition(ctx, info.Name, Removing, Removed, func() error { + return retry(ctx, func() error { + // Send 'delete' message to thin-pool + e := dmsetup.DeleteDevice(p.poolName, info.DeviceID) + // Ignores the error if the device has been deleted already. + if e != nil && !errors.Is(e, unix.ENODATA) { + return e + } + return nil + }) + }); err != nil { + return errors.Wrapf(err, "failed to delete device %q (dev id: %d)", info.Name, info.DeviceID) + } + + return nil +} + +// RemovePool deactivates all child thin-devices and removes thin-pool device +func (p *PoolDevice) RemovePool(ctx context.Context) error { + deviceNames, err := p.metadata.GetDeviceNames(ctx) + if err != nil { + return errors.Wrap(err, "can't query device names") + } + + var result *multierror.Error + + // Deactivate devices if any + for _, name := range deviceNames { + if err := p.DeactivateDevice(ctx, name, true, true); err != nil { + result = multierror.Append(result, errors.Wrapf(err, "failed to remove %q", name)) + } + } + + if err := dmsetup.RemoveDevice(p.poolName, dmsetup.RemoveWithForce, dmsetup.RemoveWithRetries, dmsetup.RemoveDeferred); err != nil { + result = multierror.Append(result, errors.Wrapf(err, "failed to remove pool %q", p.poolName)) + } + + return result.ErrorOrNil() +} + +// MarkDeviceState changes the device's state in metastore +func (p *PoolDevice) MarkDeviceState(ctx context.Context, name string, state DeviceState) error { + return p.metadata.ChangeDeviceState(ctx, name, state) +} + +// WalkDevices iterates all devices in pool metadata +func (p *PoolDevice) WalkDevices(ctx context.Context, cb func(info *DeviceInfo) error) error { + return p.metadata.WalkDevices(ctx, func(info *DeviceInfo) error { + return cb(info) + }) +} + +// Close closes pool device (thin-pool will not be removed) +func (p *PoolDevice) Close() error { + return p.metadata.Close() +} diff -Nru containerd-1.2.6/snapshots/devmapper/pool_device_test.go containerd-1.5.9/snapshots/devmapper/pool_device_test.go --- containerd-1.2.6/snapshots/devmapper/pool_device_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/pool_device_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,312 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devmapper + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" + "time" + + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/containerd/snapshots/devmapper/dmsetup" + "github.com/docker/go-units" + "github.com/sirupsen/logrus" + "gotest.tools/v3/assert" +) + +const ( + thinDevice1 = "thin-1" + thinDevice2 = "thin-2" + snapDevice1 = "snap-1" + device1Size = 100000 + device2Size = 200000 + testsPrefix = "devmapper-snapshotter-tests-" +) + +// TestPoolDevice runs integration tests for pool device. +// The following scenario implemented: +// - Create pool device with name 'test-pool-device' +// - Create two thin volumes 'thin-1' and 'thin-2' +// - Write ext4 file system on 'thin-1' and make sure it'errs moutable +// - Write v1 test file on 'thin-1' volume +// - Take 'thin-1' snapshot 'snap-1' +// - Change v1 file to v2 on 'thin-1' +// - Mount 'snap-1' and make sure test file is v1 +// - Unmount volumes and remove all devices +func TestPoolDevice(t *testing.T) { + testutil.RequiresRoot(t) + + logrus.SetLevel(logrus.DebugLevel) + ctx := context.Background() + + tempDir, err := ioutil.TempDir("", "pool-device-test-") + assert.NilError(t, err, "couldn't get temp directory for testing") + + _, loopDataDevice := createLoopbackDevice(t, tempDir) + _, loopMetaDevice := createLoopbackDevice(t, tempDir) + + poolName := fmt.Sprintf("test-pool-device-%d", time.Now().Nanosecond()) + err = dmsetup.CreatePool(poolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize) + assert.NilError(t, err, "failed to create pool %q", poolName) + + defer func() { + // Detach loop devices and remove images + err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice) + assert.NilError(t, err) + + err = os.RemoveAll(tempDir) + assert.NilError(t, err, "couldn't cleanup temp directory") + }() + + config := &Config{ + PoolName: poolName, + RootPath: tempDir, + BaseImageSize: "16mb", + BaseImageSizeBytes: 16 * 1024 * 1024, + } + + pool, err := NewPoolDevice(ctx, config) + assert.NilError(t, err, "can't create device pool") + assert.Assert(t, pool != nil) + + defer func() { + err := pool.RemovePool(ctx) + assert.NilError(t, err, "can't close device pool") + }() + + // Create thin devices + t.Run("CreateThinDevice", func(t *testing.T) { + testCreateThinDevice(t, pool) + }) + + // Make ext4 filesystem on 'thin-1' + t.Run("MakeFileSystem", func(t *testing.T) { + testMakeFileSystem(t, pool) + }) + + // Mount 'thin-1' and write v1 test file on 'thin-1' device + err = mount.WithTempMount(ctx, getMounts(thinDevice1), func(thin1MountPath string) error { + // Write v1 test file on 'thin-1' device + thin1TestFilePath := filepath.Join(thin1MountPath, "TEST") + err := ioutil.WriteFile(thin1TestFilePath, []byte("test file (v1)"), 0700) + assert.NilError(t, err, "failed to write test file v1 on '%s' volume", thinDevice1) + + return nil + }) + + // Take snapshot of 'thin-1' + t.Run("CreateSnapshotDevice", func(t *testing.T) { + testCreateSnapshot(t, pool) + }) + + // Update TEST file on 'thin-1' to v2 + err = mount.WithTempMount(ctx, getMounts(thinDevice1), func(thin1MountPath string) error { + thin1TestFilePath := filepath.Join(thin1MountPath, "TEST") + err = ioutil.WriteFile(thin1TestFilePath, []byte("test file (v2)"), 0700) + assert.NilError(t, err, "failed to write test file v2 on 'thin-1' volume after taking snapshot") + + return nil + }) + + assert.NilError(t, err) + + // Mount 'snap-1' and make sure TEST file is v1 + err = mount.WithTempMount(ctx, getMounts(snapDevice1), func(snap1MountPath string) error { + // Read test file from snapshot device and make sure it's v1 + fileData, err := ioutil.ReadFile(filepath.Join(snap1MountPath, "TEST")) + assert.NilError(t, err, "couldn't read test file from '%s' device", snapDevice1) + assert.Equal(t, "test file (v1)", string(fileData), "test file content is invalid on snapshot") + + return nil + }) + + assert.NilError(t, err) + + t.Run("DeactivateDevice", func(t *testing.T) { + testDeactivateThinDevice(t, pool) + }) + + t.Run("RemoveDevice", func(t *testing.T) { + testRemoveThinDevice(t, pool) + }) + + t.Run("rollbackActivate", func(t *testing.T) { + testCreateThinDevice(t, pool) + + ctx := context.Background() + + snapDevice := "snap2" + + err := pool.CreateSnapshotDevice(ctx, thinDevice1, snapDevice, device1Size) + assert.NilError(t, err) + + info, err := pool.metadata.GetDevice(ctx, snapDevice) + assert.NilError(t, err) + + // Simulate a case that the device cannot be activated. + err = pool.DeactivateDevice(ctx, info.Name, false, false) + assert.NilError(t, err) + + err = pool.rollbackActivate(ctx, info, err) + assert.NilError(t, err) + }) +} + +func TestPoolDeviceMarkFaulty(t *testing.T) { + tempDir, store := createStore(t) + defer cleanupStore(t, tempDir, store) + + err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown}) + assert.NilError(t, err) + + // Note: do not use 'Activated' here because pool.ensureDeviceStates() will + // try to activate the real dm device, which will fail on a faked device. + err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Deactivated}) + assert.NilError(t, err) + + pool := &PoolDevice{metadata: store} + err = pool.ensureDeviceStates(testCtx) + assert.NilError(t, err) + + called := 0 + err = pool.metadata.WalkDevices(testCtx, func(info *DeviceInfo) error { + called++ + + switch called { + case 1: + assert.Equal(t, Faulty, info.State) + assert.Equal(t, "1", info.Name) + case 2: + assert.Equal(t, Deactivated, info.State) + assert.Equal(t, "2", info.Name) + default: + t.Error("unexpected walk call") + } + + return nil + }) + assert.NilError(t, err) + assert.Equal(t, 2, called) +} + +func testCreateThinDevice(t *testing.T, pool *PoolDevice) { + ctx := context.Background() + + err := pool.CreateThinDevice(ctx, thinDevice1, device1Size) + assert.NilError(t, err, "can't create first thin device") + + err = pool.CreateThinDevice(ctx, thinDevice1, device1Size) + assert.Assert(t, err != nil, "device pool allows duplicated device names") + + err = pool.CreateThinDevice(ctx, thinDevice2, device2Size) + assert.NilError(t, err, "can't create second thin device") + + deviceInfo1, err := pool.metadata.GetDevice(ctx, thinDevice1) + assert.NilError(t, err) + + deviceInfo2, err := pool.metadata.GetDevice(ctx, thinDevice2) + assert.NilError(t, err) + + assert.Assert(t, deviceInfo1.DeviceID != deviceInfo2.DeviceID, "assigned device ids should be different") + + usage, err := pool.GetUsage(thinDevice1) + assert.NilError(t, err) + assert.Equal(t, usage, int64(0)) +} + +func testMakeFileSystem(t *testing.T, pool *PoolDevice) { + devicePath := dmsetup.GetFullDevicePath(thinDevice1) + args := []string{ + devicePath, + "-E", + "nodiscard,lazy_itable_init=0,lazy_journal_init=0", + } + + output, err := exec.Command("mkfs.ext4", args...).CombinedOutput() + assert.NilError(t, err, "failed to make filesystem on '%s': %s", thinDevice1, string(output)) + + usage, err := pool.GetUsage(thinDevice1) + assert.NilError(t, err) + assert.Assert(t, usage > 0) +} + +func testCreateSnapshot(t *testing.T, pool *PoolDevice) { + err := pool.CreateSnapshotDevice(context.Background(), thinDevice1, snapDevice1, device1Size) + assert.NilError(t, err, "failed to create snapshot from '%s' volume", thinDevice1) +} + +func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) { + deviceList := []string{ + thinDevice2, + snapDevice1, + } + + for _, deviceName := range deviceList { + assert.Assert(t, pool.IsActivated(deviceName)) + + err := pool.DeactivateDevice(context.Background(), deviceName, false, true) + assert.NilError(t, err, "failed to remove '%s'", deviceName) + + assert.Assert(t, !pool.IsActivated(deviceName)) + } +} + +func testRemoveThinDevice(t *testing.T, pool *PoolDevice) { + err := pool.RemoveDevice(testCtx, thinDevice1) + assert.NilError(t, err, "should delete thin device from pool") + + err = pool.RemoveDevice(testCtx, thinDevice2) + assert.NilError(t, err, "should delete thin device from pool") +} + +func getMounts(thinDeviceName string) []mount.Mount { + return []mount.Mount{ + { + Source: dmsetup.GetFullDevicePath(thinDeviceName), + Type: "ext4", + }, + } +} + +func createLoopbackDevice(t *testing.T, dir string) (string, string) { + file, err := ioutil.TempFile(dir, testsPrefix) + assert.NilError(t, err) + + size, err := units.RAMInBytes("128Mb") + assert.NilError(t, err) + + err = file.Truncate(size) + assert.NilError(t, err) + + err = file.Close() + assert.NilError(t, err) + + imagePath := file.Name() + + loopDevice, err := mount.AttachLoopDevice(imagePath) + assert.NilError(t, err) + + return imagePath, loopDevice +} diff -Nru containerd-1.2.6/snapshots/devmapper/README.md containerd-1.5.9/snapshots/devmapper/README.md --- containerd-1.2.6/snapshots/devmapper/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/devmapper/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,176 @@ +## Devmapper snapshotter + +Devmapper is a `containerd` snapshotter plugin that stores snapshots in ext4-formatted filesystem images +in a devicemapper thin pool. + +## Setup + +To make it work you need to prepare `thin-pool` in advance and update containerd's configuration file. +This file is typically located at `/etc/containerd/config.toml`. + +Here's minimal sample entry that can be made in the configuration file: + +``` +[plugins] + ... + [plugins.devmapper] + pool_name = "containerd-pool" + base_image_size = "8192MB" + ... +``` + +The following configuration flags are supported: +* `root_path` - a directory where the metadata will be available (if empty + default location for `containerd` plugins will be used) +* `pool_name` - a name to use for the devicemapper thin pool. Pool name + should be the same as in `/dev/mapper/` directory +* `base_image_size` - defines how much space to allocate when creating the base device +* `async_remove` - flag to async remove device using snapshot GC's cleanup callback + +Pool name and base image size are required snapshotter parameters. + +## Run +Give it a try with the following commands: + +```bash +ctr images pull --snapshotter devmapper docker.io/library/hello-world:latest +ctr run --snapshotter devmapper docker.io/library/hello-world:latest test +``` + +## Requirements + +The devicemapper snapshotter requires `dmsetup` (>= 1.02.110) command line tool to be installed and +available on your computer. On Ubuntu, it can be installed with `apt-get install dmsetup` command. + +### How to setup device mapper thin-pool + +There are many ways how to configure a devmapper thin-pool depending on your requirements, disk configuration, +and environment. + +On local dev environment you can utilize loopback devices. This type of configuration is simple and suits well for +development and testing (please note that this configuration is slow and not recommended for production uses). +Run the following script to create a thin-pool device: + +```bash +#!/bin/bash +set -ex + +DATA_DIR=/var/lib/containerd/devmapper +POOL_NAME=devpool + +mkdir -p ${DATA_DIR} + +# Create data file +sudo touch "${DATA_DIR}/data" +sudo truncate -s 100G "${DATA_DIR}/data" + +# Create metadata file +sudo touch "${DATA_DIR}/meta" +sudo truncate -s 10G "${DATA_DIR}/meta" + +# Allocate loop devices +DATA_DEV=$(sudo losetup --find --show "${DATA_DIR}/data") +META_DEV=$(sudo losetup --find --show "${DATA_DIR}/meta") + +# Define thin-pool parameters. +# See https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt for details. +SECTOR_SIZE=512 +DATA_SIZE="$(sudo blockdev --getsize64 -q ${DATA_DEV})" +LENGTH_IN_SECTORS=$(bc <<< "${DATA_SIZE}/${SECTOR_SIZE}") +DATA_BLOCK_SIZE=128 +LOW_WATER_MARK=32768 + +# Create a thin-pool device +sudo dmsetup create "${POOL_NAME}" \ + --table "0 ${LENGTH_IN_SECTORS} thin-pool ${META_DEV} ${DATA_DEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK}" + +cat << EOF +# +# Add this to your config.toml configuration file and restart containerd daemon +# +[plugins] + [plugins.devmapper] + pool_name = "${POOL_NAME}" + root_path = "${DATA_DIR}" + base_image_size = "10GB" +EOF +``` + +Use `dmsetup` to verify that the thin-pool created successfully: +```bash +sudo dmsetup ls +devpool (253:0) +``` + +Once configured and restarted `containerd`, you'll see the following output: +``` +INFO[2020-03-17T20:24:45.532604888Z] loading plugin "io.containerd.snapshotter.v1.devmapper"... type=io.containerd.snapshotter.v1 +INFO[2020-03-17T20:24:45.532672738Z] initializing pool device "dev-pool" +``` + +Another way to setup a thin-pool is via [container-storage-setup](https://github.com/projectatomic/container-storage-setup) +tool (formerly known as `docker-storage-setup`). It is a script to configure CoW file systems like devicemapper: + +```bash +#!/bin/bash +set -ex + +# Block device to use for devmapper thin-pool +BLOCK_DEV=/dev/sdf +POOL_NAME=devpool +VG_NAME=containerd + +# Install container-storage-setup tool +git clone https://github.com/projectatomic/container-storage-setup.git +cd container-storage-setup/ +sudo make install-core +echo "Using version $(container-storage-setup -v)" + +# Create configuration file +# Refer to `man container-storage-setup` to see available options +sudo tee /etc/sysconfig/docker-storage-setup < 0 as just written file system also consumes blocks + assert.Assert(t, emptyLayerUsage.Size > 0) + + err = snapshotter.Commit(ctx, "layer-1", "prepare-1") + assert.NilError(t, err) + + // Create child layer with 1MB file + + var ( + sizeBytes int64 = 1048576 // 1MB + baseApplier = fstest.Apply(fstest.CreateRandomFile("/a", 12345679, sizeBytes, 0777)) + ) + + mounts, err := snapshotter.Prepare(ctx, "prepare-2", "layer-1") + assert.NilError(t, err) + + err = mount.WithTempMount(ctx, mounts, baseApplier.Apply) + assert.NilError(t, err) + + err = snapshotter.Commit(ctx, "layer-2", "prepare-2") + assert.NilError(t, err) + + layer2Usage, err := snapshotter.Usage(ctx, "layer-2") + assert.NilError(t, err) + + // Should be at least 1 MB + fs metadata + assert.Check(t, layer2Usage.Size >= sizeBytes, + "%d > %d", layer2Usage.Size, sizeBytes) +} + +func TestMkfs(t *testing.T) { + ctx := context.Background() + err := mkfs(ctx, "") + assert.ErrorContains(t, err, `mkfs.ext4 couldn't initialize ""`) +} diff -Nru containerd-1.2.6/snapshots/lcow/lcow.go containerd-1.5.9/snapshots/lcow/lcow.go --- containerd-1.2.6/snapshots/lcow/lcow.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/lcow/lcow.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,13 +25,13 @@ "io" "os" "path/filepath" + "runtime" "strconv" "strings" "sync" - "syscall" "time" - "unsafe" + winfs "github.com/Microsoft/go-winio/pkg/fs" "github.com/Microsoft/hcsshim/pkg/go-runhcs" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" @@ -42,7 +42,6 @@ "github.com/containerd/continuity/fs" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "golang.org/x/sys/windows" ) func init() { @@ -52,13 +51,20 @@ InitFn: func(ic *plugin.InitContext) (interface{}, error) { ic.Meta.Platforms = append(ic.Meta.Platforms, ocispec.Platform{ OS: "linux", - Architecture: "amd64", + Architecture: runtime.GOARCH, }) return NewSnapshotter(ic.Root) }, }) } +const ( + rootfsSizeLabel = "containerd.io/snapshot/io.microsoft.container.storage.rootfs.size-gb" + rootfsLocLabel = "containerd.io/snapshot/io.microsoft.container.storage.rootfs.location" + reuseScratchLabel = "containerd.io/snapshot/io.microsoft.container.storage.reuse-scratch" + reuseScratchOwnerKeyLabel = "containerd.io/snapshot/io.microsoft.owner.key" +) + type snapshotter struct { root string ms *storage.MetaStore @@ -68,7 +74,7 @@ // NewSnapshotter returns a new windows snapshotter func NewSnapshotter(root string) (snapshots.Snapshotter, error) { - fsType, err := getFileSystemType(root) + fsType, err := winfs.GetFileSystemType(root) if err != nil { return nil, err } @@ -100,7 +106,6 @@ // Should be used for parent resolution, existence checks and to discern // the kind of snapshot. func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { - log.G(ctx).Debug("Starting Stat") ctx, t, err := s.ms.TransactionContext(ctx, false) if err != nil { return snapshots.Info{}, err @@ -112,7 +117,6 @@ } func (s *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { - log.G(ctx).Debug("Starting Update") ctx, t, err := s.ms.TransactionContext(ctx, true) if err != nil { return snapshots.Info{}, err @@ -132,21 +136,21 @@ } func (s *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { - log.G(ctx).Debug("Starting Usage") ctx, t, err := s.ms.TransactionContext(ctx, false) if err != nil { return snapshots.Usage{}, err } - defer t.Rollback() + id, info, usage, err := storage.GetInfo(ctx, key) + t.Rollback() // transaction no longer needed at this point. - _, info, usage, err := storage.GetInfo(ctx, key) if err != nil { return snapshots.Usage{}, err } if info.Kind == snapshots.KindActive { - du := fs.Usage{ - Size: 0, + du, err := fs.DiskUsage(ctx, s.getSnapshotDir(id)) + if err != nil { + return snapshots.Usage{}, err } usage = snapshots.Usage(du) } @@ -155,12 +159,10 @@ } func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { - log.G(ctx).Debug("Starting Prepare") return s.createSnapshot(ctx, snapshots.KindActive, key, parent, opts) } func (s *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { - log.G(ctx).Debug("Starting View") return s.createSnapshot(ctx, snapshots.KindView, key, parent, opts) } @@ -169,7 +171,6 @@ // // This can be used to recover mounts after calling View or Prepare. func (s *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { - log.G(ctx).Debug("Starting Mounts") ctx, t, err := s.ms.TransactionContext(ctx, false) if err != nil { return nil, err @@ -184,31 +185,39 @@ } func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { - log.G(ctx).Debug("Starting Commit") ctx, t, err := s.ms.TransactionContext(ctx, true) if err != nil { return err } - defer t.Rollback() + defer func() { + if err != nil { + if rerr := t.Rollback(); rerr != nil { + log.G(ctx).WithError(rerr).Warn("failed to rollback transaction") + } + } + }() - usage := fs.Usage{ - Size: 0, + // grab the existing id + id, _, _, err := storage.GetInfo(ctx, key) + if err != nil { + return err + } + + usage, err := fs.DiskUsage(ctx, s.getSnapshotDir(id)) + if err != nil { + return err } if _, err = storage.CommitActive(ctx, key, name, snapshots.Usage(usage), opts...); err != nil { return errors.Wrap(err, "failed to commit snapshot") } - if err := t.Commit(); err != nil { - return err - } - return nil + return t.Commit() } // Remove abandons the transaction identified by key. All resources // associated with the key will be removed. func (s *snapshotter) Remove(ctx context.Context, key string) error { - log.G(ctx).Debug("Starting Remove") ctx, t, err := s.ms.TransactionContext(ctx, true) if err != nil { return err @@ -243,15 +252,14 @@ } // Walk the committed snapshots. -func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { - log.G(ctx).Debug("Starting Walk") +func (s *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := s.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, fs...) } // Close closes the snapshotter @@ -301,7 +309,7 @@ return filepath.Join(s.root, "snapshots", id) } -func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) ([]mount.Mount, error) { +func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (_ []mount.Mount, err error) { ctx, t, err := s.ms.TransactionContext(ctx, true) if err != nil { return nil, err @@ -321,27 +329,70 @@ return nil, err } - scratchSource, err := s.openOrCreateScratch(ctx) - if err != nil { - return nil, err + var snapshotInfo snapshots.Info + for _, o := range opts { + o(&snapshotInfo) } - defer scratchSource.Close() - // TODO: JTERRY75 - This has to be called sandbox.vhdx for the time - // being but it really is the scratch.vhdx Using this naming convention - // for now but this is not the kubernetes sandbox. + defer func() { + if err != nil { + os.RemoveAll(snDir) + } + }() + + // IO/disk space optimization // - // Create the sandbox.vhdx for this snapshot from the cache. - destPath := filepath.Join(snDir, "sandbox.vhdx") - dest, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE, 0700) - if err != nil { - return nil, errors.Wrap(err, "failed to create sandbox.vhdx in snapshot") - } - defer dest.Close() - if _, err := io.Copy(dest, scratchSource); err != nil { - dest.Close() - os.Remove(destPath) - return nil, errors.Wrap(err, "failed to copy cached scratch.vhdx to sandbox.vhdx in snapshot") + // We only need one sandbox.vhd for the container. Skip making one for this + // snapshot if this isn't the snapshot that just houses the final sandbox.vhd + // that will be mounted as the containers scratch. The key for a snapshot + // where a layer.vhd will be extracted to it will have the substring `extract-` in it. + // If this is changed this will also need to be changed. + // + // We save about 17MB per layer (if the default scratch vhd size of 20GB is used) and of + // course the time to copy the vhdx per snapshot. + if !strings.Contains(key, snapshots.UnpackKeyPrefix) { + // This is the code path that handles re-using a scratch disk that has already been + // made/mounted for an LCOW UVM. In the non sharing case, we create a new disk and mount this + // into the LCOW UVM for every container but there are certain scenarios where we'd rather + // just mount a single disk and then have every container share this one storage space instead of + // every container having it's own xGB of space to play around with. + // + // This is accomplished by just making a symlink to the disk that we'd like to share and then + // using ref counting later on down the stack in hcsshim if we see that we've already mounted this + // disk. + shareScratch := snapshotInfo.Labels[reuseScratchLabel] + ownerKey := snapshotInfo.Labels[reuseScratchOwnerKeyLabel] + if shareScratch == "true" && ownerKey != "" { + if err = s.handleSharing(ctx, ownerKey, snDir); err != nil { + return nil, err + } + } else { + var sizeGB int + if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok { + i64, _ := strconv.ParseInt(sizeGBstr, 10, 32) + sizeGB = int(i64) + } + + scratchLocation := snapshotInfo.Labels[rootfsLocLabel] + scratchSource, err := s.openOrCreateScratch(ctx, sizeGB, scratchLocation) + if err != nil { + return nil, err + } + defer scratchSource.Close() + + // Create the sandbox.vhdx for this snapshot from the cache + destPath := filepath.Join(snDir, "sandbox.vhdx") + dest, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE, 0700) + if err != nil { + return nil, errors.Wrap(err, "failed to create sandbox.vhdx in snapshot") + } + defer dest.Close() + if _, err := io.Copy(dest, scratchSource); err != nil { + dest.Close() + os.Remove(destPath) + return nil, errors.Wrap(err, "failed to copy cached scratch.vhdx to sandbox.vhdx in snapshot") + } + } } } @@ -352,19 +403,58 @@ return s.mounts(newSnapshot), nil } -func (s *snapshotter) openOrCreateScratch(ctx context.Context) (_ *os.File, err error) { +func (s *snapshotter) handleSharing(ctx context.Context, id, snDir string) error { + var key string + if err := s.Walk(ctx, func(ctx context.Context, info snapshots.Info) error { + if strings.Contains(info.Name, id) { + key = info.Name + } + return nil + }); err != nil { + return err + } + + mounts, err := s.Mounts(ctx, key) + if err != nil { + return errors.Wrap(err, "failed to get mounts for owner snapshot") + } + + sandboxPath := filepath.Join(mounts[0].Source, "sandbox.vhdx") + linkPath := filepath.Join(snDir, "sandbox.vhdx") + if _, err := os.Stat(sandboxPath); err != nil { + return errors.Wrap(err, "failed to find sandbox.vhdx in snapshot directory") + } + + // We've found everything we need, now just make a symlink in our new snapshot to the + // sandbox.vhdx in the scratch we're asking to share. + if err := os.Symlink(sandboxPath, linkPath); err != nil { + return errors.Wrap(err, "failed to create symlink for sandbox scratch space") + } + return nil +} + +func (s *snapshotter) openOrCreateScratch(ctx context.Context, sizeGB int, scratchLoc string) (_ *os.File, err error) { // Create the scratch.vhdx cache file if it doesn't already exit. s.scratchLock.Lock() defer s.scratchLock.Unlock() - scratchFinalPath := filepath.Join(s.root, "scratch.vhdx") + vhdFileName := "scratch.vhdx" + if sizeGB > 0 { + vhdFileName = fmt.Sprintf("scratch_%d.vhdx", sizeGB) + } + + scratchFinalPath := filepath.Join(s.root, vhdFileName) + if scratchLoc != "" { + scratchFinalPath = filepath.Join(scratchLoc, vhdFileName) + } + scratchSource, err := os.OpenFile(scratchFinalPath, os.O_RDONLY, 0700) if err != nil { if !os.IsNotExist(err) { - return nil, errors.Wrap(err, "failed to open scratch.vhdx for read") + return nil, errors.Wrapf(err, "failed to open vhd %s for read", vhdFileName) } - log.G(ctx).Debug("scratch.vhdx not found, creating a new one") + log.G(ctx).Debugf("vhdx %s not found, creating a new one", vhdFileName) // Golang logic for ioutil.TempFile without the file creation r := uint32(time.Now().UnixNano() + int64(os.Getpid())) @@ -380,19 +470,26 @@ LogFormat: runhcs.JSON, Owner: "containerd", } - if err := rhcs.CreateScratch(ctx, scratchTempPath); err != nil { - _ = os.Remove(scratchTempPath) + + opt := runhcs.CreateScratchOpts{ + SizeGB: sizeGB, + } + + if err := rhcs.CreateScratchWithOpts(ctx, scratchTempPath, &opt); err != nil { + os.Remove(scratchTempPath) return nil, errors.Wrapf(err, "failed to create '%s' temp file", scratchTempName) } if err := os.Rename(scratchTempPath, scratchFinalPath); err != nil { - _ = os.Remove(scratchTempPath) + os.Remove(scratchTempPath) return nil, errors.Wrapf(err, "failed to rename '%s' temp file to 'scratch.vhdx'", scratchTempName) } scratchSource, err = os.OpenFile(scratchFinalPath, os.O_RDONLY, 0700) if err != nil { - _ = os.Remove(scratchFinalPath) + os.Remove(scratchFinalPath) return nil, errors.Wrap(err, "failed to open scratch.vhdx for read after creation") } + } else { + log.G(ctx).Debugf("scratch vhd %s was already present. Retrieved from cache", vhdFileName) } return scratchSource, nil } @@ -404,35 +501,3 @@ } return parentLayerPaths } - -// getFileSystemType obtains the type of a file system through GetVolumeInformation -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx -func getFileSystemType(path string) (fsType string, hr error) { - drive := filepath.VolumeName(path) - if len(drive) != 2 { - return "", errors.New("getFileSystemType path must start with a drive letter") - } - - var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW") - buf = make([]uint16, 255) - size = windows.MAX_PATH + 1 - ) - drive += `\` - n := uintptr(unsafe.Pointer(nil)) - r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - fsType = windows.UTF16ToString(buf) - return -} - -// win32FromHresult is a helper function to get the win32 error code from an HRESULT -func win32FromHresult(hr uintptr) uintptr { - if hr&0x1fff0000 == 0x00070000 { - return hr & 0xffff - } - return hr -} diff -Nru containerd-1.2.6/snapshots/native/native_default.go containerd-1.5.9/snapshots/native/native_default.go --- containerd-1.2.6/snapshots/native/native_default.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/native/native_default.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +// +build !freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package native + +const mountType = "bind" + +var defaultMountOptions = []string{"rbind"} diff -Nru containerd-1.2.6/snapshots/native/native_freebsd.go containerd-1.5.9/snapshots/native/native_freebsd.go --- containerd-1.2.6/snapshots/native/native_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/native/native_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package native + +const mountType = "nullfs" + +var defaultMountOptions = []string{} diff -Nru containerd-1.2.6/snapshots/native/native.go containerd-1.5.9/snapshots/native/native.go --- containerd-1.2.6/snapshots/native/native.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/native/native.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,8 +24,6 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" @@ -33,17 +31,6 @@ "github.com/pkg/errors" ) -func init() { - plugin.Register(&plugin.Registration{ - Type: plugin.SnapshotPlugin, - ID: "native", - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) - return NewSnapshotter(ic.Root) - }, - }) -} - type snapshotter struct { root string ms *storage.MetaStore @@ -232,18 +219,17 @@ } // Walk the committed snapshots. -func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (o *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, fs...) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (_ []mount.Mount, err error) { var ( - err error path, td string ) @@ -287,7 +273,15 @@ if td != "" { if len(s.ParentIDs) > 0 { parent := o.getSnapshotDir(s.ParentIDs[0]) - if err := fs.CopyDir(td, parent); err != nil { + xattrErrorHandler := func(dst, src, xattrKey string, copyErr error) error { + // security.* xattr cannot be copied in most cases (moby/buildkit#1189) + log.G(ctx).WithError(copyErr).Debugf("failed to copy xattr %q", xattrKey) + return nil + } + copyDirOpts := []fs.CopyDirOpt{ + fs.WithXAttrErrorHandler(xattrErrorHandler), + } + if err := fs.CopyDir(td, parent, copyDirOpts...); err != nil { return nil, errors.Wrap(err, "copying of parent failed") } } @@ -333,12 +327,9 @@ return []mount.Mount{ { - Source: source, - Type: "bind", - Options: []string{ - roFlag, - "rbind", - }, + Source: source, + Type: mountType, + Options: append(defaultMountOptions, roFlag), }, } } diff -Nru containerd-1.2.6/snapshots/native/plugin/plugin.go containerd-1.5.9/snapshots/native/plugin/plugin.go --- containerd-1.2.6/snapshots/native/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/native/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,54 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package plugin + +import ( + "errors" + + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/snapshots/native" +) + +// Config represents configuration for the native plugin. +type Config struct { + // Root directory for the plugin + RootPath string `toml:"root_path"` +} + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.SnapshotPlugin, + ID: "native", + Config: &Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) + + config, ok := ic.Config.(*Config) + if !ok { + return nil, errors.New("invalid native configuration") + } + + root := ic.Root + if len(config.RootPath) != 0 { + root = config.RootPath + } + + return native.NewSnapshotter(root) + }, + }) +} diff -Nru containerd-1.2.6/snapshots/overlay/check.go containerd-1.5.9/snapshots/overlay/check.go --- containerd-1.2.6/snapshots/overlay/check.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/check.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package overlay - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/mount" - "github.com/containerd/continuity/fs" - "github.com/pkg/errors" -) - -// supportsMultipleLowerDir checks if the system supports multiple lowerdirs, -// which is required for the overlay snapshotter. On 4.x kernels, multiple lowerdirs -// are always available (so this check isn't needed), and backported to RHEL and -// CentOS 3.x kernels (3.10.0-693.el7.x86_64 and up). This function is to detect -// support on those kernels, without doing a kernel version compare. -// -// Ported from moby overlay2. -func supportsMultipleLowerDir(d string) error { - td, err := ioutil.TempDir(d, "multiple-lowerdir-check") - if err != nil { - return err - } - defer func() { - if err := os.RemoveAll(td); err != nil { - log.L.WithError(err).Warnf("Failed to remove check directory %v", td) - } - }() - - for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { - if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { - return err - } - } - - opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", filepath.Join(td, "lower2"), filepath.Join(td, "lower1"), filepath.Join(td, "upper"), filepath.Join(td, "work")) - m := mount.Mount{ - Type: "overlay", - Source: "overlay", - Options: []string{opts}, - } - dest := filepath.Join(td, "merged") - if err := m.Mount(dest); err != nil { - return errors.Wrap(err, "failed to mount overlay") - } - if err := mount.UnmountAll(dest, 0); err != nil { - log.L.WithError(err).Warnf("Failed to unmount check directory %v", dest) - } - return nil -} - -// Supported returns nil when the overlayfs is functional on the system with the root directory. -// Supported is not called during plugin initialization, but exposed for downstream projects which uses -// this snapshotter as a library. -func Supported(root string) error { - if err := os.MkdirAll(root, 0700); err != nil { - return err - } - supportsDType, err := fs.SupportsDType(root) - if err != nil { - return err - } - if !supportsDType { - return fmt.Errorf("%s does not support d_type. If the backing filesystem is xfs, please reformat with ftype=1 to enable d_type support", root) - } - return supportsMultipleLowerDir(root) -} diff -Nru containerd-1.2.6/snapshots/overlay/check_test.go containerd-1.5.9/snapshots/overlay/check_test.go --- containerd-1.2.6/snapshots/overlay/check_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/check_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package overlay - -import ( - "io/ioutil" - "os" - "os/exec" - "testing" - - "github.com/containerd/containerd/pkg/testutil" - "github.com/containerd/continuity/testutil/loopback" -) - -func testOverlaySupported(t testing.TB, expected bool, mkfs ...string) { - testutil.RequiresRoot(t) - mnt, err := ioutil.TempDir("", "containerd-fs-test-supports-overlay") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(mnt) - - deviceName, cleanupDevice, err := loopback.New(100 << 20) // 100 MB - if err != nil { - t.Fatal(err) - } - if out, err := exec.Command(mkfs[0], append(mkfs[1:], deviceName)...).CombinedOutput(); err != nil { - // not fatal - cleanupDevice() - t.Skipf("could not mkfs (%v) %s: %v (out: %q)", mkfs, deviceName, err, string(out)) - } - if out, err := exec.Command("mount", deviceName, mnt).CombinedOutput(); err != nil { - // not fatal - cleanupDevice() - t.Skipf("could not mount %s: %v (out: %q)", deviceName, err, string(out)) - } - defer func() { - testutil.Unmount(t, mnt) - cleanupDevice() - }() - workload := func() { - err = Supported(mnt) - if expected && err != nil { - t.Fatal(err) - } - if !expected && err == nil { - t.Fatal("error is expected") - } - } - b, ok := t.(*testing.B) - if ok { - b.ResetTimer() - for i := 0; i < b.N; i++ { - workload() - } - b.StopTimer() - } else { - workload() - } -} - -func BenchmarkOverlaySupportedOnExt4(b *testing.B) { - testOverlaySupported(b, true, "mkfs.ext4", "-F") -} - -func BenchmarkOverlayUnsupportedOnFType0XFS(b *testing.B) { - testOverlaySupported(b, false, "mkfs.xfs", "-m", "crc=0", "-n", "ftype=0") -} - -func BenchmarkOverlaySupportedOnFType1XFS(b *testing.B) { - testOverlaySupported(b, true, "mkfs.xfs", "-m", "crc=0", "-n", "ftype=1") -} - -func BenchmarkOverlayUnsupportedOnFAT(b *testing.B) { - testOverlaySupported(b, false, "mkfs.fat") -} diff -Nru containerd-1.2.6/snapshots/overlay/overlay.go containerd-1.5.9/snapshots/overlay/overlay.go --- containerd-1.2.6/snapshots/overlay/overlay.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/overlay.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,26 +29,14 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/snapshots/overlay/overlayutils" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/continuity/fs" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) -func init() { - plugin.Register(&plugin.Registration{ - Type: plugin.SnapshotPlugin, - ID: "overlayfs", - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) - ic.Meta.Exports["root"] = ic.Root - return NewSnapshotter(ic.Root, AsynchronousRemove) - }, - }) -} - // SnapshotterConfig is used to configure the overlay snapshotter instance type SnapshotterConfig struct { asyncRemove bool @@ -70,6 +58,8 @@ root string ms *storage.MetaStore asyncRemove bool + indexOff bool + userxattr bool // whether to enable "userxattr" mount option } // NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs @@ -102,10 +92,24 @@ return nil, err } + // figure out whether "index=off" option is recognized by the kernel + var indexOff bool + if _, err = os.Stat("/sys/module/overlay/parameters/index"); err == nil { + indexOff = true + } + + // figure out whether "userxattr" option is recognized by the kernel && needed + userxattr, err := overlayutils.NeedsUserXAttr(root) + if err != nil { + logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr) + } + return &snapshotter{ root: root, ms: ms, asyncRemove: config.asyncRemove, + indexOff: indexOff, + userxattr: userxattr, }, nil } @@ -165,9 +169,8 @@ return snapshots.Usage{}, err } - upperPath := o.upperPath(id) - if info.Kind == snapshots.KindActive { + upperPath := o.upperPath(id) du, err := fs.DiskUsage(ctx, upperPath) if err != nil { // TODO(stevvooe): Consider not reporting an error in this case. @@ -282,14 +285,14 @@ return t.Commit() } -// Walk the committed snapshots. -func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +// Walk the snapshots. +func (o *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, fs...) } // Cleanup cleans up disk resources from removed or abandoned snapshots @@ -350,7 +353,7 @@ return cleanup, nil } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (_ []mount.Mount, err error) { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return nil, err @@ -426,7 +429,7 @@ } func (o *snapshotter) prepareDirectory(ctx context.Context, snapshotDir string, kind snapshots.Kind) (string, error) { - td, err := ioutil.TempDir(filepath.Join(o.root, "snapshots"), "new-") + td, err := ioutil.TempDir(snapshotDir, "new-") if err != nil { return "", errors.Wrap(err, "failed to create temp dir") } @@ -466,6 +469,15 @@ } var options []string + // set index=off when mount overlayfs + if o.indexOff { + options = append(options, "index=off") + } + + if o.userxattr { + options = append(options, "userxattr") + } + if s.Kind == snapshots.KindActive { options = append(options, fmt.Sprintf("workdir=%s", o.workPath(s.ID)), diff -Nru containerd-1.2.6/snapshots/overlay/overlay_test.go containerd-1.5.9/snapshots/overlay/overlay_test.go --- containerd-1.2.6/snapshots/overlay/overlay_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/overlay_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -30,25 +30,54 @@ "github.com/containerd/containerd/mount" "github.com/containerd/containerd/pkg/testutil" "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/snapshots/overlay/overlayutils" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/containerd/snapshots/testsuite" ) -func newSnapshotter(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { - snapshotter, err := NewSnapshotter(root) - if err != nil { - return nil, nil, err - } +func newSnapshotterWithOpts(opts ...Opt) testsuite.SnapshotterFunc { + return func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { + snapshotter, err := NewSnapshotter(root, opts...) + if err != nil { + return nil, nil, err + } - return snapshotter, func() error { return snapshotter.Close() }, nil + return snapshotter, func() error { return snapshotter.Close() }, nil + } } func TestOverlay(t *testing.T) { testutil.RequiresRoot(t) - testsuite.SnapshotterSuite(t, "Overlay", newSnapshotter) + optTestCases := map[string][]Opt{ + "no opt": nil, + // default in init() + "AsynchronousRemove": {AsynchronousRemove}, + } + + for optsName, opts := range optTestCases { + t.Run(optsName, func(t *testing.T) { + newSnapshotter := newSnapshotterWithOpts(opts...) + testsuite.SnapshotterSuite(t, "Overlay", newSnapshotter) + t.Run("TestOverlayMounts", func(t *testing.T) { + testOverlayMounts(t, newSnapshotter) + }) + t.Run("TestOverlayCommit", func(t *testing.T) { + testOverlayCommit(t, newSnapshotter) + }) + t.Run("TestOverlayOverlayMount", func(t *testing.T) { + testOverlayOverlayMount(t, newSnapshotter) + }) + t.Run("TestOverlayOverlayRead", func(t *testing.T) { + testOverlayOverlayRead(t, newSnapshotter) + }) + t.Run("TestOverlayView", func(t *testing.T) { + testOverlayView(t, newSnapshotter) + }) + }) + } } -func TestOverlayMounts(t *testing.T) { +func testOverlayMounts(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) { ctx := context.TODO() root, err := ioutil.TempDir("", "overlay") if err != nil { @@ -82,7 +111,7 @@ } } -func TestOverlayCommit(t *testing.T) { +func testOverlayCommit(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) { ctx := context.TODO() root, err := ioutil.TempDir("", "overlay") if err != nil { @@ -107,7 +136,7 @@ } } -func TestOverlayOverlayMount(t *testing.T) { +func testOverlayOverlayMount(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) { ctx := context.TODO() root, err := ioutil.TempDir("", "overlay") if err != nil { @@ -145,11 +174,21 @@ upper = "upperdir=" + filepath.Join(bp, "fs") lower = "lowerdir=" + getParents(ctx, o, root, "/tmp/layer2")[0] ) - for i, v := range []string{ + + expected := []string{ + "index=off", + } + if userxattr, err := overlayutils.NeedsUserXAttr(root); err != nil { + t.Fatal(err) + } else if userxattr { + expected = append(expected, "userxattr") + } + expected = append(expected, []string{ work, upper, lower, - } { + }...) + for i, v := range expected { if m.Options[i] != v { t.Errorf("expected %q but received %q", v, m.Options[i]) } @@ -190,7 +229,7 @@ return parents } -func TestOverlayOverlayRead(t *testing.T) { +func testOverlayOverlayRead(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) { testutil.RequiresRoot(t) ctx := context.TODO() root, err := ioutil.TempDir("", "overlay") @@ -234,7 +273,7 @@ } } -func TestOverlayView(t *testing.T) { +func testOverlayView(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) { ctx := context.TODO() root, err := ioutil.TempDir("", "overlay") if err != nil { @@ -306,12 +345,26 @@ if m.Source != "overlay" { t.Errorf("mount source should be overlay but received %q", m.Source) } - if len(m.Options) != 1 { - t.Errorf("expected 1 mount option but got %d", len(m.Options)) + + expectedOptions := 2 + userxattr, err := overlayutils.NeedsUserXAttr(root) + if err != nil { + t.Fatal(err) + } + if userxattr { + expectedOptions++ + } + + if len(m.Options) != expectedOptions { + t.Errorf("expected %d additional mount option but got %d", expectedOptions, len(m.Options)) } lowers := getParents(ctx, o, root, "/tmp/view2") expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1]) - if m.Options[0] != expected { - t.Errorf("expected option %q but received %q", expected, m.Options[0]) + optIdx := 1 + if userxattr { + optIdx++ + } + if m.Options[optIdx] != expected { + t.Errorf("expected option %q but received %q", expected, m.Options[optIdx]) } } diff -Nru containerd-1.2.6/snapshots/overlay/overlayutils/check.go containerd-1.5.9/snapshots/overlay/overlayutils/check.go --- containerd-1.2.6/snapshots/overlay/overlayutils/check.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/overlayutils/check.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,170 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package overlayutils + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/pkg/userns" + "github.com/containerd/continuity/fs" + "github.com/pkg/errors" +) + +// SupportsMultipleLowerDir checks if the system supports multiple lowerdirs, +// which is required for the overlay snapshotter. On 4.x kernels, multiple lowerdirs +// are always available (so this check isn't needed), and backported to RHEL and +// CentOS 3.x kernels (3.10.0-693.el7.x86_64 and up). This function is to detect +// support on those kernels, without doing a kernel version compare. +// +// Ported from moby overlay2. +func SupportsMultipleLowerDir(d string) error { + td, err := ioutil.TempDir(d, "multiple-lowerdir-check") + if err != nil { + return err + } + defer func() { + if err := os.RemoveAll(td); err != nil { + log.L.WithError(err).Warnf("Failed to remove check directory %v", td) + } + }() + + for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { + if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { + return err + } + } + + opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", filepath.Join(td, "lower2"), filepath.Join(td, "lower1"), filepath.Join(td, "upper"), filepath.Join(td, "work")) + m := mount.Mount{ + Type: "overlay", + Source: "overlay", + Options: []string{opts}, + } + dest := filepath.Join(td, "merged") + if err := m.Mount(dest); err != nil { + return errors.Wrap(err, "failed to mount overlay") + } + if err := mount.UnmountAll(dest, 0); err != nil { + log.L.WithError(err).Warnf("Failed to unmount check directory %v", dest) + } + return nil +} + +// Supported returns nil when the overlayfs is functional on the system with the root directory. +// Supported is not called during plugin initialization, but exposed for downstream projects which uses +// this snapshotter as a library. +func Supported(root string) error { + if err := os.MkdirAll(root, 0700); err != nil { + return err + } + supportsDType, err := fs.SupportsDType(root) + if err != nil { + return err + } + if !supportsDType { + return fmt.Errorf("%s does not support d_type. If the backing filesystem is xfs, please reformat with ftype=1 to enable d_type support", root) + } + return SupportsMultipleLowerDir(root) +} + +// NeedsUserXAttr returns whether overlayfs should be mounted with the "userxattr" mount option. +// +// The "userxattr" option is needed for mounting overlayfs inside a user namespace with kernel >= 5.11. +// +// The "userxattr" option is NOT needed for the initial user namespace (aka "the host"). +// +// Also, Ubuntu (since circa 2015) and Debian (since 10) with kernel < 5.11 can mount +// the overlayfs in a user namespace without the "userxattr" option. +// +// The corresponding kernel commit: https://github.com/torvalds/linux/commit/2d2f2d7322ff43e0fe92bf8cccdc0b09449bf2e1 +// > ovl: user xattr +// > +// > Optionally allow using "user.overlay." namespace instead of "trusted.overlay." +// > ... +// > Disable redirect_dir and metacopy options, because these would allow privilege escalation through direct manipulation of the +// > "user.overlay.redirect" or "user.overlay.metacopy" xattrs. +// > ... +// +// The "userxattr" support is not exposed in "/sys/module/overlay/parameters". +func NeedsUserXAttr(d string) (bool, error) { + if !userns.RunningInUserNS() { + // we are the real root (i.e., the root in the initial user NS), + // so we do never need "userxattr" opt. + return false, nil + } + + // TODO: add fast path for kernel >= 5.11 . + // + // Keep in mind that distro vendors might be going to backport the patch to older kernels. + // So we can't completely remove the check. + + tdRoot := filepath.Join(d, "userxattr-check") + if err := os.RemoveAll(tdRoot); err != nil { + log.L.WithError(err).Warnf("Failed to remove check directory %v", tdRoot) + } + + if err := os.MkdirAll(tdRoot, 0700); err != nil { + return false, err + } + + defer func() { + if err := os.RemoveAll(tdRoot); err != nil { + log.L.WithError(err).Warnf("Failed to remove check directory %v", tdRoot) + } + }() + + td, err := ioutil.TempDir(tdRoot, "") + if err != nil { + return false, err + } + + for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { + if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { + return false, err + } + } + + opts := []string{ + fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", filepath.Join(td, "lower2"), filepath.Join(td, "lower1"), filepath.Join(td, "upper"), filepath.Join(td, "work")), + "userxattr", + } + + m := mount.Mount{ + Type: "overlay", + Source: "overlay", + Options: opts, + } + + dest := filepath.Join(td, "merged") + if err := m.Mount(dest); err != nil { + // Probably the host is running Ubuntu/Debian kernel (< 5.11) with the userns patch but without the userxattr patch. + // Return false without error. + log.L.WithError(err).Debugf("cannot mount overlay with \"userxattr\", probably the kernel does not support userxattr") + return false, nil + } + if err := mount.UnmountAll(dest, 0); err != nil { + log.L.WithError(err).Warnf("Failed to unmount check directory %v", dest) + } + return true, nil +} diff -Nru containerd-1.2.6/snapshots/overlay/overlayutils/check_test.go containerd-1.5.9/snapshots/overlay/overlayutils/check_test.go --- containerd-1.2.6/snapshots/overlay/overlayutils/check_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/overlayutils/check_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,92 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package overlayutils + +import ( + "io/ioutil" + "os" + "os/exec" + "testing" + + "github.com/containerd/containerd/pkg/testutil" + "github.com/containerd/continuity/testutil/loopback" +) + +func testOverlaySupported(t testing.TB, expected bool, mkfs ...string) { + testutil.RequiresRoot(t) + mnt, err := ioutil.TempDir("", "containerd-fs-test-supports-overlay") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(mnt) + + loop, err := loopback.New(100 << 20) // 100 MB + if err != nil { + t.Fatal(err) + } + if out, err := exec.Command(mkfs[0], append(mkfs[1:], loop.Device)...).CombinedOutput(); err != nil { + // not fatal + loop.Close() + t.Skipf("could not mkfs (%v) %s: %v (out: %q)", mkfs, loop.Device, err, string(out)) + } + if out, err := exec.Command("mount", loop.Device, mnt).CombinedOutput(); err != nil { + // not fatal + loop.Close() + t.Skipf("could not mount %s: %v (out: %q)", loop.Device, err, string(out)) + } + defer func() { + testutil.Unmount(t, mnt) + loop.Close() + }() + workload := func() { + err = Supported(mnt) + if expected && err != nil { + t.Fatal(err) + } + if !expected && err == nil { + t.Fatal("error is expected") + } + } + b, ok := t.(*testing.B) + if ok { + b.ResetTimer() + for i := 0; i < b.N; i++ { + workload() + } + b.StopTimer() + } else { + workload() + } +} + +func BenchmarkOverlaySupportedOnExt4(b *testing.B) { + testOverlaySupported(b, true, "mkfs.ext4", "-F") +} + +func BenchmarkOverlayUnsupportedOnFType0XFS(b *testing.B) { + testOverlaySupported(b, false, "mkfs.xfs", "-m", "crc=0", "-n", "ftype=0") +} + +func BenchmarkOverlaySupportedOnFType1XFS(b *testing.B) { + testOverlaySupported(b, true, "mkfs.xfs", "-m", "crc=0", "-n", "ftype=1") +} + +func BenchmarkOverlayUnsupportedOnFAT(b *testing.B) { + testOverlaySupported(b, false, "mkfs.fat") +} diff -Nru containerd-1.2.6/snapshots/overlay/plugin/plugin.go containerd-1.5.9/snapshots/overlay/plugin/plugin.go --- containerd-1.2.6/snapshots/overlay/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshots/overlay/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package overlay + +import ( + "errors" + + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/snapshots/overlay" +) + +// Config represents configuration for the overlay plugin. +type Config struct { + // Root directory for the plugin + RootPath string `toml:"root_path"` +} + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.SnapshotPlugin, + ID: "overlayfs", + Config: &Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) + + config, ok := ic.Config.(*Config) + if !ok { + return nil, errors.New("invalid overlay configuration") + } + + root := ic.Root + if config.RootPath != "" { + root = config.RootPath + } + + ic.Meta.Exports["root"] = root + return overlay.NewSnapshotter(root, overlay.AsynchronousRemove) + }, + }) +} diff -Nru containerd-1.2.6/snapshots/proxy/proxy.go containerd-1.5.9/snapshots/proxy/proxy.go --- containerd-1.2.6/snapshots/proxy/proxy.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/proxy/proxy.go 2022-01-05 17:30:58.000000000 +0000 @@ -153,9 +153,10 @@ return errdefs.FromGRPC(err) } -func (p *proxySnapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (p *proxySnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { sc, err := p.client.List(ctx, &snapshotsapi.ListSnapshotsRequest{ Snapshotter: p.snapshotterName, + Filters: fs, }) if err != nil { return errdefs.FromGRPC(err) @@ -183,6 +184,13 @@ return nil } +func (p *proxySnapshotter) Cleanup(ctx context.Context) error { + _, err := p.client.Cleanup(ctx, &snapshotsapi.CleanupRequest{ + Snapshotter: p.snapshotterName, + }) + return errdefs.FromGRPC(err) +} + func toKind(kind snapshotsapi.Kind) snapshots.Kind { if kind == snapshotsapi.KindActive { return snapshots.KindActive diff -Nru containerd-1.2.6/snapshots/snapshotter.go containerd-1.5.9/snapshots/snapshotter.go --- containerd-1.2.6/snapshots/snapshotter.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/snapshotter.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,6 +25,16 @@ "github.com/containerd/containerd/mount" ) +const ( + // UnpackKeyPrefix is the beginning of the key format used for snapshots that will have + // image content unpacked into them. + UnpackKeyPrefix = "extract" + // UnpackKeyFormat is the format for the snapshotter keys used for extraction + UnpackKeyFormat = UnpackKeyPrefix + "-%s %s" + inheritedLabelsPrefix = "containerd.io/snapshot/" + labelSnapshotRef = "containerd.io/snapshot.ref" +) + // Kind identifies the kind of snapshot. type Kind uint8 @@ -86,10 +96,15 @@ // Info provides information about a particular snapshot. // JSON marshallability is supported for interactive with tools like ctr, type Info struct { - Kind Kind // active or committed snapshot - Name string // name or key of snapshot - Parent string `json:",omitempty"` // name of parent snapshot - Labels map[string]string `json:",omitempty"` // Labels for snapshot + Kind Kind // active or committed snapshot + Name string // name or key of snapshot + Parent string `json:",omitempty"` // name of parent snapshot + + // Labels for a snapshot. + // + // Note: only labels prefixed with `containerd.io/snapshot/` will be inherited by the + // snapshotter's `Prepare`, `View`, or `Commit` calls. + Labels map[string]string `json:",omitempty"` Created time.Time `json:",omitempty"` // Created time Updated time.Time `json:",omitempty"` // Last update time } @@ -113,6 +128,9 @@ u.Inodes += other.Inodes } +// WalkFunc defines the callback for a snapshot walk. +type WalkFunc func(context.Context, Info) error + // Snapshotter defines the methods required to implement a snapshot snapshotter for // allocating, snapshotting and mounting filesystem changesets. The model works // by building up sets of changes with parent-child relationships. @@ -160,9 +178,13 @@ // layerPath, tmpDir := getLayerPath(), mkTmpDir() // just a path to layer tar file. // // We start by using a Snapshotter to Prepare a new snapshot transaction, using a -// key and descending from the empty parent "": +// key and descending from the empty parent "". To prevent our layer from being +// garbage collected during unpacking, we add the `containerd.io/gc.root` label: // -// mounts, err := snapshotter.Prepare(ctx, key, "") +// noGcOpt := snapshots.WithLabels(map[string]string{ +// "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339), +// }) +// mounts, err := snapshotter.Prepare(ctx, key, "", noGcOpt) // if err != nil { ... } // // We get back a list of mounts from Snapshotter.Prepare, with the key identifying @@ -191,15 +213,13 @@ // // Now that we've verified and unpacked our layer, we commit the active // snapshot to a name. For this example, we are just going to use the layer -// digest, but in practice, this will probably be the ChainID: +// digest, but in practice, this will probably be the ChainID. This also removes +// the active snapshot: // -// if err := snapshotter.Commit(ctx, digest.String(), key); err != nil { ... } +// if err := snapshotter.Commit(ctx, digest.String(), key, noGcOpt); err != nil { ... } // // Now, we have a layer in the Snapshotter that can be accessed with the digest -// provided during commit. Once you have committed the snapshot, the active -// snapshot can be removed with the following: -// -// snapshotter.Remove(ctx, key) +// provided during commit. // // Importing the Next Layer // @@ -207,7 +227,7 @@ // above except that the parent is provided as parent when calling // Manager.Prepare, assuming a clean, unique key identifier: // -// mounts, err := snapshotter.Prepare(ctx, key, parentDigest) +// mounts, err := snapshotter.Prepare(ctx, key, parentDigest, noGcOpt) // // We then mount, apply and commit, as we did above. The new snapshot will be // based on the content of the previous one. @@ -307,9 +327,15 @@ // removed before proceeding. Remove(ctx context.Context, key string) error - // Walk all snapshots in the snapshotter. For each snapshot in the - // snapshotter, the function will be called. - Walk(ctx context.Context, fn func(context.Context, Info) error) error + // Walk will call the provided function for each snapshot in the + // snapshotter which match the provided filters. If no filters are + // given all items will be walked. + // Filters: + // name + // parent + // kind (active,view,committed) + // labels.(label) + Walk(ctx context.Context, fn WalkFunc, filters ...string) error // Close releases the internal resources. // @@ -320,13 +346,48 @@ Close() error } +// Cleaner defines a type capable of performing asynchronous resource cleanup. +// The Cleaner interface should be used by snapshotters which implement fast +// removal and deferred resource cleanup. This prevents snapshots from needing +// to perform lengthy resource cleanup before acknowledging a snapshot key +// has been removed and available for re-use. This is also useful when +// performing multi-key removal with the intent of cleaning up all the +// resources after each snapshot key has been removed. +type Cleaner interface { + Cleanup(ctx context.Context) error +} + // Opt allows setting mutable snapshot properties on creation type Opt func(info *Info) error -// WithLabels adds labels to a created snapshot +// WithLabels appends labels to a created snapshot func WithLabels(labels map[string]string) Opt { return func(info *Info) error { - info.Labels = labels + if info.Labels == nil { + info.Labels = make(map[string]string) + } + + for k, v := range labels { + info.Labels[k] = v + } + return nil } } + +// FilterInheritedLabels filters the provided labels by removing any key which +// isn't a snapshot label. Snapshot labels have a prefix of "containerd.io/snapshot/" +// or are the "containerd.io/snapshot.ref" label. +func FilterInheritedLabels(labels map[string]string) map[string]string { + if labels == nil { + return nil + } + + filtered := make(map[string]string) + for k, v := range labels { + if k == labelSnapshotRef || strings.HasPrefix(k, inheritedLabelsPrefix) { + filtered[k] = v + } + } + return filtered +} diff -Nru containerd-1.2.6/snapshots/storage/bolt.go containerd-1.5.9/snapshots/storage/bolt.go --- containerd-1.2.6/snapshots/storage/bolt.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/storage/bolt.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,6 +24,7 @@ "time" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/filters" "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/snapshots" "github.com/pkg/errors" @@ -144,7 +145,12 @@ // WalkInfo iterates through all metadata Info for the stored snapshots and // calls the provided function for each. Requires a context with a storage // transaction. -func WalkInfo(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func WalkInfo(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { + filter, err := filters.ParseAll(fs...) + if err != nil { + return err + } + // TODO: allow indexes (name, parent, specific labels) return withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { return bkt.ForEach(func(k, v []byte) error { // skip non buckets @@ -160,6 +166,9 @@ if err := readSnapshot(sbkt, nil, &si); err != nil { return err } + if !filter.Match(adaptSnapshot(si)) { + return nil + } return fn(ctx, si) }) @@ -297,7 +306,7 @@ } if err := readSnapshot(sbkt, &id, &si); err != nil { - errors.Wrapf(err, "failed to read snapshot %s", key) + return errors.Wrapf(err, "failed to read snapshot %s", key) } if pbkt != nil { @@ -604,3 +613,36 @@ } return idEncoded, nil } + +func adaptSnapshot(info snapshots.Info) filters.Adaptor { + return filters.AdapterFunc(func(fieldpath []string) (string, bool) { + if len(fieldpath) == 0 { + return "", false + } + + switch fieldpath[0] { + case "kind": + switch info.Kind { + case snapshots.KindActive: + return "active", true + case snapshots.KindView: + return "view", true + case snapshots.KindCommitted: + return "committed", true + } + case "name": + return info.Name, true + case "parent": + return info.Parent, true + case "labels": + if len(info.Labels) == 0 { + return "", false + } + + v, ok := info.Labels[strings.Join(fieldpath[1:], ".")] + return v, ok + } + + return "", false + }) +} diff -Nru containerd-1.2.6/snapshots/storage/metastore_test.go containerd-1.5.9/snapshots/storage/metastore_test.go --- containerd-1.2.6/snapshots/storage/metastore_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/storage/metastore_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,8 +28,8 @@ "github.com/containerd/containerd/snapshots" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" - "gotest.tools/assert" - is "gotest.tools/assert/cmp" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) type testFunc func(context.Context, *testing.T, *MetaStore) @@ -261,7 +261,7 @@ // actual value should be within a few seconds of now now := time.Now() delta := now.Sub(actual) - threshold := 10 * time.Second + threshold := 30 * time.Second return delta > -threshold && delta < threshold })) diff -Nru containerd-1.2.6/snapshots/testsuite/testsuite.go containerd-1.5.9/snapshots/testsuite/testsuite.go --- containerd-1.2.6/snapshots/testsuite/testsuite.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/testsuite/testsuite.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,26 +18,33 @@ import ( "context" + //nolint:golint + _ "crypto/sha256" "fmt" "io/ioutil" "math/rand" "os" "path/filepath" + "sort" "testing" "time" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log/logtest" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/pkg/testutil" "github.com/containerd/containerd/snapshots" "github.com/containerd/continuity/fs/fstest" - "gotest.tools/assert" - is "gotest.tools/assert/cmp" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) +// SnapshotterFunc is used in SnapshotterSuite +type SnapshotterFunc func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) + // SnapshotterSuite runs a test suite on the snapshotter given a factory function. -func SnapshotterSuite(t *testing.T, name string, snapshotterFn func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error)) { +func SnapshotterSuite(t *testing.T, name string, snapshotterFn SnapshotterFunc) { restoreMask := clearMask() defer restoreMask() @@ -48,6 +55,7 @@ t.Run("PreareViewFailingtest", makeTest(name, snapshotterFn, checkSnapshotterPrepareView)) t.Run("Update", makeTest(name, snapshotterFn, checkUpdate)) t.Run("Remove", makeTest(name, snapshotterFn, checkRemove)) + t.Run("Walk", makeTest(name, snapshotterFn, checkWalk)) t.Run("LayerFileupdate", makeTest(name, snapshotterFn, checkLayerFileUpdate)) t.Run("RemoveDirectoryInLowerLayer", makeTest(name, snapshotterFn, checkRemoveDirectoryInLowerLayer)) @@ -64,14 +72,14 @@ t.Run("CloseTwice", makeTest(name, snapshotterFn, closeTwice)) t.Run("RootPermission", makeTest(name, snapshotterFn, checkRootPermission)) - t.Run("128LayersMount", makeTest(name, snapshotterFn, check128LayersMount)) + t.Run("128LayersMount", makeTest(name, snapshotterFn, check128LayersMount(name))) } func makeTest(name string, snapshotterFn func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error), fn func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string)) func(t *testing.T) { return func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := logtest.WithT(context.Background(), t) ctx = namespaces.WithNamespace(ctx, "testsuite") // Make two directories: a snapshotter root and a play area for the tests: // @@ -149,11 +157,12 @@ if err := mount.All(mounts, preparing); err != nil { t.Fatalf("failure reason: %+v", err) } - defer testutil.Unmount(t, preparing) if err := initialApplier.Apply(preparing); err != nil { t.Fatalf("failure reason: %+v", err) } + // unmount before commit + testutil.Unmount(t, preparing) committed := filepath.Join(work, "committed") if err := snapshotter.Commit(ctx, committed, preparing, opt); err != nil { @@ -185,7 +194,6 @@ if err := mount.All(mounts, next); err != nil { t.Fatalf("failure reason: %+v", err) } - defer testutil.Unmount(t, next) if err := fstest.CheckDirectoryEqualWithApplier(next, initialApplier); err != nil { t.Fatalf("failure reason: %+v", err) @@ -194,6 +202,8 @@ if err := diffApplier.Apply(next); err != nil { t.Fatalf("failure reason: %+v", err) } + // unmount before commit + testutil.Unmount(t, next) ni, err := snapshotter.Stat(ctx, next) if err != nil { @@ -498,7 +508,6 @@ if err != nil { t.Fatal(err) } - defer testutil.Unmount(t, base) committedBase := filepath.Join(work, "committed-base") if err = snapshotter.Commit(ctx, committedBase, base, opt); err != nil { @@ -537,6 +546,7 @@ if err != nil { t.Fatal(err) } + testutil.Unmount(t, base) err = snapshotter.Remove(ctx, committedBase) if err != nil { t.Fatal(err) @@ -863,93 +873,230 @@ } } -func check128LayersMount(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) { - lowestApply := fstest.Apply( - fstest.CreateFile("/bottom", []byte("way at the bottom\n"), 0777), - fstest.CreateFile("/overwriteme", []byte("FIRST!\n"), 0777), - fstest.CreateDir("/ADDHERE", 0755), - fstest.CreateDir("/ONLYME", 0755), - fstest.CreateFile("/ONLYME/bottom", []byte("bye!\n"), 0777), - ) - - appliers := []fstest.Applier{lowestApply} - for i := 1; i <= 127; i++ { - appliers = append(appliers, fstest.Apply( - fstest.CreateFile("/overwriteme", []byte(fmt.Sprintf("%d WAS HERE!\n", i)), 0777), - fstest.CreateFile(fmt.Sprintf("/ADDHERE/file-%d", i), []byte("same\n"), 0755), - fstest.RemoveAll("/ONLYME"), +func check128LayersMount(name string) func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) { + return func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) { + if name == "Aufs" { + t.Skip("aufs tests have issues with whiteouts here on some CI kernels") + } + lowestApply := fstest.Apply( + fstest.CreateFile("/bottom", []byte("way at the bottom\n"), 0777), + fstest.CreateFile("/overwriteme", []byte("FIRST!\n"), 0777), + fstest.CreateDir("/ADDHERE", 0755), fstest.CreateDir("/ONLYME", 0755), - fstest.CreateFile(fmt.Sprintf("/ONLYME/file-%d", i), []byte("only me!\n"), 0777), - )) - } + fstest.CreateFile("/ONLYME/bottom", []byte("bye!\n"), 0777), + ) - flat := filepath.Join(work, "flat") - if err := os.MkdirAll(flat, 0777); err != nil { - t.Fatalf("failed to create flat dir(%s): %+v", flat, err) - } + appliers := []fstest.Applier{lowestApply} + for i := 1; i <= 127; i++ { + appliers = append(appliers, fstest.Apply( + fstest.CreateFile("/overwriteme", []byte(fmt.Sprintf("%d WAS HERE!\n", i)), 0777), + fstest.CreateFile(fmt.Sprintf("/ADDHERE/file-%d", i), []byte("same\n"), 0755), + fstest.RemoveAll("/ONLYME"), + fstest.CreateDir("/ONLYME", 0755), + fstest.CreateFile(fmt.Sprintf("/ONLYME/file-%d", i), []byte("only me!\n"), 0777), + )) + } + + flat := filepath.Join(work, "flat") + if err := os.MkdirAll(flat, 0777); err != nil { + t.Fatalf("failed to create flat dir(%s): %+v", flat, err) + } + + // NOTE: add gc labels to avoid snapshots get removed by gc... + parent := "" + for i, applier := range appliers { + preparing := filepath.Join(work, fmt.Sprintf("prepare-layer-%d", i)) + if err := os.MkdirAll(preparing, 0777); err != nil { + t.Fatalf("[layer %d] failed to create preparing dir(%s): %+v", i, preparing, err) + } - // NOTE: add gc labels to avoid snapshots get removed by gc... - parent := "" - for i, applier := range appliers { - preparing := filepath.Join(work, fmt.Sprintf("prepare-layer-%d", i)) - if err := os.MkdirAll(preparing, 0777); err != nil { - t.Fatalf("[layer %d] failed to create preparing dir(%s): %+v", i, preparing, err) - } + mounts, err := snapshotter.Prepare(ctx, preparing, parent, opt) + if err != nil { + t.Fatalf("[layer %d] failed to get mount info: %+v", i, err) + } - mounts, err := snapshotter.Prepare(ctx, preparing, parent, opt) - if err != nil { - t.Fatalf("[layer %d] failed to get mount info: %+v", i, err) - } + if err := mount.All(mounts, preparing); err != nil { + t.Fatalf("[layer %d] failed to mount on the target(%s): %+v", i, preparing, err) + } - if err := mount.All(mounts, preparing); err != nil { - t.Fatalf("[layer %d] failed to mount on the target(%s): %+v", i, preparing, err) - } + if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil { + testutil.Unmount(t, preparing) + t.Fatalf("[layer %d] preparing doesn't equal to flat before apply: %+v", i, err) + } - if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil { - testutil.Unmount(t, preparing) - t.Fatalf("[layer %d] preparing doesn't equal to flat before apply: %+v", i, err) - } + if err := applier.Apply(flat); err != nil { + testutil.Unmount(t, preparing) + t.Fatalf("[layer %d] failed to apply on flat dir: %+v", i, err) + } + + if err = applier.Apply(preparing); err != nil { + testutil.Unmount(t, preparing) + t.Fatalf("[layer %d] failed to apply on preparing dir: %+v", i, err) + } + + if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil { + testutil.Unmount(t, preparing) + t.Fatalf("[layer %d] preparing doesn't equal to flat after apply: %+v", i, err) + } - if err := applier.Apply(flat); err != nil { testutil.Unmount(t, preparing) - t.Fatalf("[layer %d] failed to apply on flat dir: %+v", i, err) + + parent = filepath.Join(work, fmt.Sprintf("committed-%d", i)) + if err := snapshotter.Commit(ctx, parent, preparing, opt); err != nil { + t.Fatalf("[layer %d] failed to commit the preparing: %+v", i, err) + } + } - if err = applier.Apply(preparing); err != nil { - testutil.Unmount(t, preparing) - t.Fatalf("[layer %d] failed to apply on preparing dir: %+v", i, err) + view := filepath.Join(work, "fullview") + if err := os.MkdirAll(view, 0777); err != nil { + t.Fatalf("failed to create fullview dir(%s): %+v", view, err) } - if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil { - testutil.Unmount(t, preparing) - t.Fatalf("[layer %d] preparing doesn't equal to flat after apply: %+v", i, err) + mounts, err := snapshotter.View(ctx, view, parent, opt) + if err != nil { + t.Fatalf("failed to get view's mount info: %+v", err) } - testutil.Unmount(t, preparing) + if err := mount.All(mounts, view); err != nil { + t.Fatalf("failed to mount on the target(%s): %+v", view, err) + } + defer testutil.Unmount(t, view) - parent = filepath.Join(work, fmt.Sprintf("committed-%d", i)) - if err := snapshotter.Commit(ctx, parent, preparing, opt); err != nil { - t.Fatalf("[layer %d] failed to commit the preparing: %+v", i, err) + if err := fstest.CheckDirectoryEqual(view, flat); err != nil { + t.Fatalf("fullview should equal to flat: %+v", err) } + } +} +func checkWalk(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) { + opt := snapshots.WithLabels(map[string]string{ + "containerd.io/gc.root": "check-walk", + }) + + // No parent active + if _, err := snapshotter.Prepare(ctx, "a-np", "", opt); err != nil { + t.Fatal(err) + } + + // Base parent + if _, err := snapshotter.Prepare(ctx, "p-tmp", "", opt); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "p", "p-tmp", opt); err != nil { + t.Fatal(err) } - view := filepath.Join(work, "fullview") - if err := os.MkdirAll(view, 0777); err != nil { - t.Fatalf("failed to create fullview dir(%s): %+v", view, err) + // Active + if _, err := snapshotter.Prepare(ctx, "a", "p", opt); err != nil { + t.Fatal(err) } - mounts, err := snapshotter.View(ctx, view, parent, opt) - if err != nil { - t.Fatalf("failed to get view's mount info: %+v", err) + // View + if _, err := snapshotter.View(ctx, "v", "p", opt); err != nil { + t.Fatal(err) } - if err := mount.All(mounts, view); err != nil { - t.Fatalf("failed to mount on the target(%s): %+v", view, err) + // Base parent with label=1 + if _, err := snapshotter.Prepare(ctx, "p-wl-tmp", "", opt); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "p-wl", "p-wl-tmp", snapshots.WithLabels(map[string]string{ + "l": "1", + "containerd.io/gc.root": "check-walk", + })); err != nil { + t.Fatal(err) + } + + // active with label=2 + if _, err := snapshotter.Prepare(ctx, "a-wl", "p-wl", snapshots.WithLabels(map[string]string{ + "l": "2", + "containerd.io/gc.root": "check-walk", + })); err != nil { + t.Fatal(err) } - defer testutil.Unmount(t, view) - if err := fstest.CheckDirectoryEqual(view, flat); err != nil { - t.Fatalf("fullview should equal to flat: %+v", err) + // view with label=3 + if _, err := snapshotter.View(ctx, "v-wl", "p-wl", snapshots.WithLabels(map[string]string{ + "l": "3", + "containerd.io/gc.root": "check-walk", + })); err != nil { + t.Fatal(err) + } + + // no parent active with label=2 + if _, err := snapshotter.Prepare(ctx, "a-np-wl", "", snapshots.WithLabels(map[string]string{ + "l": "2", + "containerd.io/gc.root": "check-walk", + })); err != nil { + t.Fatal(err) + } + + for i, tc := range []struct { + matches []string + filters []string + }{ + { + matches: []string{"a-np", "p", "a", "v", "p-wl", "a-wl", "v-wl", "a-np-wl"}, + filters: []string{"labels.\"containerd.io/gc.root\"==check-walk"}, + }, + { + matches: []string{"a-np", "a", "a-wl", "a-np-wl"}, + filters: []string{"kind==active,labels.\"containerd.io/gc.root\"==check-walk"}, + }, + { + matches: []string{"v", "v-wl"}, + filters: []string{"kind==view,labels.\"containerd.io/gc.root\"==check-walk"}, + }, + { + matches: []string{"p", "p-wl"}, + filters: []string{"kind==committed,labels.\"containerd.io/gc.root\"==check-walk"}, + }, + { + matches: []string{"p", "a-np-wl"}, + filters: []string{"name==p", "name==a-np-wl"}, + }, + { + matches: []string{"a-wl"}, + filters: []string{"name==a-wl,labels.l"}, + }, + { + matches: []string{"a", "v"}, + filters: []string{"parent==p"}, + }, + { + matches: []string{"a", "v", "a-wl", "v-wl"}, + filters: []string{"parent!=\"\",labels.\"containerd.io/gc.root\"==check-walk"}, + }, + { + matches: []string{"p-wl", "a-wl", "v-wl", "a-np-wl"}, + filters: []string{"labels.l"}, + }, + { + matches: []string{"a-wl", "a-np-wl"}, + filters: []string{"labels.l==2"}, + }, + } { + actual := []string{} + err := snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error { + actual = append(actual, si.Name) + return nil + }, tc.filters...) + if err != nil { + t.Fatal(err) + } + + sort.Strings(tc.matches) + sort.Strings(actual) + if len(actual) != len(tc.matches) { + t.Errorf("[%d] Unexpected result (size):\nActual:\n\t%#v\nExpected:\n\t%#v", i, actual, tc.matches) + continue + } + for j := range actual { + if actual[j] != tc.matches[j] { + t.Errorf("[%d] Unexpected result @%d:\nActual:\n\t%#vExpected:\n\t%#v", i, j, actual, tc.matches) + break + } + } } } diff -Nru containerd-1.2.6/snapshots/windows/windows.go containerd-1.5.9/snapshots/windows/windows.go --- containerd-1.2.6/snapshots/windows/windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshots/windows/windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,23 +21,29 @@ import ( "context" "encoding/json" + "fmt" + "io" + "io/ioutil" "os" "path/filepath" + "strconv" "strings" - "syscall" - "unsafe" - "github.com/Microsoft/go-winio/vhd" + "github.com/Microsoft/go-winio" + winfs "github.com/Microsoft/go-winio/pkg/fs" "github.com/Microsoft/hcsshim" + "github.com/Microsoft/hcsshim/computestorage" + "github.com/Microsoft/hcsshim/pkg/ociwclayer" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/continuity/fs" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" - "golang.org/x/sys/windows" ) func init() { @@ -45,11 +51,19 @@ Type: plugin.SnapshotPlugin, ID: "windows", InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = []ocispec.Platform{platforms.DefaultSpec()} return NewSnapshotter(ic.Root) }, }) } +const ( + // Label to specify that we should make a scratch space for a UtilityVM. + uvmScratchLabel = "containerd.io/snapshot/io.microsoft.vm.storage.scratch" + // Label to control a containers scratch space size (sandbox.vhdx). + rootfsSizeLabel = "containerd.io/snapshot/io.microsoft.container.storage.rootfs.size-gb" +) + type snapshotter struct { root string info hcsshim.DriverInfo @@ -58,7 +72,7 @@ // NewSnapshotter returns a new windows snapshotter func NewSnapshotter(root string) (snapshots.Snapshotter, error) { - fsType, err := getFileSystemType(root) + fsType, err := winfs.GetFileSystemType(root) if err != nil { return nil, err } @@ -127,17 +141,20 @@ if err != nil { return snapshots.Usage{}, err } - defer t.Rollback() + id, info, usage, err := storage.GetInfo(ctx, key) + t.Rollback() // transaction no longer needed at this point. - _, info, usage, err := storage.GetInfo(ctx, key) if err != nil { return snapshots.Usage{}, err } if info.Kind == snapshots.KindActive { - du := fs.Usage{ - Size: 0, + path := s.getSnapshotDir(id) + du, err := fs.DiskUsage(ctx, path) + if err != nil { + return snapshots.Usage{}, err } + usage = snapshots.Usage(du) } @@ -170,25 +187,50 @@ return s.mounts(snapshot), nil } -func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { +func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) (retErr error) { ctx, t, err := s.ms.TransactionContext(ctx, true) if err != nil { return err } - defer t.Rollback() - usage := fs.Usage{ - Size: 0, - } + defer func() { + if retErr != nil { + if rerr := t.Rollback(); rerr != nil { + log.G(ctx).WithError(rerr).Warn("failed to rollback transaction") + } + } + }() - if _, err = storage.CommitActive(ctx, key, name, snapshots.Usage(usage), opts...); err != nil { - return errors.Wrap(err, "failed to commit snapshot") + // grab the existing id + id, _, _, err := storage.GetInfo(ctx, key) + if err != nil { + return errors.Wrapf(err, "failed to get storage info for %s", key) } - if err := t.Commit(); err != nil { + snapshot, err := storage.GetSnapshot(ctx, key) + if err != nil { return err } - return nil + + path := s.getSnapshotDir(id) + + // If (windowsDiff).Apply was used to populate this layer, then it's already in the 'committed' state. + // See createSnapshot below for more details + if !strings.Contains(key, snapshots.UnpackKeyPrefix) { + if err := s.convertScratchToReadOnlyLayer(ctx, snapshot, path); err != nil { + return err + } + } + + usage, err := fs.DiskUsage(ctx, path) + if err != nil { + return errors.Wrapf(err, "failed to collect disk usage of snapshot storage: %s", path) + } + + if _, err := storage.CommitActive(ctx, key, name, snapshots.Usage(usage), opts...); err != nil { + return errors.Wrap(err, "failed to commit snapshot") + } + return t.Commit() } // Remove abandons the transaction identified by key. All resources @@ -213,11 +255,19 @@ return err } // If permission denied, it's possible that the scratch is still mounted, an - // artifact after a hard daemon crash for example. Worth a shot to try detaching it + // artifact after a hard daemon crash for example. Worth a shot to try deactivating it // before retrying the rename. - if detachErr := vhd.DetachVhd(filepath.Join(path, "sandbox.vhdx")); detachErr != nil { - return errors.Wrapf(err, "failed to detach VHD: %s", detachErr) + var ( + home, layerID = filepath.Split(path) + di = hcsshim.DriverInfo{ + HomeDir: home, + } + ) + + if deactivateErr := hcsshim.DeactivateLayer(di, layerID); deactivateErr != nil { + return errors.Wrapf(err, "failed to deactivate layer following failed rename: %s", deactivateErr) } + if renameErr := os.Rename(path, renamed); renameErr != nil && !os.IsNotExist(renameErr) { return errors.Wrapf(err, "second rename attempt following detach failed: %s", renameErr) } @@ -240,14 +290,14 @@ } // Walk the committed snapshots. -func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (s *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := s.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, fs...) } // Close closes the snapshotter @@ -310,18 +360,51 @@ } if kind == snapshots.KindActive { - parentLayerPaths := s.parentIDsToParentPaths(newSnapshot.ParentIDs) - - var parentPath string - if len(parentLayerPaths) != 0 { - parentPath = parentLayerPaths[0] + log.G(ctx).Debug("createSnapshot active") + // Create the new snapshot dir + snDir := s.getSnapshotDir(newSnapshot.ID) + if err := os.MkdirAll(snDir, 0700); err != nil { + return nil, err } - if err := hcsshim.CreateSandboxLayer(s.info, newSnapshot.ID, parentPath, parentLayerPaths); err != nil { - return nil, errors.Wrap(err, "failed to create sandbox layer") + // IO/disk space optimization + // + // We only need one sandbox.vhdx for the container. Skip making one for this + // snapshot if this isn't the snapshot that just houses the final sandbox.vhd + // that will be mounted as the containers scratch. Currently the key for a snapshot + // where a layer will be extracted to will have the string `extract-` in it. + if !strings.Contains(key, snapshots.UnpackKeyPrefix) { + parentLayerPaths := s.parentIDsToParentPaths(newSnapshot.ParentIDs) + + var snapshotInfo snapshots.Info + for _, o := range opts { + o(&snapshotInfo) + } + + var sizeGB int + if sizeGBstr, ok := snapshotInfo.Labels[rootfsSizeLabel]; ok { + i32, err := strconv.ParseInt(sizeGBstr, 10, 32) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse label %q=%q", rootfsSizeLabel, sizeGBstr) + } + sizeGB = int(i32) + } + + var makeUVMScratch bool + if _, ok := snapshotInfo.Labels[uvmScratchLabel]; ok { + makeUVMScratch = true + } + + // This has to be run first to avoid clashing with the containers sandbox.vhdx. + if makeUVMScratch { + if err := s.createUVMScratchLayer(ctx, snDir, parentLayerPaths); err != nil { + return nil, errors.Wrap(err, "failed to make UVM's scratch layer") + } + } + if err := s.createScratchLayer(ctx, snDir, parentLayerPaths, sizeGB); err != nil { + return nil, errors.Wrap(err, "failed to create scratch layer") + } } - - // TODO(darrenstahlmsft): Allow changing sandbox size } if err := t.Commit(); err != nil { @@ -339,34 +422,136 @@ return parentLayerPaths } -// getFileSystemType obtains the type of a file system through GetVolumeInformation -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx -func getFileSystemType(path string) (fsType string, hr error) { - drive := filepath.VolumeName(path) - if len(drive) != 2 { - return "", errors.New("getFileSystemType path must start with a drive letter") +// This is essentially a recreation of what HCS' CreateSandboxLayer does with some extra bells and +// whistles like expanding the volume if a size is specified. This will create a 1GB scratch +// vhdx to be used if a different sized scratch that is not equal to the default of 20 is requested. +func (s *snapshotter) createScratchLayer(ctx context.Context, snDir string, parentLayers []string, sizeGB int) error { + parentLen := len(parentLayers) + if parentLen == 0 { + return errors.New("no parent layers present") } + baseLayer := parentLayers[parentLen-1] var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW") - buf = make([]uint16, 255) - size = windows.MAX_PATH + 1 + templateBase = filepath.Join(baseLayer, "blank-base.vhdx") + templateDiffDisk = filepath.Join(baseLayer, "blank.vhdx") + newDisks = sizeGB > 0 && sizeGB < 20 + expand = sizeGB > 0 && sizeGB != 20 ) - drive += `\` - n := uintptr(unsafe.Pointer(nil)) - r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0) - if int32(r0) < 0 { - hr = syscall.Errno(win32FromHresult(r0)) - } - fsType = windows.UTF16ToString(buf) - return -} - -// win32FromHresult is a helper function to get the win32 error code from an HRESULT -func win32FromHresult(hr uintptr) uintptr { - if hr&0x1fff0000 == 0x00070000 { - return hr & 0xffff + + // If a size greater than 0 and less than 20 (the default size produced by hcs) + // was specified we make a new set of disks to be used. We make it a 1GB disk and just + // expand it to the size specified so for future container runs we don't need to remake a disk. + if newDisks { + templateBase = filepath.Join(baseLayer, "scratch.vhdx") + templateDiffDisk = filepath.Join(baseLayer, "scratch-diff.vhdx") + } + + if _, err := os.Stat(templateDiffDisk); os.IsNotExist(err) { + // Scratch disk not present so lets make it. + if err := computestorage.SetupContainerBaseLayer(ctx, baseLayer, templateBase, templateDiffDisk, 1); err != nil { + return errors.Wrapf(err, "failed to create scratch vhdx at %q", baseLayer) + } + } + + dest := filepath.Join(snDir, "sandbox.vhdx") + if err := copyScratchDisk(templateDiffDisk, dest); err != nil { + return err + } + + if expand { + gbToByte := 1024 * 1024 * 1024 + if err := hcsshim.ExpandSandboxSize(s.info, filepath.Base(snDir), uint64(gbToByte*sizeGB)); err != nil { + return errors.Wrapf(err, "failed to expand sandbox vhdx size to %d GB", sizeGB) + } + } + return nil +} + +// convertScratchToReadOnlyLayer reimporst the layer over itself, to transfer the files from the sandbox.vhdx to the on-disk storage. +func (s *snapshotter) convertScratchToReadOnlyLayer(ctx context.Context, snapshot storage.Snapshot, path string) (retErr error) { + + // TODO darrenstahlmsft: When this is done isolated, we should disable these. + // it currently cannot be disabled, unless we add ref counting. Since this is + // temporary, leaving it enabled is OK for now. + // https://github.com/containerd/containerd/issues/1681 + if err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil { + return errors.Wrap(err, "failed to enable necessary privileges") + } + + parentLayerPaths := s.parentIDsToParentPaths(snapshot.ParentIDs) + reader, writer := io.Pipe() + + go func() { + err := ociwclayer.ExportLayerToTar(ctx, writer, path, parentLayerPaths) + writer.CloseWithError(err) + }() + + if _, err := ociwclayer.ImportLayerFromTar(ctx, reader, path, parentLayerPaths); err != nil { + return errors.Wrap(err, "failed to reimport snapshot") + } + + if _, err := io.Copy(ioutil.Discard, reader); err != nil { + return errors.Wrap(err, "failed discarding extra data in import stream") + } + + // NOTE: We do not delete the sandbox.vhdx here, as that will break later calls to + // ociwclayer.ExportLayerToTar for this snapshot. + // As a consequence, the data for this layer is held twice, once on-disk and once + // in the sandbox.vhdx. + // TODO: This is either a bug or misfeature in hcsshim, so will need to be resolved + // there first. + + return nil +} + +// This handles creating the UVMs scratch layer. +func (s *snapshotter) createUVMScratchLayer(ctx context.Context, snDir string, parentLayers []string) error { + parentLen := len(parentLayers) + if parentLen == 0 { + return errors.New("no parent layers present") } - return hr + baseLayer := parentLayers[parentLen-1] + + // Make sure base layer has a UtilityVM folder. + uvmPath := filepath.Join(baseLayer, "UtilityVM") + if _, err := os.Stat(uvmPath); os.IsNotExist(err) { + return errors.Wrapf(err, "failed to find UtilityVM directory in base layer %q", baseLayer) + } + + templateDiffDisk := filepath.Join(uvmPath, "SystemTemplate.vhdx") + + // Check if SystemTemplate disk doesn't exist for some reason (this should be made during the unpacking + // of the base layer). + if _, err := os.Stat(templateDiffDisk); os.IsNotExist(err) { + return fmt.Errorf("%q does not exist in Utility VM image", templateDiffDisk) + } + + // Move the sandbox.vhdx into a nested vm folder to avoid clashing with a containers sandbox.vhdx. + vmScratchDir := filepath.Join(snDir, "vm") + if err := os.MkdirAll(vmScratchDir, 0777); err != nil { + return errors.Wrap(err, "failed to make `vm` directory for vm's scratch space") + } + + return copyScratchDisk(templateDiffDisk, filepath.Join(vmScratchDir, "sandbox.vhdx")) +} + +func copyScratchDisk(source, dest string) error { + scratchSource, err := os.OpenFile(source, os.O_RDWR, 0700) + if err != nil { + return errors.Wrapf(err, "failed to open %s", source) + } + defer scratchSource.Close() + + f, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, 0700) + if err != nil { + return errors.Wrap(err, "failed to create sandbox.vhdx in snapshot") + } + defer f.Close() + + if _, err := io.Copy(f, scratchSource); err != nil { + os.Remove(dest) + return errors.Wrapf(err, "failed to copy cached %q to %q in snapshot", source, dest) + } + return nil } diff -Nru containerd-1.2.6/snapshotter_opts_unix.go containerd-1.5.9/snapshotter_opts_unix.go --- containerd-1.2.6/snapshotter_opts_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/snapshotter_opts_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "fmt" + + "github.com/containerd/containerd/snapshots" +) + +// WithRemapperLabels creates the labels used by any supporting snapshotter +// to shift the filesystem ownership (user namespace mapping) automatically; currently +// supported by the fuse-overlayfs snapshotter +func WithRemapperLabels(ctrUID, hostUID, ctrGID, hostGID, length uint32) snapshots.Opt { + return snapshots.WithLabels(map[string]string{ + "containerd.io/snapshot/uidmapping": fmt.Sprintf("%d:%d:%d", ctrUID, hostUID, length), + "containerd.io/snapshot/gidmapping": fmt.Sprintf("%d:%d:%d", ctrGID, hostGID, length), + }) +} diff -Nru containerd-1.2.6/snapshot_test.go containerd-1.5.9/snapshot_test.go --- containerd-1.2.6/snapshot_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/snapshot_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "runtime" - "testing" - - "github.com/containerd/containerd/snapshots" - "github.com/containerd/containerd/snapshots/testsuite" -) - -func newSnapshotter(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { - client, err := New(address) - if err != nil { - return nil, nil, err - } - - sn := client.SnapshotService(DefaultSnapshotter) - - return sn, func() error { - // no need to close remote snapshotter - return client.Close() - }, nil -} - -func TestSnapshotterClient(t *testing.T) { - if testing.Short() { - t.Skip() - } - if runtime.GOOS == "windows" { - t.Skip("snapshots not yet supported on Windows") - } - testsuite.SnapshotterSuite(t, "SnapshotterClient", newSnapshotter) -} diff -Nru containerd-1.2.6/sys/env.go containerd-1.5.9/sys/env.go --- containerd-1.2.6/sys/env.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/env.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import "golang.org/x/sys/unix" - -// RunningPrivileged returns true if the effective user ID of the -// calling process is 0 -func RunningPrivileged() bool { - return unix.Geteuid() == 0 -} - -// RunningUnprivileged returns true if the effective user ID of the -// calling process is not 0 -func RunningUnprivileged() bool { - return !RunningPrivileged() -} diff -Nru containerd-1.2.6/sys/epoll.go containerd-1.5.9/sys/epoll.go --- containerd-1.2.6/sys/epoll.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/epoll.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,17 +20,14 @@ import "golang.org/x/sys/unix" -// EpollCreate1 directly calls unix.EpollCreate1 -func EpollCreate1(flag int) (int, error) { - return unix.EpollCreate1(flag) -} +// EpollCreate1 is an alias for unix.EpollCreate1 +// Deprecated: use golang.org/x/sys/unix.EpollCreate1 +var EpollCreate1 = unix.EpollCreate1 -// EpollCtl directly calls unix.EpollCtl -func EpollCtl(epfd int, op int, fd int, event *unix.EpollEvent) error { - return unix.EpollCtl(epfd, op, fd, event) -} +// EpollCtl is an alias for unix.EpollCtl +// Deprecated: use golang.org/x/sys/unix.EpollCtl +var EpollCtl = unix.EpollCtl -// EpollWait directly calls unix.EpollWait -func EpollWait(epfd int, events []unix.EpollEvent, msec int) (int, error) { - return unix.EpollWait(epfd, events, msec) -} +// EpollWait is an alias for unix.EpollWait +// Deprecated: use golang.org/x/sys/unix.EpollWait +var EpollWait = unix.EpollWait diff -Nru containerd-1.2.6/sys/filesys_unix.go containerd-1.5.9/sys/filesys_unix.go --- containerd-1.2.6/sys/filesys_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/filesys_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,3 +24,8 @@ func ForceRemoveAll(path string) error { return os.RemoveAll(path) } + +// MkdirAllWithACL is a wrapper for os.MkdirAll on Unix systems. +func MkdirAllWithACL(path string, perm os.FileMode) error { + return os.MkdirAll(path, perm) +} diff -Nru containerd-1.2.6/sys/filesys_windows.go containerd-1.5.9/sys/filesys_windows.go --- containerd-1.2.6/sys/filesys_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/filesys_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,12 +22,20 @@ "os" "path/filepath" "regexp" + "sort" + "strconv" "strings" "syscall" "unsafe" - winio "github.com/Microsoft/go-winio" "github.com/Microsoft/hcsshim" + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +const ( + // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System + SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" ) // MkdirAllWithACL is a wrapper for MkdirAll that creates a directory @@ -36,7 +44,8 @@ return mkdirall(path, true) } -// MkdirAll implementation that is volume path aware for Windows. +// MkdirAll implementation that is volume path aware for Windows. It can be used +// as a drop-in replacement for os.MkdirAll() func MkdirAll(path string, _ os.FileMode) error { return mkdirall(path, false) } @@ -78,7 +87,7 @@ if j > 1 { // Create parent - err = mkdirall(path[0:j-1], false) + err = mkdirall(path[0:j-1], adminAndLocalSystem) if err != nil { return err } @@ -106,27 +115,26 @@ // mkdirWithACL creates a new directory. If there is an error, it will be of // type *PathError. . // -// This is a modified and combined version of os.Mkdir and syscall.Mkdir +// This is a modified and combined version of os.Mkdir and windows.Mkdir // in golang to cater for creating a directory am ACL permitting full // access, with inheritance, to any subfolder/file for Built-in Administrators // and Local System. func mkdirWithACL(name string) error { - sa := syscall.SecurityAttributes{Length: 0} - sddl := "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" - sd, err := winio.SddlToSecurityDescriptor(sddl) + sa := windows.SecurityAttributes{Length: 0} + sd, err := windows.SecurityDescriptorFromString(SddlAdministratorsLocalSystem) if err != nil { return &os.PathError{Op: "mkdir", Path: name, Err: err} } sa.Length = uint32(unsafe.Sizeof(sa)) sa.InheritHandle = 1 - sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) + sa.SecurityDescriptor = sd - namep, err := syscall.UTF16PtrFromString(name) + namep, err := windows.UTF16PtrFromString(name) if err != nil { return &os.PathError{Op: "mkdir", Path: name, Err: err} } - e := syscall.CreateDirectory(namep, &sa) + e := windows.CreateDirectory(namep, &sa) if e != nil { return &os.PathError{Op: "mkdir", Path: name, Err: e} } @@ -149,7 +157,7 @@ return true } -// The origin of the functions below here are the golang OS and syscall packages, +// The origin of the functions below here are the golang OS and windows packages, // slightly modified to only cope with files, not directories due to the // specific use case. // @@ -181,83 +189,142 @@ if name == "" { return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT} } - r, errf := syscallOpenFileSequential(name, flag, 0) + r, errf := windowsOpenFileSequential(name, flag, 0) if errf == nil { return r, nil } return nil, &os.PathError{Op: "open", Path: name, Err: errf} } -func syscallOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { - r, e := syscallOpenSequential(name, flag|syscall.O_CLOEXEC, 0) +func windowsOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { + r, e := windowsOpenSequential(name, flag|windows.O_CLOEXEC, 0) if e != nil { return nil, e } return os.NewFile(uintptr(r), name), nil } -func makeInheritSa() *syscall.SecurityAttributes { - var sa syscall.SecurityAttributes +func makeInheritSa() *windows.SecurityAttributes { + var sa windows.SecurityAttributes sa.Length = uint32(unsafe.Sizeof(sa)) sa.InheritHandle = 1 return &sa } -func syscallOpenSequential(path string, mode int, _ uint32) (fd syscall.Handle, err error) { +func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) { if len(path) == 0 { - return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND + return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND } - pathp, err := syscall.UTF16PtrFromString(path) + pathp, err := windows.UTF16PtrFromString(path) if err != nil { - return syscall.InvalidHandle, err + return windows.InvalidHandle, err } var access uint32 - switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) { - case syscall.O_RDONLY: - access = syscall.GENERIC_READ - case syscall.O_WRONLY: - access = syscall.GENERIC_WRITE - case syscall.O_RDWR: - access = syscall.GENERIC_READ | syscall.GENERIC_WRITE - } - if mode&syscall.O_CREAT != 0 { - access |= syscall.GENERIC_WRITE - } - if mode&syscall.O_APPEND != 0 { - access &^= syscall.GENERIC_WRITE - access |= syscall.FILE_APPEND_DATA - } - sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE) - var sa *syscall.SecurityAttributes - if mode&syscall.O_CLOEXEC == 0 { + switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) { + case windows.O_RDONLY: + access = windows.GENERIC_READ + case windows.O_WRONLY: + access = windows.GENERIC_WRITE + case windows.O_RDWR: + access = windows.GENERIC_READ | windows.GENERIC_WRITE + } + if mode&windows.O_CREAT != 0 { + access |= windows.GENERIC_WRITE + } + if mode&windows.O_APPEND != 0 { + access &^= windows.GENERIC_WRITE + access |= windows.FILE_APPEND_DATA + } + sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE) + var sa *windows.SecurityAttributes + if mode&windows.O_CLOEXEC == 0 { sa = makeInheritSa() } var createmode uint32 switch { - case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): - createmode = syscall.CREATE_NEW - case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC): - createmode = syscall.CREATE_ALWAYS - case mode&syscall.O_CREAT == syscall.O_CREAT: - createmode = syscall.OPEN_ALWAYS - case mode&syscall.O_TRUNC == syscall.O_TRUNC: - createmode = syscall.TRUNCATE_EXISTING + case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL): + createmode = windows.CREATE_NEW + case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC): + createmode = windows.CREATE_ALWAYS + case mode&windows.O_CREAT == windows.O_CREAT: + createmode = windows.OPEN_ALWAYS + case mode&windows.O_TRUNC == windows.O_TRUNC: + createmode = windows.TRUNCATE_EXISTING default: - createmode = syscall.OPEN_EXISTING + createmode = windows.OPEN_EXISTING } // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. - //https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN - h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) + h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) return h, e } -// ForceRemoveAll is the same as os.RemoveAll, but uses hcsshim.DestroyLayer in order -// to delete container layers. +// ForceRemoveAll is the same as os.RemoveAll, but is aware of io.containerd.snapshotter.v1.windows +// and uses hcsshim to unmount and delete container layers contained therein, in the correct order, +// when passed a containerd root data directory (i.e. the `--root` directory for containerd). func ForceRemoveAll(path string) error { + // snapshots/windows/windows.go init() + const snapshotPlugin = "io.containerd.snapshotter.v1" + "." + "windows" + // snapshots/windows/windows.go NewSnapshotter() + snapshotDir := filepath.Join(path, snapshotPlugin, "snapshots") + if stat, err := os.Stat(snapshotDir); err == nil && stat.IsDir() { + if err := cleanupWCOWLayers(snapshotDir); err != nil { + return errors.Wrapf(err, "failed to cleanup WCOW layers in %s", snapshotDir) + } + } + + return os.RemoveAll(path) +} + +func cleanupWCOWLayers(root string) error { + // See snapshots/windows/windows.go getSnapshotDir() + var layerNums []int + if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if path != root && info.IsDir() { + if layerNum, err := strconv.Atoi(filepath.Base(path)); err == nil { + layerNums = append(layerNums, layerNum) + } else { + return err + } + return filepath.SkipDir + } + + return nil + }); err != nil { + return err + } + + sort.Sort(sort.Reverse(sort.IntSlice(layerNums))) + + for _, layerNum := range layerNums { + if err := cleanupWCOWLayer(filepath.Join(root, strconv.Itoa(layerNum))); err != nil { + return err + } + } + + return nil +} + +func cleanupWCOWLayer(layerPath string) error { info := hcsshim.DriverInfo{ - HomeDir: filepath.Dir(path), + HomeDir: filepath.Dir(layerPath), + } + + // ERROR_DEV_NOT_EXIST is returned if the layer is not currently prepared. + if err := hcsshim.UnprepareLayer(info, filepath.Base(layerPath)); err != nil { + if hcserror, ok := err.(*hcsshim.HcsError); !ok || hcserror.Err != windows.ERROR_DEV_NOT_EXIST { + return errors.Wrapf(err, "failed to unprepare %s", layerPath) + } + } + + if err := hcsshim.DeactivateLayer(info, filepath.Base(layerPath)); err != nil { + return errors.Wrapf(err, "failed to deactivate %s", layerPath) } - return hcsshim.DestroyLayer(info, filepath.Base(path)) + if err := hcsshim.DestroyLayer(info, filepath.Base(layerPath)); err != nil { + return errors.Wrapf(err, "failed to destroy %s", layerPath) + } + + return nil } diff -Nru containerd-1.2.6/sys/mount_linux.go containerd-1.5.9/sys/mount_linux.go --- containerd-1.2.6/sys/mount_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/mount_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -21,6 +21,7 @@ "syscall" "unsafe" + "github.com/containerd/containerd/log" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -30,9 +31,8 @@ var ( sourceP, targetP, fstypeP, dataP *byte pid uintptr - ws unix.WaitStatus err error - errno syscall.Errno + errno, status syscall.Errno ) sourceP, err = syscall.BytePtrFromString(source) @@ -60,37 +60,62 @@ runtime.LockOSThread() defer runtime.UnlockOSThread() + var pipefds [2]int + if err := syscall.Pipe2(pipefds[:], syscall.O_CLOEXEC); err != nil { + return errors.Wrap(err, "failed to open pipe") + } + + defer func() { + // close both ends of the pipe in a deferred function, since open file + // descriptor table is shared with child + syscall.Close(pipefds[0]) + syscall.Close(pipefds[1]) + }() + pid, errno = forkAndMountat(dirfd, uintptr(unsafe.Pointer(sourceP)), uintptr(unsafe.Pointer(targetP)), uintptr(unsafe.Pointer(fstypeP)), flags, - uintptr(unsafe.Pointer(dataP))) + uintptr(unsafe.Pointer(dataP)), + pipefds[1], + ) if errno != 0 { return errors.Wrap(errno, "failed to fork thread") } - _, err = unix.Wait4(int(pid), &ws, 0, nil) - for err == syscall.EINTR { - _, err = unix.Wait4(int(pid), &ws, 0, nil) - } + defer func() { + _, err := unix.Wait4(int(pid), nil, 0, nil) + for err == syscall.EINTR { + _, err = unix.Wait4(int(pid), nil, 0, nil) + } - if err != nil { - return errors.Wrapf(err, "failed to find pid=%d process", pid) - } + if err != nil { + log.L.WithError(err).Debugf("failed to find pid=%d process", pid) + } + }() - errno = syscall.Errno(ws.ExitStatus()) + _, _, errno = syscall.RawSyscall(syscall.SYS_READ, + uintptr(pipefds[0]), + uintptr(unsafe.Pointer(&status)), + unsafe.Sizeof(status)) if errno != 0 { - return errors.Wrap(errno, "failed to mount") + return errors.Wrap(errno, "failed to read pipe") } + + if status != 0 { + return errors.Wrap(status, "failed to mount") + } + return nil } // forkAndMountat will fork thread, change working dir and mount. // // precondition: the runtime OS thread must be locked. -func forkAndMountat(dirfd uintptr, source, target, fstype, flags, data uintptr) (pid uintptr, errno syscall.Errno) { +func forkAndMountat(dirfd uintptr, source, target, fstype, flags, data uintptr, pipefd int) (pid uintptr, errno syscall.Errno) { + // block signal during clone beforeFork() @@ -114,6 +139,7 @@ _, _, errno = syscall.RawSyscall6(syscall.SYS_MOUNT, source, target, fstype, flags, data, 0) childerr: + _, _, errno = syscall.RawSyscall(syscall.SYS_WRITE, uintptr(pipefd), uintptr(unsafe.Pointer(&errno)), unsafe.Sizeof(errno)) syscall.RawSyscall(syscall.SYS_EXIT, uintptr(errno), 0, 0) panic("unreachable") } diff -Nru containerd-1.2.6/sys/mount_linux_test.go containerd-1.5.9/sys/mount_linux_test.go --- containerd-1.2.6/sys/mount_linux_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/mount_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,7 +32,7 @@ type fMountatCaseFunc func(t *testing.T, root string) func TestFMountat(t *testing.T) { - if RunningUnprivileged() { + if !runningPrivileged() { t.Skip("Needs to be run as root") return } @@ -125,8 +125,8 @@ defer f.Close() err = FMountat(f.Fd(), filepath.Join(root, "empty"), filepath.Join(root, "work"), "", 0, "") - if got := errors.Cause(err); got != expectedErr { - t.Fatalf("expected error %v, but got %v", expectedErr, got) + if !errors.Is(err, expectedErr) { + t.Fatalf("expected error %v, but got %v", expectedErr, errors.Cause(err)) } } @@ -146,8 +146,8 @@ defer f.Close() err = FMountat(f.Fd(), filepath.Join(root, "oops"), "at", "bind", unix.MS_BIND, "") - if got := errors.Cause(err); got != expectedErr { - t.Fatalf("expected error %v, but got %v", expectedErr, got) + if !errors.Is(err, expectedErr) { + t.Fatalf("expected error %v, but got %v", expectedErr, err) } } diff -Nru containerd-1.2.6/sys/oom_linux.go containerd-1.5.9/sys/oom_linux.go --- containerd-1.2.6/sys/oom_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/oom_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sys + +import ( + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + + "github.com/containerd/containerd/pkg/userns" + "golang.org/x/sys/unix" +) + +const ( + // OOMScoreAdjMin is from OOM_SCORE_ADJ_MIN https://github.com/torvalds/linux/blob/v5.10/include/uapi/linux/oom.h#L9 + OOMScoreAdjMin = -1000 + // OOMScoreAdjMax is from OOM_SCORE_ADJ_MAX https://github.com/torvalds/linux/blob/v5.10/include/uapi/linux/oom.h#L10 + OOMScoreAdjMax = 1000 +) + +// AdjustOOMScore sets the oom score for the provided pid. If the provided score +// is out of range (-1000 - 1000), it is clipped to the min/max value. +func AdjustOOMScore(pid, score int) error { + if score > OOMScoreAdjMax { + score = OOMScoreAdjMax + } else if score < OOMScoreAdjMin { + score = OOMScoreAdjMin + } + return SetOOMScore(pid, score) +} + +// SetOOMScore sets the oom score for the provided pid +func SetOOMScore(pid, score int) error { + if score > OOMScoreAdjMax || score < OOMScoreAdjMin { + return fmt.Errorf("value out of range (%d): OOM score must be between %d and %d", score, OOMScoreAdjMin, OOMScoreAdjMax) + } + path := fmt.Sprintf("/proc/%d/oom_score_adj", pid) + f, err := os.OpenFile(path, os.O_WRONLY, 0) + if err != nil { + return err + } + defer f.Close() + if _, err = f.WriteString(strconv.Itoa(score)); err != nil { + if os.IsPermission(err) && (!runningPrivileged() || userns.RunningInUserNS()) { + return nil + } + return err + } + return nil +} + +// GetOOMScoreAdj gets the oom score for a process. It returns 0 (zero) if either +// no oom score is set, or a sore is set to 0. +func GetOOMScoreAdj(pid int) (int, error) { + path := fmt.Sprintf("/proc/%d/oom_score_adj", pid) + data, err := ioutil.ReadFile(path) + if err != nil { + return 0, err + } + return strconv.Atoi(strings.TrimSpace(string(data))) +} + +// runningPrivileged returns true if the effective user ID of the +// calling process is 0 +func runningPrivileged() bool { + return unix.Geteuid() == 0 +} diff -Nru containerd-1.2.6/sys/oom_linux_test.go containerd-1.5.9/sys/oom_linux_test.go --- containerd-1.2.6/sys/oom_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/oom_linux_test.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,127 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sys + +import ( + "errors" + "fmt" + "os" + "os/exec" + "testing" + "time" + + "github.com/containerd/containerd/pkg/userns" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestSetPositiveOomScoreAdjustment(t *testing.T) { + // Setting a *positive* OOM score adjust does not require privileged + _, adjustment, err := adjustOom(123) + assert.NilError(t, err) + assert.Check(t, is.Equal(adjustment, 123)) +} + +func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) { + if !runningPrivileged() || userns.RunningInUserNS() { + t.Skip("requires root and not running in user namespace") + return + } + + _, adjustment, err := adjustOom(-123) + assert.NilError(t, err) + assert.Check(t, is.Equal(adjustment, -123)) +} + +func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) { + if runningPrivileged() && !userns.RunningInUserNS() { + t.Skip("needs to be run as non-root or in user namespace") + return + } + + initial, adjustment, err := adjustOom(-123) + assert.NilError(t, err) + assert.Check(t, is.Equal(adjustment, initial)) +} + +func TestSetOOMScoreBoundaries(t *testing.T) { + err := SetOOMScore(0, OOMScoreAdjMax+1) + assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMax+1)) + + err = SetOOMScore(0, OOMScoreAdjMin-1) + assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMin-1)) + + _, adjustment, err := adjustOom(OOMScoreAdjMax) + assert.NilError(t, err) + assert.Check(t, is.Equal(adjustment, OOMScoreAdjMax)) + + score, err := GetOOMScoreAdj(os.Getpid()) + assert.NilError(t, err) + if score == OOMScoreAdjMin { + // We won't be able to set the score lower than the parent process. This + // could also be tested if the parent process does not have a oom-score-adj + // set, but GetOOMScoreAdj does not distinguish between "not set" and + // "score is set, but zero". + _, adjustment, err = adjustOom(OOMScoreAdjMin) + assert.NilError(t, err) + assert.Check(t, is.Equal(adjustment, OOMScoreAdjMin)) + } +} + +func adjustOom(adjustment int) (int, int, error) { + cmd := exec.Command("sleep", "100") + if err := cmd.Start(); err != nil { + return 0, 0, err + } + + defer cmd.Process.Kill() + + pid, err := waitForPid(cmd.Process) + if err != nil { + return 0, 0, err + } + initial, err := GetOOMScoreAdj(pid) + if err != nil { + return 0, 0, err + } + + if err := SetOOMScore(pid, adjustment); err != nil { + return 0, 0, err + } + + adj, err := GetOOMScoreAdj(pid) + return initial, adj, err +} + +func waitForPid(process *os.Process) (int, error) { + c := make(chan int, 1) + go func() { + for { + pid := process.Pid + if pid != 0 { + c <- pid + } + } + }() + + select { + case pid := <-c: + return pid, nil + case <-time.After(10 * time.Second): + return 0, errors.New("process did not start in 10 seconds") + } +} diff -Nru containerd-1.2.6/sys/oom_unix.go containerd-1.5.9/sys/oom_unix.go --- containerd-1.2.6/sys/oom_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/oom_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import ( - "fmt" - "os" - "strconv" - - "github.com/opencontainers/runc/libcontainer/system" -) - -// OOMScoreMaxKillable is the maximum score keeping the process killable by the oom killer -const OOMScoreMaxKillable = -999 - -// SetOOMScore sets the oom score for the provided pid -func SetOOMScore(pid, score int) error { - path := fmt.Sprintf("/proc/%d/oom_score_adj", pid) - f, err := os.OpenFile(path, os.O_WRONLY, 0) - if err != nil { - return err - } - defer f.Close() - if _, err = f.WriteString(strconv.Itoa(score)); err != nil { - if os.IsPermission(err) && (system.RunningInUserNS() || RunningUnprivileged()) { - return nil - } - return err - } - return nil -} diff -Nru containerd-1.2.6/sys/oom_unix_test.go containerd-1.5.9/sys/oom_unix_test.go --- containerd-1.2.6/sys/oom_unix_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/oom_unix_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "os/exec" - "strconv" - "strings" - "testing" - "time" - - "gotest.tools/assert" - is "gotest.tools/assert/cmp" -) - -func TestSetPositiveOomScoreAdjustment(t *testing.T) { - adjustment, err := adjustOom(123) - if err != nil { - t.Error(err) - return - } - assert.Check(t, is.Equal(adjustment, 123)) -} - -func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) { - if RunningUnprivileged() { - t.Skip("Needs to be run as root") - return - } - - adjustment, err := adjustOom(-123) - if err != nil { - t.Error(err) - return - } - assert.Check(t, is.Equal(adjustment, -123)) -} - -func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) { - if RunningPrivileged() { - t.Skip("Needs to be run as non-root") - return - } - - adjustment, err := adjustOom(-123) - if err != nil { - t.Error(err) - return - } - assert.Check(t, is.Equal(adjustment, 0)) -} - -func adjustOom(adjustment int) (int, error) { - cmd := exec.Command("sleep", "100") - if err := cmd.Start(); err != nil { - return 0, err - } - - pid, err := waitForPid(cmd.Process) - if err != nil { - return 0, err - } - - if err := SetOOMScore(pid, adjustment); err != nil { - return 0, err - } - - return readOomScoreAdj(pid) -} - -func waitForPid(process *os.Process) (int, error) { - c := make(chan int) - go func() { - for { - pid := process.Pid - if pid != 0 { - c <- pid - } - } - }() - - select { - case pid := <-c: - return pid, nil - case <-time.After(10 * time.Second): - return 0, errors.New("Process did not start in 10 seconds") - } -} - -func readOomScoreAdj(pid int) (int, error) { - oomScore, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/oom_score_adj", pid)) - if err != nil { - return 0, err - } - - scoreAsInt, err := strconv.Atoi(strings.TrimSpace(string(oomScore))) - if err != nil { - return 0, err - } - - return scoreAsInt, nil -} diff -Nru containerd-1.2.6/sys/oom_unsupported.go containerd-1.5.9/sys/oom_unsupported.go --- containerd-1.2.6/sys/oom_unsupported.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/oom_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sys + +const ( + // OOMScoreMaxKillable is not implemented on non Linux + OOMScoreMaxKillable = 0 + // OOMScoreAdjMax is not implemented on non Linux + OOMScoreAdjMax = 0 +) + +// AdjustOOMScore sets the oom score for the provided pid. If the provided score +// is out of range (-1000 - 1000), it is clipped to the min/max value. +// +// Not implemented on Windows +func AdjustOOMScore(pid, score int) error { + return nil +} + +// SetOOMScore sets the oom score for the process +// +// Not implemented on Windows +func SetOOMScore(pid, score int) error { + return nil +} + +// GetOOMScoreAdj gets the oom score for a process +// +// Not implemented on Windows +func GetOOMScoreAdj(pid int) (int, error) { + return 0, nil +} diff -Nru containerd-1.2.6/sys/oom_windows.go containerd-1.5.9/sys/oom_windows.go --- containerd-1.2.6/sys/oom_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/oom_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -// SetOOMScore sets the oom score for the process -// -// Not implemented on Windows -func SetOOMScore(pid, score int) error { - return nil -} diff -Nru containerd-1.2.6/sys/proc.go containerd-1.5.9/sys/proc.go --- containerd-1.2.6/sys/proc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/proc.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -// +build linux - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" - - "github.com/opencontainers/runc/libcontainer/system" -) - -const nanoSecondsPerSecond = 1e9 - -var clockTicksPerSecond = uint64(system.GetClockTicks()) - -// GetSystemCPUUsage returns the host system's cpu usage in -// nanoseconds. An error is returned if the format of the underlying -// file does not match. -// -// Uses /proc/stat defined by POSIX. Looks for the cpu -// statistics line and then sums up the first seven fields -// provided. See `man 5 proc` for details on specific field -// information. -func GetSystemCPUUsage() (uint64, error) { - var line string - f, err := os.Open("/proc/stat") - if err != nil { - return 0, err - } - bufReader := bufio.NewReaderSize(nil, 128) - defer func() { - bufReader.Reset(nil) - f.Close() - }() - bufReader.Reset(f) - err = nil - for err == nil { - line, err = bufReader.ReadString('\n') - if err != nil { - break - } - parts := strings.Fields(line) - switch parts[0] { - case "cpu": - if len(parts) < 8 { - return 0, fmt.Errorf("bad format of cpu stats") - } - var totalClockTicks uint64 - for _, i := range parts[1:8] { - v, err := strconv.ParseUint(i, 10, 64) - if err != nil { - return 0, fmt.Errorf("error parsing cpu stats") - } - totalClockTicks += v - } - return (totalClockTicks * nanoSecondsPerSecond) / - clockTicksPerSecond, nil - } - } - return 0, fmt.Errorf("bad stats format") -} diff -Nru containerd-1.2.6/sys/reaper/reaper_unix.go containerd-1.5.9/sys/reaper/reaper_unix.go --- containerd-1.2.6/sys/reaper/reaper_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/reaper/reaper_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,248 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package reaper + +import ( + "os/exec" + "sync" + "time" + + runc "github.com/containerd/go-runc" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// ErrNoSuchProcess is returned when the process no longer exists +var ErrNoSuchProcess = errors.New("no such process") + +const bufferSize = 32 + +type subscriber struct { + sync.Mutex + c chan runc.Exit + closed bool +} + +func (s *subscriber) close() { + s.Lock() + if s.closed { + s.Unlock() + return + } + close(s.c) + s.closed = true + s.Unlock() +} + +func (s *subscriber) do(fn func()) { + s.Lock() + fn() + s.Unlock() +} + +// Reap should be called when the process receives an SIGCHLD. Reap will reap +// all exited processes and close their wait channels +func Reap() error { + now := time.Now() + exits, err := reap(false) + for _, e := range exits { + done := Default.notify(runc.Exit{ + Timestamp: now, + Pid: e.Pid, + Status: e.Status, + }) + + select { + case <-done: + case <-time.After(1 * time.Second): + } + } + return err +} + +// Default is the default monitor initialized for the package +var Default = &Monitor{ + subscribers: make(map[chan runc.Exit]*subscriber), +} + +// Monitor monitors the underlying system for process status changes +type Monitor struct { + sync.Mutex + + subscribers map[chan runc.Exit]*subscriber +} + +// Start starts the command a registers the process with the reaper +func (m *Monitor) Start(c *exec.Cmd) (chan runc.Exit, error) { + ec := m.Subscribe() + if err := c.Start(); err != nil { + m.Unsubscribe(ec) + return nil, err + } + return ec, nil +} + +// Wait blocks until a process is signal as dead. +// User should rely on the value of the exit status to determine if the +// command was successful or not. +func (m *Monitor) Wait(c *exec.Cmd, ec chan runc.Exit) (int, error) { + for e := range ec { + if e.Pid == c.Process.Pid { + // make sure we flush all IO + c.Wait() + m.Unsubscribe(ec) + return e.Status, nil + } + } + // return no such process if the ec channel is closed and no more exit + // events will be sent + return -1, ErrNoSuchProcess +} + +// Subscribe to process exit changes +func (m *Monitor) Subscribe() chan runc.Exit { + c := make(chan runc.Exit, bufferSize) + m.Lock() + m.subscribers[c] = &subscriber{ + c: c, + } + m.Unlock() + return c +} + +// Unsubscribe to process exit changes +func (m *Monitor) Unsubscribe(c chan runc.Exit) { + m.Lock() + s, ok := m.subscribers[c] + if !ok { + m.Unlock() + return + } + s.close() + delete(m.subscribers, c) + m.Unlock() +} + +func (m *Monitor) getSubscribers() map[chan runc.Exit]*subscriber { + out := make(map[chan runc.Exit]*subscriber) + m.Lock() + for k, v := range m.subscribers { + out[k] = v + } + m.Unlock() + return out +} + +func (m *Monitor) notify(e runc.Exit) chan struct{} { + const timeout = 1 * time.Millisecond + var ( + done = make(chan struct{}, 1) + timer = time.NewTimer(timeout) + success = make(map[chan runc.Exit]struct{}) + ) + stop(timer, true) + + go func() { + defer close(done) + + for { + var ( + failed int + subscribers = m.getSubscribers() + ) + for _, s := range subscribers { + s.do(func() { + if s.closed { + return + } + if _, ok := success[s.c]; ok { + return + } + timer.Reset(timeout) + recv := true + select { + case s.c <- e: + success[s.c] = struct{}{} + case <-timer.C: + recv = false + failed++ + } + stop(timer, recv) + }) + } + // all subscribers received the message + if failed == 0 { + return + } + } + }() + return done +} + +func stop(timer *time.Timer, recv bool) { + if !timer.Stop() && recv { + <-timer.C + } +} + +// exit is the wait4 information from an exited process +type exit struct { + Pid int + Status int +} + +// reap reaps all child processes for the calling process and returns their +// exit information +func reap(wait bool) (exits []exit, err error) { + var ( + ws unix.WaitStatus + rus unix.Rusage + ) + flag := unix.WNOHANG + if wait { + flag = 0 + } + for { + pid, err := unix.Wait4(-1, &ws, flag, &rus) + if err != nil { + if err == unix.ECHILD { + return exits, nil + } + return exits, err + } + if pid <= 0 { + return exits, nil + } + exits = append(exits, exit{ + Pid: pid, + Status: exitStatus(ws), + }) + } +} + +const exitSignalOffset = 128 + +// exitStatus returns the correct exit status for a process based on if it +// was signaled or exited cleanly +func exitStatus(status unix.WaitStatus) int { + if status.Signaled() { + return exitSignalOffset + int(status.Signal()) + } + return status.ExitStatus() +} diff -Nru containerd-1.2.6/sys/reaper/reaper_utils_linux.go containerd-1.5.9/sys/reaper/reaper_utils_linux.go --- containerd-1.2.6/sys/reaper/reaper_utils_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/reaper/reaper_utils_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,39 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package reaper + +import ( + "unsafe" + + "golang.org/x/sys/unix" +) + +// SetSubreaper sets the value i as the subreaper setting for the calling process +func SetSubreaper(i int) error { + return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) +} + +// GetSubreaper returns the subreaper setting for the calling process +func GetSubreaper() (int, error) { + var i uintptr + + if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil { + return -1, err + } + + return int(i), nil +} diff -Nru containerd-1.2.6/sys/reaper.go containerd-1.5.9/sys/reaper.go --- containerd-1.2.6/sys/reaper.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/reaper.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import ( - "golang.org/x/sys/unix" -) - -// Exit is the wait4 information from an exited process -type Exit struct { - Pid int - Status int -} - -// Reap reaps all child processes for the calling process and returns their -// exit information -func Reap(wait bool) (exits []Exit, err error) { - var ( - ws unix.WaitStatus - rus unix.Rusage - ) - flag := unix.WNOHANG - if wait { - flag = 0 - } - for { - pid, err := unix.Wait4(-1, &ws, flag, &rus) - if err != nil { - if err == unix.ECHILD { - return exits, nil - } - return exits, err - } - if pid <= 0 { - return exits, nil - } - exits = append(exits, Exit{ - Pid: pid, - Status: exitStatus(ws), - }) - } -} - -const exitSignalOffset = 128 - -// exitStatus returns the correct exit status for a process based on if it -// was signaled or exited cleanly -func exitStatus(status unix.WaitStatus) int { - if status.Signaled() { - return exitSignalOffset + int(status.Signal()) - } - return status.ExitStatus() -} diff -Nru containerd-1.2.6/sys/reaper_linux.go containerd-1.5.9/sys/reaper_linux.go --- containerd-1.2.6/sys/reaper_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/reaper_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sys - -import ( - "unsafe" - - "golang.org/x/sys/unix" -) - -// If arg2 is nonzero, set the "child subreaper" attribute of the -// calling process; if arg2 is zero, unset the attribute. When a -// process is marked as a child subreaper, all of the children -// that it creates, and their descendants, will be marked as -// having a subreaper. In effect, a subreaper fulfills the role -// of init(1) for its descendant processes. Upon termination of -// a process that is orphaned (i.e., its immediate parent has -// already terminated) and marked as having a subreaper, the -// nearest still living ancestor subreaper will receive a SIGCHLD -// signal and be able to wait(2) on the process to discover its -// termination status. -const setChildSubreaper = 36 - -// SetSubreaper sets the value i as the subreaper setting for the calling process -func SetSubreaper(i int) error { - return unix.Prctl(setChildSubreaper, uintptr(i), 0, 0, 0) -} - -// GetSubreaper returns the subreaper setting for the calling process -func GetSubreaper() (int, error) { - var i uintptr - - if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil { - return -1, err - } - - return int(i), nil -} diff -Nru containerd-1.2.6/sys/socket_unix.go containerd-1.5.9/sys/socket_unix.go --- containerd-1.2.6/sys/socket_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/socket_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -68,11 +68,11 @@ } func mkdirAs(path string, uid, gid int) error { - if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) { + if _, err := os.Stat(path); !os.IsNotExist(err) { return err } - if err := os.Mkdir(path, 0770); err != nil { + if err := os.MkdirAll(path, 0770); err != nil { return err } diff -Nru containerd-1.2.6/sys/stat_bsd.go containerd-1.5.9/sys/stat_bsd.go --- containerd-1.2.6/sys/stat_bsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/sys/stat_bsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd netbsd /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/sys/stat_openbsd.go containerd-1.5.9/sys/stat_openbsd.go --- containerd-1.2.6/sys/stat_openbsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/stat_openbsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,45 @@ +// +build openbsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sys + +import ( + "syscall" + "time" +) + +// StatAtime returns the Atim +func StatAtime(st *syscall.Stat_t) syscall.Timespec { + return st.Atim +} + +// StatCtime returns the Ctim +func StatCtime(st *syscall.Stat_t) syscall.Timespec { + return st.Ctim +} + +// StatMtime returns the Mtim +func StatMtime(st *syscall.Stat_t) syscall.Timespec { + return st.Mtim +} + +// StatATimeAsTime returns st.Atim as a time.Time +func StatATimeAsTime(st *syscall.Stat_t) time.Time { + // The int64 conversions ensure the line compiles for 32-bit systems as well. + return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert +} diff -Nru containerd-1.2.6/sys/userns_deprecated.go containerd-1.5.9/sys/userns_deprecated.go --- containerd-1.2.6/sys/userns_deprecated.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/sys/userns_deprecated.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package sys + +import "github.com/containerd/containerd/pkg/userns" + +// RunningInUserNS detects whether we are currently running in a user namespace. +// Deprecated: use github.com/containerd/containerd/pkg/userns.RunningInUserNS instead. +var RunningInUserNS = userns.RunningInUserNS diff -Nru containerd-1.2.6/task.go containerd-1.5.9/task.go --- containerd-1.2.6/task.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/task.go 2022-01-05 17:30:58.000000000 +0000 @@ -35,13 +35,16 @@ "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/oci" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/rootfs" + "github.com/containerd/containerd/runtime/linux/runctypes" + "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/containerd/typeurl" google_protobuf "github.com/gogo/protobuf/types" digest "github.com/opencontainers/go-digest" is "github.com/opencontainers/image-spec/specs-go" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -115,6 +118,13 @@ ParentCheckpoint digest.Digest // Options hold runtime specific settings for checkpointing a task Options interface{} + + runtime string +} + +// Runtime name for the container +func (i *CheckpointTaskInfo) Runtime() string { + return i.runtime } // CheckpointTaskOpts allows the caller to set checkpoint options @@ -129,6 +139,12 @@ RootFS []mount.Mount // Options hold runtime specific settings for task creation Options interface{} + runtime string +} + +// Runtime name for the container +func (i *TaskInfo) Runtime() string { + return i.runtime } // Task is the executable object within containerd @@ -144,9 +160,11 @@ // Pids returns a list of system specific process ids inside the task Pids(context.Context) ([]ProcessInfo, error) // Checkpoint serializes the runtime and memory information of a task into an - // OCI Index that can be push and pulled from a remote resource. + // OCI Index that can be pushed and pulled from a remote resource. // // Additional software like CRIU maybe required to checkpoint and restore tasks + // NOTE: Checkpoint supports to dump task information to a directory, in this way, + // an empty OCI Index will be returned. Checkpoint(context.Context, ...CheckpointTaskOpts) (Image, error) // Update modifies executing tasks with updated settings Update(context.Context, ...UpdateTaskOpts) error @@ -158,18 +176,26 @@ // For the built in Linux runtime, github.com/containerd/cgroups.Metrics // are returned in protobuf format Metrics(context.Context) (*types.Metric, error) + // Spec returns the current OCI specification for the task + Spec(context.Context) (*oci.Spec, error) } var _ = (Task)(&task{}) type task struct { client *Client + c Container io cio.IO id string pid uint32 } +// Spec returns the current OCI specification for the task +func (t *task) Spec(ctx context.Context) (*oci.Spec, error) { + return t.c.Spec(ctx) +} + // ID of the task func (t *task) ID() string { return t.id @@ -289,6 +315,7 @@ return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "task must be stopped before deletion: %s", status.Status) } if t.io != nil { + t.io.Close() t.io.Cancel() t.io.Wait() } @@ -389,17 +416,25 @@ return errdefs.FromGRPC(err) } +// NOTE: Checkpoint supports to dump task information to a directory, in this way, an empty +// OCI Index will be returned. func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Image, error) { ctx, done, err := t.client.WithLease(ctx) if err != nil { return nil, err } defer done(ctx) + cr, err := t.client.ContainerService().Get(ctx, t.id) + if err != nil { + return nil, err + } request := &tasks.CheckpointTaskRequest{ ContainerID: t.id, } - var i CheckpointTaskInfo + i := CheckpointTaskInfo{ + runtime: cr.Runtime.Name, + } for _, o := range opts { if err := o(&i); err != nil { return nil, err @@ -417,15 +452,20 @@ } request.Options = any } - // make sure we pause it and resume after all other filesystem operations are completed - if err := t.Pause(ctx); err != nil { - return nil, err - } - defer t.Resume(ctx) - cr, err := t.client.ContainerService().Get(ctx, t.id) + + status, err := t.Status(ctx) if err != nil { return nil, err } + + if status.Status != Paused { + // make sure we pause it and resume after all other filesystem operations are completed + if err := t.Pause(ctx); err != nil { + return nil, err + } + defer t.Resume(ctx) + } + index := v1.Index{ Versioned: is.Versioned{ SchemaVersion: 2, @@ -435,6 +475,12 @@ if err := t.checkpointTask(ctx, &index, request); err != nil { return nil, err } + // if checkpoint image path passed, jump checkpoint image, + // return an empty image + if isCheckpointPathExist(cr.Runtime.Name, i.Options) { + return NewImage(t.client, images.Image{}), nil + } + if cr.Image != "" { if err := t.checkpointImage(ctx, &index, cr.Image); err != nil { return nil, err @@ -467,6 +513,8 @@ type UpdateTaskInfo struct { // Resources updates a tasks resource constraints Resources interface{} + // Annotations allows arbitrary and/or experimental resource constraints for task update + Annotations map[string]string } // UpdateTaskOpts allows a caller to update task settings @@ -489,11 +537,17 @@ } request.Resources = any } + if i.Annotations != nil { + request.Annotations = i.Annotations + } _, err := t.client.TaskService().Update(ctx, request) return errdefs.FromGRPC(err) } func (t *task) LoadProcess(ctx context.Context, id string, ioAttach cio.Attach) (Process, error) { + if id == t.id && ioAttach == nil { + return t, nil + } response, err := t.client.TaskService().Get(ctx, &tasks.GetRequest{ ContainerID: t.id, ExecID: id, @@ -544,6 +598,7 @@ if err != nil { return errdefs.FromGRPC(err) } + // NOTE: response.Descriptors can be an empty slice if checkpoint image is jumped // add the checkpoint descriptors to the index for _, d := range response.Descriptors { index.Manifests = append(index.Manifests, v1.Descriptor{ @@ -554,6 +609,7 @@ OS: goruntime.GOOS, Architecture: goruntime.GOARCH, }, + Annotations: d.Annotations, }) } return nil @@ -621,3 +677,24 @@ Size: size, }, nil } + +// isCheckpointPathExist only suitable for runc runtime now +func isCheckpointPathExist(runtime string, v interface{}) bool { + if v == nil { + return false + } + + switch runtime { + case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2: + if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" { + return true + } + + case plugin.RuntimeLinuxV1: + if opts, ok := v.(*runctypes.CheckpointOptions); ok && opts.ImagePath != "" { + return true + } + } + + return false +} diff -Nru containerd-1.2.6/task_opts.go containerd-1.5.9/task_opts.go --- containerd-1.2.6/task_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/task_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -27,6 +27,8 @@ "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/runtime/linux/runctypes" + "github.com/containerd/containerd/runtime/v2/runc/options" imagespec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -57,9 +59,10 @@ for _, m := range index.Manifests { if m.MediaType == images.MediaTypeContainerd1Checkpoint { info.Checkpoint = &types.Descriptor{ - MediaType: m.MediaType, - Size_: m.Size, - Digest: m.Digest, + MediaType: m.MediaType, + Size_: m.Size, + Digest: m.Digest, + Annotations: m.Annotations, } return nil } @@ -89,6 +92,58 @@ } } +// WithCheckpointImagePath sets image path for checkpoint option +func WithCheckpointImagePath(path string) CheckpointTaskOpts { + return func(r *CheckpointTaskInfo) error { + if CheckRuntime(r.Runtime(), "io.containerd.runc") { + if r.Options == nil { + r.Options = &options.CheckpointOptions{} + } + opts, ok := r.Options.(*options.CheckpointOptions) + if !ok { + return errors.New("invalid v2 shim checkpoint options format") + } + opts.ImagePath = path + } else { + if r.Options == nil { + r.Options = &runctypes.CheckpointOptions{} + } + opts, ok := r.Options.(*runctypes.CheckpointOptions) + if !ok { + return errors.New("invalid v1 shim checkpoint options format") + } + opts.ImagePath = path + } + return nil + } +} + +// WithRestoreImagePath sets image path for create option +func WithRestoreImagePath(path string) NewTaskOpts { + return func(ctx context.Context, c *Client, ti *TaskInfo) error { + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.CriuImagePath = path + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{} + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("invalid v1 shim create options format") + } + opts.CriuImagePath = path + } + return nil + } +} + // ProcessDeleteOpts allows the caller to set options for the deletion of a task type ProcessDeleteOpts func(context.Context, Process) error @@ -154,3 +209,11 @@ return nil } } + +// WithAnnotations sets the provided annotations for task updates. +func WithAnnotations(annotations map[string]string) UpdateTaskOpts { + return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error { + r.Annotations = annotations + return nil + } +} diff -Nru containerd-1.2.6/task_opts_unix.go containerd-1.5.9/task_opts_unix.go --- containerd-1.2.6/task_opts_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/task_opts_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,36 +22,136 @@ "context" "github.com/containerd/containerd/runtime/linux/runctypes" + "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/pkg/errors" ) // WithNoNewKeyring causes tasks not to be created with a new keyring for secret storage. // There is an upper limit on the number of keyrings in a linux system func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &runctypes.CreateOptions{} - } - opts, ok := ti.Options.(*runctypes.CreateOptions) - if !ok { - return errors.New("could not cast TaskInfo Options to CreateOptions") + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.NoNewKeyring = true + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{} + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("could not cast TaskInfo Options to CreateOptions") + } + opts.NoNewKeyring = true } - - opts.NoNewKeyring = true return nil } // WithNoPivotRoot instructs the runtime not to you pivot_root -func WithNoPivotRoot(_ context.Context, _ *Client, info *TaskInfo) error { - if info.Options == nil { - info.Options = &runctypes.CreateOptions{ - NoPivotRoot: true, +func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error { + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.NoPivotRoot = true + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{ + NoPivotRoot: true, + } + return nil + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("invalid options type, expected runctypes.CreateOptions") + } + opts.NoPivotRoot = true + } + return nil +} + +// WithShimCgroup sets the existing cgroup for the shim +func WithShimCgroup(path string) NewTaskOpts { + return func(ctx context.Context, c *Client, ti *TaskInfo) error { + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.ShimCgroup = path + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{} + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("could not cast TaskInfo Options to CreateOptions") + } + opts.ShimCgroup = path + } + return nil + } +} + +// WithUIDOwner allows console I/O to work with the remapped UID in user namespace +func WithUIDOwner(uid uint32) NewTaskOpts { + return func(ctx context.Context, c *Client, ti *TaskInfo) error { + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.IoUid = uid + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{} + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("could not cast TaskInfo Options to CreateOptions") + } + opts.IoUid = uid } return nil } - opts, ok := info.Options.(*runctypes.CreateOptions) - if !ok { - return errors.New("invalid options type, expected runctypes.CreateOptions") +} + +// WithGIDOwner allows console I/O to work with the remapped GID in user namespace +func WithGIDOwner(gid uint32) NewTaskOpts { + return func(ctx context.Context, c *Client, ti *TaskInfo) error { + if CheckRuntime(ti.Runtime(), "io.containerd.runc") { + if ti.Options == nil { + ti.Options = &options.Options{} + } + opts, ok := ti.Options.(*options.Options) + if !ok { + return errors.New("invalid v2 shim create options format") + } + opts.IoGid = gid + } else { + if ti.Options == nil { + ti.Options = &runctypes.CreateOptions{} + } + opts, ok := ti.Options.(*runctypes.CreateOptions) + if !ok { + return errors.New("could not cast TaskInfo Options to CreateOptions") + } + opts.IoGid = gid + } + return nil } - opts.NoPivotRoot = true - return nil } diff -Nru containerd-1.2.6/task_opts_unix_test.go containerd-1.5.9/task_opts_unix_test.go --- containerd-1.2.6/task_opts_unix_test.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/task_opts_unix_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package containerd - -import ( - "context" - "testing" - - "github.com/containerd/containerd/runtime/linux/runctypes" -) - -func TestWithNoNewKeyringAddsNoNewKeyringToOptions(t *testing.T) { - var taskInfo TaskInfo - var ctx context.Context - var client Client - - err := WithNoNewKeyring(ctx, &client, &taskInfo) - if err != nil { - t.Fatal(err) - } - - opts := taskInfo.Options.(*runctypes.CreateOptions) - - if !opts.NoNewKeyring { - t.Fatal("NoNewKeyring set on WithNoNewKeyring") - } - -} - -func TestWithNoNewKeyringDoesNotOverwriteOtherOptions(t *testing.T) { - var taskInfo TaskInfo - var ctx context.Context - var client Client - - taskInfo.Options = &runctypes.CreateOptions{NoPivotRoot: true} - - err := WithNoNewKeyring(ctx, &client, &taskInfo) - if err != nil { - t.Fatal(err) - } - - opts := taskInfo.Options.(*runctypes.CreateOptions) - - if !opts.NoPivotRoot { - t.Fatal("WithNoNewKeyring overwrote other options") - } -} diff -Nru containerd-1.2.6/test/build.sh containerd-1.5.9/test/build.sh --- containerd-1.2.6/test/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/build.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,58 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is used to build and upload containerd with latest CRI plugin +# from containerd/cri in gcr.io/k8s-testimages/kubekins-e2e. + +set -o xtrace +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname "${BASH_SOURCE[0]}")/build-utils.sh +cd "${ROOT}" + +# Make sure output directory is clean. +make clean + +# Build CRI+CNI release +make BUILDTAGS="seccomp no_aufs no_btrfs no_devmapper no_zfs" cri-cni-release + +BUILDDIR=$(mktemp -d) +cleanup() { + if [[ ${BUILDDIR} == /tmp/* ]]; then + echo "[-] REMOVING ${BUILDDIR}" + rm -rf ${BUILDDIR} + fi +} +trap cleanup EXIT + +set -x +latest=$(readlink ./releases/cri-cni-containerd.tar.gz) +tarball=$(echo ${latest} | sed -e 's/cri-containerd-cni/containerd-cni/g' | sed -e 's/-linux-amd64/.linux-amd64/g') +cp releases/${latest} ${BUILDDIR}/${tarball} +cp releases/${latest}.sha256sum ${BUILDDIR}/${tarball}.sha256 + +# Push test tarball to Google cloud storage. +VERSION=$(git describe --match 'v[0-9]*' --dirty='.m' --always) + +if [ -z "${DEPLOY_DIR}" ]; then + DEPLOY_DIR="containerd" +else + DEPLOY_DIR="containerd/${DEPLOY_DIR}" +fi + +PUSH_VERSION=true DEPLOY_DIR=${DEPLOY_DIR} TARBALL=${tarball} VERSION=${VERSION#v} BUILD_DIR=${BUILDDIR} ${ROOT}/test/push.sh diff -Nru containerd-1.2.6/test/build-test-images.sh containerd-1.5.9/test/build-test-images.sh --- containerd-1.2.6/test/build-test-images.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/build-test-images.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is used to build and upload images in integration/images +# directory to gcr.io/k8s-cri-containerd repository + +set -o xtrace +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname "${BASH_SOURCE[0]}")/build-utils.sh +source $(dirname "${BASH_SOURCE[0]}")/init-buildx.sh +cd "${ROOT}" + +# ignore errors if the image already exists +make -C integration/images/volume-copy-up push PROJ="gcr.io/${PROJECT:-k8s-cri-containerd}" || true +make -C integration/images/volume-ownership push PROJ="gcr.io/${PROJECT:-k8s-cri-containerd}" || true diff -Nru containerd-1.2.6/test/build-utils.sh containerd-1.5.9/test/build-utils.sh --- containerd-1.2.6/test/build-utils.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/build-utils.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/.. + +# PROJECT is the gce project to upload tarball. +PROJECT=${PROJECT:-"k8s-cri-containerd"} + +# GOOGLE_APPLICATION_CREDENTIALS is the path of service account file. +if [ -z ${GOOGLE_APPLICATION_CREDENTIALS:-""} ]; then + echo "GOOGLE_APPLICATION_CREDENTIALS is not set" + exit 1 +fi + +# Activate gcloud service account. +gcloud auth activate-service-account --key-file "${GOOGLE_APPLICATION_CREDENTIALS}" --project="${PROJECT}" + +# Kubernetes test infra uses jessie and stretch. +if cat /etc/os-release | grep jessie; then + sh -c "echo 'deb http://ftp.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/backports.list" + apt-get update + apt-get install -y libseccomp2/jessie-backports + apt-get install -y libseccomp-dev/jessie-backports +else + cat /etc/os-release + apt-get update + apt-get install -y libseccomp2 + apt-get install -y libseccomp-dev +fi + +# PULL_REFS is from prow. +if [ ! -z "${PULL_REFS:-""}" ]; then + DEPLOY_DIR=$(echo "${PULL_REFS}" | sha1sum | awk '{print $1}') +fi diff -Nru containerd-1.2.6/test/e2e/master.yaml containerd-1.5.9/test/e2e/master.yaml --- containerd-1.2.6/test/e2e/master.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/e2e/master.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,199 @@ +#cloud-config + +users: +- name: etcd + homedir: /var/etcd + lock_passwd: true + ssh_redirect_user: true + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-master-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-master-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes master + After=kube-master-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-master-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-master-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-master-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-master-installation.service + - systemctl enable kube-master-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/test/e2e/node.yaml containerd-1.5.9/test/e2e/node.yaml --- containerd-1.2.6/test/e2e/node.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/e2e/node.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,193 @@ +#cloud-config + +write_files: +# Setup containerd. + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=kubernetes.target + +# Setup kubernetes. + - path: /etc/systemd/system/kube-node-installation.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Download and install k8s binaries and configurations + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/kubernetes/bin + ExecStartPre=/bin/mount --bind /home/kubernetes/bin /home/kubernetes/bin + ExecStartPre=/bin/mount -o remount,exec /home/kubernetes/bin + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/kubernetes/bin/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/configure-sh + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure.sh + ExecStart=/home/kubernetes/bin/configure.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-node-configuration.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Configure kubernetes node + After=kube-node-installation.service + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/configure-helper.sh + ExecStart=/home/kubernetes/bin/configure-helper.sh + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-container-runtime-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for container runtime + After=kube-node-configuration.service + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh container-runtime + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubelet-monitor.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes health monitoring for kubelet + After=kube-node-configuration.service + + [Service] + Restart=always + RestartSec=10 + RemainAfterExit=yes + ExecStartPre=/bin/chmod 544 /home/kubernetes/bin/health-monitor.sh + ExecStart=/home/kubernetes/bin/health-monitor.sh kubelet + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.timer + permissions: 0644 + owner: root + content: | + [Unit] + Description=Hourly kube-logrotate invocation + + [Timer] + OnCalendar=hourly + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kube-logrotate.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes log rotation + After=kube-node-configuration.service + + [Service] + Type=oneshot + ExecStart=-/usr/sbin/logrotate /etc/logrotate.conf + + [Install] + WantedBy=kubernetes.target + + - path: /etc/systemd/system/kubernetes.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Kubernetes + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl enable kube-node-installation.service + - systemctl enable kube-node-configuration.service + - systemctl enable kubelet-monitor.service + - systemctl enable kube-container-runtime-monitor.service + - systemctl enable kube-logrotate.timer + - systemctl enable kube-logrotate.service + - systemctl enable kubernetes.target + - systemctl start kubernetes.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-enabled docker && (systemctl is-active docker || systemctl start docker) diff -Nru containerd-1.2.6/test/e2e_node/gci-init.sh containerd-1.5.9/test/e2e_node/gci-init.sh --- containerd-1.2.6/test/e2e_node/gci-init.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/e2e_node/gci-init.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is used to do extra initialization on GCI. + +mount /tmp /tmp -o remount,exec,suid +#TODO(random-liu): Stop docker and remove this docker thing. +usermod -a -G docker jenkins +#TODO(random-liu): Change current node e2e to use init script, +# so that we don't need to copy this code everywhere. +mkdir -p /var/lib/kubelet +mkdir -p /home/kubernetes/containerized_mounter/rootfs +mount --bind /home/kubernetes/containerized_mounter/ /home/kubernetes/containerized_mounter/ +mount -o remount, exec /home/kubernetes/containerized_mounter/ +wget https://storage.googleapis.com/kubernetes-release/gci-mounter/mounter.tar -O /tmp/mounter.tar +tar xvf /tmp/mounter.tar -C /home/kubernetes/containerized_mounter/rootfs +mkdir -p /home/kubernetes/containerized_mounter/rootfs/var/lib/kubelet +mount --rbind /var/lib/kubelet /home/kubernetes/containerized_mounter/rootfs/var/lib/kubelet +mount --make-rshared /home/kubernetes/containerized_mounter/rootfs/var/lib/kubelet +mount --bind /proc /home/kubernetes/containerized_mounter/rootfs/proc +mount --bind /dev /home/kubernetes/containerized_mounter/rootfs/dev +rm /tmp/mounter.tar diff -Nru containerd-1.2.6/test/e2e_node/init.yaml containerd-1.5.9/test/e2e_node/init.yaml --- containerd-1.2.6/test/e2e_node/init.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/e2e_node/init.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +#cloud-config + +write_files: + - path: /etc/systemd/system/containerd-installation.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=Download and install containerd binaries and configurations. + After=network-online.target + + [Service] + Type=oneshot + RemainAfterExit=yes + ExecStartPre=/bin/mkdir -p /home/containerd + ExecStartPre=/bin/mount --bind /home/containerd /home/containerd + ExecStartPre=/bin/mount -o remount,exec /home/containerd + ExecStartPre=/usr/bin/curl --fail --retry 5 --retry-delay 3 --silent --show-error -H "X-Google-Metadata-Request: True" -o /home/containerd/configure.sh http://metadata.google.internal/computeMetadata/v1/instance/attributes/containerd-configure-sh + ExecStartPre=/bin/chmod 544 /home/containerd/configure.sh + ExecStart=/home/containerd/configure.sh + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.service + permissions: 0644 + owner: root + content: | + # installed by cloud-init + [Unit] + Description=containerd container runtime + Documentation=https://containerd.io + After=containerd-installation.service + + [Service] + Restart=always + RestartSec=5 + Delegate=yes + KillMode=process + OOMScoreAdjust=-999 + LimitNOFILE=1048576 + # Having non-zero Limit*s causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + LimitNPROC=infinity + LimitCORE=infinity + TasksMax=infinity + ExecStartPre=/sbin/modprobe overlay + ExecStart=/home/containerd/usr/local/bin/containerd + + [Install] + WantedBy=containerd.target + + - path: /etc/systemd/system/containerd.target + permissions: 0644 + owner: root + content: | + [Unit] + Description=Containerd + + [Install] + WantedBy=multi-user.target + +runcmd: + # Stop the existing containerd service if there is one. (for Docker 18.09+) + - systemctl is-active containerd && systemctl stop containerd + - systemctl daemon-reload + - systemctl enable containerd-installation.service + - systemctl enable containerd.service + - systemctl enable containerd.target + - systemctl start containerd.target + # Start docker after containerd is running. (for Docker 18.09+) + - systemctl is-active docker || systemctl start docker diff -Nru containerd-1.2.6/test/init-buildx.sh containerd-1.5.9/test/init-buildx.sh --- containerd-1.2.6/test/init-buildx.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/init-buildx.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copyright 2020 The Kubernetes 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. + +set -o errexit +set -o nounset +set -o pipefail + +export DOCKER_CLI_EXPERIMENTAL=enabled +# Expected builder output +# +# Name: containerd-buildkit-multiarch +# Driver: docker-container +# +# Nodes: +# Name: containerd-buildkit-multiarch0 +# Endpoint: unix:///var/run/docker.sock +# Status: running +# Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 +current_builder="$(docker buildx inspect)" + +# We can skip setup if the current builder already has multi-arch +# AND if it isn't the "docker" driver, which doesn't work +# +# From https://docs.docker.com/buildx/working-with-buildx/#build-with-buildx: +# "You can run Buildx in different configurations that are exposed through a +# driver concept. Currently, Docker supports a “docker†driver that uses the +# BuildKit library bundled into the docker daemon binary, and a +# “docker-container†driver that automatically launches BuildKit inside a +# Docker container. +# +# The user experience of using Buildx is very similar across drivers. +# However, there are some features that are not currently supported by the +# “docker†driver, because the BuildKit library which is bundled into docker +# daemon uses a different storage component. In contrast, all images built with +# the “docker†driver are automatically added to the “docker images†view by +# default, whereas when using other drivers, the method for outputting an image +# needs to be selected with --output." +if ! grep -q "^Driver: docker$" <<<"${current_builder}" \ + && grep -q "linux/amd64" <<<"${current_builder}" \ + && grep -q "linux/arm" <<<"${current_builder}" \ + && grep -q "linux/arm64" <<<"${current_builder}" \ + && grep -q "linux/ppc64le" <<<"${current_builder}" \ + && grep -q "linux/s390x" <<<"${current_builder}"; then + exit 0 +fi + +# Ensure qemu is in binfmt_misc +# NOTE: Please always pin this to a digest for predictability/auditability +# Last updated: 08/21/2020 +if [ "$(uname)" == 'Linux' ]; then + docker run --rm --privileged multiarch/qemu-user-static@sha256:c772ee1965aa0be9915ee1b018a0dd92ea361b4fa1bcab5bbc033517749b2af4 --reset -p yes +fi + +# Ensure we use a builder that can leverage it (the default on linux will not) +docker buildx rm containerd-buildkit-multiarch || true +docker buildx create --use --name=containerd-buildkit-multiarch +docker buildx inspect --bootstrap diff -Nru containerd-1.2.6/test/push.sh containerd-1.5.9/test/push.sh --- containerd-1.2.6/test/push.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/push.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,66 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname "${BASH_SOURCE[0]}")/utils.sh + +# DEPLOY_BUCKET is the gcs bucket where the tarball should be stored in. +DEPLOY_BUCKET=${DEPLOY_BUCKET:-"cri-containerd-staging"} +# DEPLOY_DIR is the directory in the gcs bucket to store the tarball. +DEPLOY_DIR=${DEPLOY_DIR:-""} +# BUILD_DIR is the directory of the build out. +BUILD_DIR=${BUILD_DIR:-"_output"} +# TARBALL is the tarball name. +TARBALL=${TARBALL:-"cri-containerd.tar.gz"} +# LATEST is the name of the latest version file. +LATEST=${LATEST:-"latest"} +# PUSH_VERSION indicates whether to push version. +PUSH_VERSION=${PUSH_VERSION:-false} + +release_tar=${BUILD_DIR}/${TARBALL} +release_tar_checksum=${release_tar}.sha256 +if [[ ! -e ${release_tar} || ! -e ${release_tar_checksum} ]]; then + echo "Release tarball is not built" + exit 1 +fi + +if ! gsutil ls "gs://${DEPLOY_BUCKET}" > /dev/null; then + create_ttl_bucket ${DEPLOY_BUCKET} +fi + +if [ -z "${DEPLOY_DIR}" ]; then + DEPLOY_PATH="${DEPLOY_BUCKET}" +else + DEPLOY_PATH="${DEPLOY_BUCKET}/${DEPLOY_DIR}" +fi + +gsutil cp ${release_tar} "gs://${DEPLOY_PATH}/" +gsutil cp ${release_tar_checksum} "gs://${DEPLOY_PATH}/" +echo "Release tarball is uploaded to: + https://storage.googleapis.com/${DEPLOY_PATH}/${TARBALL}" + +if ${PUSH_VERSION}; then + if [[ -z "${VERSION}" ]]; then + echo "VERSION is not set" + exit 1 + fi + echo ${VERSION} | gsutil cp - "gs://${DEPLOY_PATH}/${LATEST}" + echo "Latest version is uploaded to: + https://storage.googleapis.com/${DEPLOY_PATH}/${LATEST}" +fi diff -Nru containerd-1.2.6/test/utils.sh containerd-1.5.9/test/utils.sh --- containerd-1.2.6/test/utils.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/test/utils.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,63 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/.. + +# upload_logs_to_gcs uploads test logs to gcs. +# Var set: +# 1. Bucket: gcs bucket to upload logs. +# 2. Dir: directory name to upload logs. +# 3. Test Result: directory of the test result. +upload_logs_to_gcs() { + local -r bucket=$1 + local -r dir=$2 + local -r result=$3 + if ! gsutil ls "gs://${bucket}" > /dev/null; then + create_ttl_bucket ${bucket} + fi + local -r upload_log_path=${bucket}/${dir} + gsutil cp -r "${result}" "gs://${upload_log_path}" + echo "Test logs are uploaed to: + http://gcsweb.k8s.io/gcs/${upload_log_path}/" +} + +# create_ttl_bucket create a public bucket in which all objects +# have a default TTL (30 days). +# Var set: +# 1. Bucket: gcs bucket name. +create_ttl_bucket() { + local -r bucket=$1 + gsutil mb "gs://${bucket}" + local -r bucket_rule=$(mktemp) + # Set 30 day TTL for logs inside the bucket. + echo '{"rule": [{"action": {"type": "Delete"},"condition": {"age": 30}}]}' > ${bucket_rule} + gsutil lifecycle set "${bucket_rule}" "gs://${bucket}" + rm "${bucket_rule}" + + gsutil -m acl ch -g all:R "gs://${bucket}" + gsutil defacl set public-read "gs://${bucket}" +} + +# sha256 generates a sha256 checksum for a file. +# Var set: +# 1. Filename. +sha256() { + if which sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{ print $1 }' + else + shasum -a256 "$1" | awk '{ print $1 }' + fi +} diff -Nru containerd-1.2.6/.travis.yml containerd-1.5.9/.travis.yml --- containerd-1.2.6/.travis.yml 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -dist: trusty -sudo: required -# setup travis so that we can run containers for integration tests -services: - - docker - -language: go - -go: - - "1.11.x" - -go_import_path: github.com/containerd/containerd - -addons: - apt: - packages: - - btrfs-tools - - libnl-3-dev - - libnet-dev - - protobuf-c-compiler - # - protobuf-compiler - - python-minimal - - libcap-dev - - libaio-dev - - libprotobuf-c0-dev - - libprotobuf-dev - - socat - -env: - - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v1 TRAVIS_CGO_ENABLED=1 - - TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runtime.v1.linux TRAVIS_CGO_ENABLED=1 - - TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0 - -before_install: - - uname -r - - sudo apt-get -q update - - sudo apt-get install -y libseccomp-dev/trusty-backports - -install: - - sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-protobuf - - sudo chmod +x /usr/local/bin/protoc - - sudo chmod og+rx /usr/local/include/google /usr/local/include/google/protobuf /usr/local/include/google/protobuf/compiler - - sudo chmod -R og+r /usr/local/include/google/protobuf/ - - protoc --version - - go get -u github.com/vbatts/git-validation - - go get -u github.com/kunalkushwaha/ltag - - go get -u github.com/LK4D4/vndr - - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-runc ; fi - - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-cni ; fi - - if [ "$TRAVIS_GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-critools ; fi - - if [ "$TRAVIS_GOOS" = "linux" ]; then wget https://github.com/checkpoint-restore/criu/archive/v3.7.tar.gz -O /tmp/criu.tar.gz ; fi - - if [ "$TRAVIS_GOOS" = "linux" ]; then tar -C /tmp/ -zxf /tmp/criu.tar.gz ; fi - - if [ "$TRAVIS_GOOS" = "linux" ]; then cd /tmp/criu-3.7 && sudo make install-criu ; fi - - cd $TRAVIS_BUILD_DIR - -before_script: - - pushd ..; git clone https://github.com/containerd/project; popd - -script: - - export GOOS=$TRAVIS_GOOS - - export CGO_ENABLED=$TRAVIS_CGO_ENABLED - - DCO_VERBOSITY=-q ../project/script/validate/dco - - ../project/script/validate/fileheader ../project/ - - ../project/script/validate/vendor - - GOOS=linux script/setup/install-dev-tools - - go build -i . - - make check - - if [ "$GOOS" = "linux" ]; then make check-protos check-api-descriptors; fi - - make build - - make binaries - - if [ "$GOOS" = "linux" ]; then sudo make install ; fi - - if [ "$GOOS" = "linux" ]; then make coverage ; fi - - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make root-coverage ; fi - - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH make integration ; fi - # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 - - if [ "$GOOS" = "linux" ]; then sudo PATH=$PATH GOPATH=$GOPATH TESTFLAGS_PARALLEL=1 make integration ; fi - - if [ "$GOOS" = "linux" ]; then - sudo PATH=$PATH containerd -log-level debug &> /tmp/containerd-cri.log & - sudo ctr version ; - sudo PATH=$PATH GOPATH=$GOPATH critest --runtime-endpoint=/var/run/containerd/containerd.sock --parallel=8 ; - TEST_RC=$? ; - test $TEST_RC -ne 0 && cat /tmp/containerd-cri.log ; - sudo pkill containerd ; - test $TEST_RC -eq 0 || /bin/false ; - fi - -after_success: - - bash <(curl -s https://codecov.io/bash) -F linux - -before_deploy: - - make release - -deploy: - provider: releases - api_key: - secure: HO+WSIVVUMMsbU74x+YyFsTP3ahqnR4xjwKAziedJ5lZXKJszQBhiYTFmcTeVBoouNjTISd07GQzpoLChuGC20U3+1NbT+CkK8xWR/x1ao2D3JY3Ds6AD9ubWRNWRLptt/xOn5Vq3F8xZyUYchwvDMl4zKCuTKxQGVdHKsINb2DehKcP5cVL6MMvqzEdfj2g99vqXAqs8uuo6dOmvxmHV43bfzDaAJSabjZZs6TKlWTqCQMet8uxyx2Dmjl2lxLwdqv12oJdrszacasn41NYuEyHI2bXyef1mhWGYN4n9bU/Y5winctZ8DOSOZvYg/2ziAaUN0+CTn1IESwVesrPz23P2Sy7wdLxu8dSIZ2yUHl7OsA5T5a5rDchAGguRVNBWvoGtuepEhdRacxTQUo1cMFZsEXjgRKKjdfc1emYQPVdN8mBv8GJwndty473ZXdvFt5R0kNVFtvWuYCa6UYJD2cKrsPSAfbZCDC/LiR3FOoTaUPMZUVkR2ACEO7Dn4+KlmBajqT40Osk/A7k1XA/TzVhMIpLtE0Vk2DfPmGsjCv8bC+MFd+R2Sc8SFdE92oEWRdoPQY5SxMYQtGxA+cbKVlT1kSw6y80yEbx5JZsBnT6+NTHwmDO3kVU9ztLdawOozTElKNAK8HoAyFmzIZ3wL64oThuDrv/TUuY8Iyn814= - file_glob: true - file: releases/*.tar.gz - skip_cleanup: true - on: - repo: containerd/containerd - tags: true diff -Nru containerd-1.2.6/unpacker.go containerd-1.5.9/unpacker.go --- containerd-1.2.6/unpacker.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/unpacker.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,353 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containerd + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "math/rand" + "sync" + "sync/atomic" + "time" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/mount" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/snapshots" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/identity" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" + "golang.org/x/sync/semaphore" +) + +const ( + labelSnapshotRef = "containerd.io/snapshot.ref" +) + +type unpacker struct { + updateCh chan ocispec.Descriptor + snapshotter string + config UnpackConfig + c *Client + limiter *semaphore.Weighted +} + +func (c *Client) newUnpacker(ctx context.Context, rCtx *RemoteContext) (*unpacker, error) { + snapshotter, err := c.resolveSnapshotterName(ctx, rCtx.Snapshotter) + if err != nil { + return nil, err + } + var config UnpackConfig + for _, o := range rCtx.UnpackOpts { + if err := o(ctx, &config); err != nil { + return nil, err + } + } + return &unpacker{ + updateCh: make(chan ocispec.Descriptor, 128), + snapshotter: snapshotter, + config: config, + c: c, + }, nil +} + +func (u *unpacker) unpack( + ctx context.Context, + rCtx *RemoteContext, + h images.Handler, + config ocispec.Descriptor, + layers []ocispec.Descriptor, +) error { + p, err := content.ReadBlob(ctx, u.c.ContentStore(), config) + if err != nil { + return err + } + + var i ocispec.Image + if err := json.Unmarshal(p, &i); err != nil { + return errors.Wrap(err, "unmarshal image config") + } + diffIDs := i.RootFS.DiffIDs + if len(layers) != len(diffIDs) { + return errors.Errorf("number of layers and diffIDs don't match: %d != %d", len(layers), len(diffIDs)) + } + + if u.config.CheckPlatformSupported { + imgPlatform := platforms.Normalize(ocispec.Platform{OS: i.OS, Architecture: i.Architecture}) + snapshotterPlatformMatcher, err := u.c.GetSnapshotterSupportedPlatforms(ctx, u.snapshotter) + if err != nil { + return errors.Wrapf(err, "failed to find supported platforms for snapshotter %s", u.snapshotter) + } + if !snapshotterPlatformMatcher.Match(imgPlatform) { + return fmt.Errorf("snapshotter %s does not support platform %s for image %s", u.snapshotter, imgPlatform, config.Digest) + } + } + + var ( + sn = u.c.SnapshotService(u.snapshotter) + a = u.c.DiffService() + cs = u.c.ContentStore() + + chain []digest.Digest + + fetchOffset int + fetchC []chan struct{} + fetchErr chan error + ) + + // If there is an early return, ensure any ongoing + // fetches get their context cancelled + ctx, cancel := context.WithCancel(ctx) + defer cancel() + +EachLayer: + for i, desc := range layers { + parent := identity.ChainID(chain) + chain = append(chain, diffIDs[i]) + + chainID := identity.ChainID(chain).String() + if _, err := sn.Stat(ctx, chainID); err == nil { + // no need to handle + continue + } else if !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to stat snapshot %s", chainID) + } + + // inherits annotations which are provided as snapshot labels. + labels := snapshots.FilterInheritedLabels(desc.Annotations) + if labels == nil { + labels = make(map[string]string) + } + labels[labelSnapshotRef] = chainID + + var ( + key string + mounts []mount.Mount + opts = append(rCtx.SnapshotterOpts, snapshots.WithLabels(labels)) + ) + + for try := 1; try <= 3; try++ { + // Prepare snapshot with from parent, label as root + key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID) + mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) + if err != nil { + if errdefs.IsAlreadyExists(err) { + if _, err := sn.Stat(ctx, chainID); err != nil { + if !errdefs.IsNotFound(err) { + return errors.Wrapf(err, "failed to stat snapshot %s", chainID) + } + // Try again, this should be rare, log it + log.G(ctx).WithField("key", key).WithField("chainid", chainID).Debug("extraction snapshot already exists, chain id not found") + } else { + // no need to handle, snapshot now found with chain id + continue EachLayer + } + } else { + return errors.Wrapf(err, "failed to prepare extraction snapshot %q", key) + } + } else { + break + } + } + if err != nil { + return errors.Wrap(err, "unable to prepare extraction snapshot") + } + + // Abort the snapshot if commit does not happen + abort := func() { + if err := sn.Remove(ctx, key); err != nil { + log.G(ctx).WithError(err).Errorf("failed to cleanup %q", key) + } + } + + if fetchErr == nil { + fetchErr = make(chan error, 1) + fetchOffset = i + fetchC = make([]chan struct{}, len(layers)-fetchOffset) + for i := range fetchC { + fetchC[i] = make(chan struct{}) + } + + go func(i int) { + err := u.fetch(ctx, h, layers[i:], fetchC) + if err != nil { + fetchErr <- err + } + close(fetchErr) + }(i) + } + + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-fetchErr: + if err != nil { + return err + } + case <-fetchC[i-fetchOffset]: + } + + diff, err := a.Apply(ctx, desc, mounts, u.config.ApplyOpts...) + if err != nil { + abort() + return errors.Wrapf(err, "failed to extract layer %s", diffIDs[i]) + } + if diff.Digest != diffIDs[i] { + abort() + return errors.Errorf("wrong diff id calculated on extraction %q", diffIDs[i]) + } + + if err = sn.Commit(ctx, chainID, key, opts...); err != nil { + abort() + if errdefs.IsAlreadyExists(err) { + continue + } + return errors.Wrapf(err, "failed to commit snapshot %s", key) + } + + // Set the uncompressed label after the uncompressed + // digest has been verified through apply. + cinfo := content.Info{ + Digest: desc.Digest, + Labels: map[string]string{ + "containerd.io/uncompressed": diff.Digest.String(), + }, + } + if _, err := cs.Update(ctx, cinfo, "labels.containerd.io/uncompressed"); err != nil { + return err + } + + } + + chainID := identity.ChainID(chain).String() + cinfo := content.Info{ + Digest: config.Digest, + Labels: map[string]string{ + fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", u.snapshotter): chainID, + }, + } + _, err = cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", u.snapshotter)) + if err != nil { + return err + } + log.G(ctx).WithFields(logrus.Fields{ + "config": config.Digest, + "chainID": chainID, + }).Debug("image unpacked") + + return nil +} + +func (u *unpacker) fetch(ctx context.Context, h images.Handler, layers []ocispec.Descriptor, done []chan struct{}) error { + eg, ctx2 := errgroup.WithContext(ctx) + for i, desc := range layers { + desc := desc + i := i + + if u.limiter != nil { + if err := u.limiter.Acquire(ctx, 1); err != nil { + return err + } + } + + eg.Go(func() error { + _, err := h.Handle(ctx2, desc) + if u.limiter != nil { + u.limiter.Release(1) + } + if err != nil && !errors.Is(err, images.ErrSkipDesc) { + return err + } + close(done[i]) + + return nil + }) + } + + return eg.Wait() +} + +func (u *unpacker) handlerWrapper( + uctx context.Context, + rCtx *RemoteContext, + unpacks *int32, +) (func(images.Handler) images.Handler, *errgroup.Group) { + eg, uctx := errgroup.WithContext(uctx) + return func(f images.Handler) images.Handler { + var ( + lock sync.Mutex + layers = map[digest.Digest][]ocispec.Descriptor{} + ) + return images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + children, err := f.Handle(ctx, desc) + if err != nil { + return children, err + } + + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + var nonLayers []ocispec.Descriptor + var manifestLayers []ocispec.Descriptor + + // Split layers from non-layers, layers will be handled after + // the config + for _, child := range children { + if images.IsLayerType(child.MediaType) { + manifestLayers = append(manifestLayers, child) + } else { + nonLayers = append(nonLayers, child) + } + } + + lock.Lock() + for _, nl := range nonLayers { + layers[nl.Digest] = manifestLayers + } + lock.Unlock() + + children = nonLayers + case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: + lock.Lock() + l := layers[desc.Digest] + lock.Unlock() + if len(l) > 0 { + atomic.AddInt32(unpacks, 1) + eg.Go(func() error { + return u.unpack(uctx, rCtx, f, desc, l) + }) + } + } + return children, nil + }) + }, eg +} + +func uniquePart() string { + t := time.Now() + var b [3]byte + // Ignore read failures, just decreases uniqueness + rand.Read(b[:]) + return fmt.Sprintf("%d-%s", t.Nanosecond(), base64.URLEncoding.EncodeToString(b[:])) +} diff -Nru containerd-1.2.6/Vagrantfile containerd-1.5.9/Vagrantfile --- containerd-1.2.6/Vagrantfile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/Vagrantfile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,260 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Copyright The containerd Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Vagrantfile for cgroup2 and SELinux +Vagrant.configure("2") do |config| + config.vm.box = "fedora/34-cloud-base" + memory = 4096 + cpus = 2 + config.vm.provider :virtualbox do |v| + v.memory = memory + v.cpus = cpus + end + config.vm.provider :libvirt do |v| + v.memory = memory + v.cpus = cpus + end + + # Disabled by default. To run: + # vagrant up --provision-with=upgrade-packages + # To upgrade only specific packages: + # UPGRADE_PACKAGES=selinux vagrant up --provision-with=upgrade-packages + # + config.vm.provision "upgrade-packages", type: "shell", run: "never" do |sh| + sh.upload_path = "/tmp/vagrant-upgrade-packages" + sh.env = { + 'UPGRADE_PACKAGES': ENV['UPGRADE_PACKAGES'], + } + sh.inline = <<~SHELL + #!/usr/bin/env bash + set -eux -o pipefail + dnf -y upgrade ${UPGRADE_PACKAGES} + SHELL + end + + # To re-run, installing CNI from RPM: + # INSTALL_PACKAGES="containernetworking-plugins" vagrant up --provision-with=install-packages + # + config.vm.provision "install-packages", type: "shell", run: "once" do |sh| + sh.upload_path = "/tmp/vagrant-install-packages" + sh.env = { + 'INSTALL_PACKAGES': ENV['INSTALL_PACKAGES'], + } + sh.inline = <<~SHELL + #!/usr/bin/env bash + set -eux -o pipefail + dnf -y install \ + container-selinux \ + curl \ + gcc \ + git \ + iptables \ + libseccomp-devel \ + libselinux-devel \ + lsof \ + make \ + ${INSTALL_PACKAGES} + SHELL + end + + # To re-run this provisioner, installing a different version of go: + # GO_VERSION="1.14.6" vagrant up --provision-with=install-golang + # + config.vm.provision "install-golang", type: "shell", run: "once" do |sh| + sh.upload_path = "/tmp/vagrant-install-golang" + sh.env = { + 'GO_VERSION': ENV['GO_VERSION'] || "1.16.12", + } + sh.inline = <<~SHELL + #!/usr/bin/env bash + set -eux -o pipefail + curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local + cat >> /etc/environment <> /etc/profile.d/sh.local < /tmp/containerd.log + systemctl stop containerd + } + selinux=$(getenforce) + if [[ $selinux == Enforcing ]]; then + setenforce 0 + fi + systemctl enable --now ${GOPATH}/src/github.com/containerd/containerd/containerd.service + if [[ $selinux == Enforcing ]]; then + setenforce 1 + fi + trap cleanup EXIT + ctr version + critest --parallel=$(nproc) --report-dir="${REPORT_DIR}" --ginkgo.skip='HostIpc is true' + SHELL + end + +end diff -Nru containerd-1.2.6/vendor/github.com/beorn7/perks/quantile/exampledata.txt containerd-1.5.9/vendor/github.com/beorn7/perks/quantile/exampledata.txt --- containerd-1.2.6/vendor/github.com/beorn7/perks/quantile/exampledata.txt 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/beorn7/perks/quantile/exampledata.txt 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2388 @@ +8 +5 +26 +12 +5 +235 +13 +6 +28 +30 +3 +3 +3 +3 +5 +2 +33 +7 +2 +4 +7 +12 +14 +5 +8 +3 +10 +4 +5 +3 +6 +6 +209 +20 +3 +10 +14 +3 +4 +6 +8 +5 +11 +7 +3 +2 +3 +3 +212 +5 +222 +4 +10 +10 +5 +6 +3 +8 +3 +10 +254 +220 +2 +3 +5 +24 +5 +4 +222 +7 +3 +3 +223 +8 +15 +12 +14 +14 +3 +2 +2 +3 +13 +3 +11 +4 +4 +6 +5 +7 +13 +5 +3 +5 +2 +5 +3 +5 +2 +7 +15 +17 +14 +3 +6 +6 +3 +17 +5 +4 +7 +6 +4 +4 +8 +6 +8 +3 +9 +3 +6 +3 +4 +5 +3 +3 +660 +4 +6 +10 +3 +6 +3 +2 +5 +13 +2 +4 +4 +10 +4 +8 +4 +3 +7 +9 +9 +3 +10 +37 +3 +13 +4 +12 +3 +6 +10 +8 +5 +21 +2 +3 +8 +3 +2 +3 +3 +4 +12 +2 +4 +8 +8 +4 +3 +2 +20 +1 +6 +32 +2 +11 +6 +18 +3 +8 +11 +3 +212 +3 +4 +2 +6 +7 +12 +11 +3 +2 +16 +10 +6 +4 +6 +3 +2 +7 +3 +2 +2 +2 +2 +5 +6 +4 +3 +10 +3 +4 +6 +5 +3 +4 +4 +5 +6 +4 +3 +4 +4 +5 +7 +5 +5 +3 +2 +7 +2 +4 +12 +4 +5 +6 +2 +4 +4 +8 +4 +15 +13 +7 +16 +5 +3 +23 +5 +5 +7 +3 +2 +9 +8 +7 +5 +8 +11 +4 +10 +76 +4 +47 +4 +3 +2 +7 +4 +2 +3 +37 +10 +4 +2 +20 +5 +4 +4 +10 +10 +4 +3 +7 +23 +240 +7 +13 +5 +5 +3 +3 +2 +5 +4 +2 +8 +7 +19 +2 +23 +8 +7 +2 +5 +3 +8 +3 +8 +13 +5 +5 +5 +2 +3 +23 +4 +9 +8 +4 +3 +3 +5 +220 +2 +3 +4 +6 +14 +3 +53 +6 +2 +5 +18 +6 +3 +219 +6 +5 +2 +5 +3 +6 +5 +15 +4 +3 +17 +3 +2 +4 +7 +2 +3 +3 +4 +4 +3 +2 +664 +6 +3 +23 +5 +5 +16 +5 +8 +2 +4 +2 +24 +12 +3 +2 +3 +5 +8 +3 +5 +4 +3 +14 +3 +5 +8 +2 +3 +7 +9 +4 +2 +3 +6 +8 +4 +3 +4 +6 +5 +3 +3 +6 +3 +19 +4 +4 +6 +3 +6 +3 +5 +22 +5 +4 +4 +3 +8 +11 +4 +9 +7 +6 +13 +4 +4 +4 +6 +17 +9 +3 +3 +3 +4 +3 +221 +5 +11 +3 +4 +2 +12 +6 +3 +5 +7 +5 +7 +4 +9 +7 +14 +37 +19 +217 +16 +3 +5 +2 +2 +7 +19 +7 +6 +7 +4 +24 +5 +11 +4 +7 +7 +9 +13 +3 +4 +3 +6 +28 +4 +4 +5 +5 +2 +5 +6 +4 +4 +6 +10 +5 +4 +3 +2 +3 +3 +6 +5 +5 +4 +3 +2 +3 +7 +4 +6 +18 +16 +8 +16 +4 +5 +8 +6 +9 +13 +1545 +6 +215 +6 +5 +6 +3 +45 +31 +5 +2 +2 +4 +3 +3 +2 +5 +4 +3 +5 +7 +7 +4 +5 +8 +5 +4 +749 +2 +31 +9 +11 +2 +11 +5 +4 +4 +7 +9 +11 +4 +5 +4 +7 +3 +4 +6 +2 +15 +3 +4 +3 +4 +3 +5 +2 +13 +5 +5 +3 +3 +23 +4 +4 +5 +7 +4 +13 +2 +4 +3 +4 +2 +6 +2 +7 +3 +5 +5 +3 +29 +5 +4 +4 +3 +10 +2 +3 +79 +16 +6 +6 +7 +7 +3 +5 +5 +7 +4 +3 +7 +9 +5 +6 +5 +9 +6 +3 +6 +4 +17 +2 +10 +9 +3 +6 +2 +3 +21 +22 +5 +11 +4 +2 +17 +2 +224 +2 +14 +3 +4 +4 +2 +4 +4 +4 +4 +5 +3 +4 +4 +10 +2 +6 +3 +3 +5 +7 +2 +7 +5 +6 +3 +218 +2 +2 +5 +2 +6 +3 +5 +222 +14 +6 +33 +3 +2 +5 +3 +3 +3 +9 +5 +3 +3 +2 +7 +4 +3 +4 +3 +5 +6 +5 +26 +4 +13 +9 +7 +3 +221 +3 +3 +4 +4 +4 +4 +2 +18 +5 +3 +7 +9 +6 +8 +3 +10 +3 +11 +9 +5 +4 +17 +5 +5 +6 +6 +3 +2 +4 +12 +17 +6 +7 +218 +4 +2 +4 +10 +3 +5 +15 +3 +9 +4 +3 +3 +6 +29 +3 +3 +4 +5 +5 +3 +8 +5 +6 +6 +7 +5 +3 +5 +3 +29 +2 +31 +5 +15 +24 +16 +5 +207 +4 +3 +3 +2 +15 +4 +4 +13 +5 +5 +4 +6 +10 +2 +7 +8 +4 +6 +20 +5 +3 +4 +3 +12 +12 +5 +17 +7 +3 +3 +3 +6 +10 +3 +5 +25 +80 +4 +9 +3 +2 +11 +3 +3 +2 +3 +8 +7 +5 +5 +19 +5 +3 +3 +12 +11 +2 +6 +5 +5 +5 +3 +3 +3 +4 +209 +14 +3 +2 +5 +19 +4 +4 +3 +4 +14 +5 +6 +4 +13 +9 +7 +4 +7 +10 +2 +9 +5 +7 +2 +8 +4 +6 +5 +5 +222 +8 +7 +12 +5 +216 +3 +4 +4 +6 +3 +14 +8 +7 +13 +4 +3 +3 +3 +3 +17 +5 +4 +3 +33 +6 +6 +33 +7 +5 +3 +8 +7 +5 +2 +9 +4 +2 +233 +24 +7 +4 +8 +10 +3 +4 +15 +2 +16 +3 +3 +13 +12 +7 +5 +4 +207 +4 +2 +4 +27 +15 +2 +5 +2 +25 +6 +5 +5 +6 +13 +6 +18 +6 +4 +12 +225 +10 +7 +5 +2 +2 +11 +4 +14 +21 +8 +10 +3 +5 +4 +232 +2 +5 +5 +3 +7 +17 +11 +6 +6 +23 +4 +6 +3 +5 +4 +2 +17 +3 +6 +5 +8 +3 +2 +2 +14 +9 +4 +4 +2 +5 +5 +3 +7 +6 +12 +6 +10 +3 +6 +2 +2 +19 +5 +4 +4 +9 +2 +4 +13 +3 +5 +6 +3 +6 +5 +4 +9 +6 +3 +5 +7 +3 +6 +6 +4 +3 +10 +6 +3 +221 +3 +5 +3 +6 +4 +8 +5 +3 +6 +4 +4 +2 +54 +5 +6 +11 +3 +3 +4 +4 +4 +3 +7 +3 +11 +11 +7 +10 +6 +13 +223 +213 +15 +231 +7 +3 +7 +228 +2 +3 +4 +4 +5 +6 +7 +4 +13 +3 +4 +5 +3 +6 +4 +6 +7 +2 +4 +3 +4 +3 +3 +6 +3 +7 +3 +5 +18 +5 +6 +8 +10 +3 +3 +3 +2 +4 +2 +4 +4 +5 +6 +6 +4 +10 +13 +3 +12 +5 +12 +16 +8 +4 +19 +11 +2 +4 +5 +6 +8 +5 +6 +4 +18 +10 +4 +2 +216 +6 +6 +6 +2 +4 +12 +8 +3 +11 +5 +6 +14 +5 +3 +13 +4 +5 +4 +5 +3 +28 +6 +3 +7 +219 +3 +9 +7 +3 +10 +6 +3 +4 +19 +5 +7 +11 +6 +15 +19 +4 +13 +11 +3 +7 +5 +10 +2 +8 +11 +2 +6 +4 +6 +24 +6 +3 +3 +3 +3 +6 +18 +4 +11 +4 +2 +5 +10 +8 +3 +9 +5 +3 +4 +5 +6 +2 +5 +7 +4 +4 +14 +6 +4 +4 +5 +5 +7 +2 +4 +3 +7 +3 +3 +6 +4 +5 +4 +4 +4 +3 +3 +3 +3 +8 +14 +2 +3 +5 +3 +2 +4 +5 +3 +7 +3 +3 +18 +3 +4 +4 +5 +7 +3 +3 +3 +13 +5 +4 +8 +211 +5 +5 +3 +5 +2 +5 +4 +2 +655 +6 +3 +5 +11 +2 +5 +3 +12 +9 +15 +11 +5 +12 +217 +2 +6 +17 +3 +3 +207 +5 +5 +4 +5 +9 +3 +2 +8 +5 +4 +3 +2 +5 +12 +4 +14 +5 +4 +2 +13 +5 +8 +4 +225 +4 +3 +4 +5 +4 +3 +3 +6 +23 +9 +2 +6 +7 +233 +4 +4 +6 +18 +3 +4 +6 +3 +4 +4 +2 +3 +7 +4 +13 +227 +4 +3 +5 +4 +2 +12 +9 +17 +3 +7 +14 +6 +4 +5 +21 +4 +8 +9 +2 +9 +25 +16 +3 +6 +4 +7 +8 +5 +2 +3 +5 +4 +3 +3 +5 +3 +3 +3 +2 +3 +19 +2 +4 +3 +4 +2 +3 +4 +4 +2 +4 +3 +3 +3 +2 +6 +3 +17 +5 +6 +4 +3 +13 +5 +3 +3 +3 +4 +9 +4 +2 +14 +12 +4 +5 +24 +4 +3 +37 +12 +11 +21 +3 +4 +3 +13 +4 +2 +3 +15 +4 +11 +4 +4 +3 +8 +3 +4 +4 +12 +8 +5 +3 +3 +4 +2 +220 +3 +5 +223 +3 +3 +3 +10 +3 +15 +4 +241 +9 +7 +3 +6 +6 +23 +4 +13 +7 +3 +4 +7 +4 +9 +3 +3 +4 +10 +5 +5 +1 +5 +24 +2 +4 +5 +5 +6 +14 +3 +8 +2 +3 +5 +13 +13 +3 +5 +2 +3 +15 +3 +4 +2 +10 +4 +4 +4 +5 +5 +3 +5 +3 +4 +7 +4 +27 +3 +6 +4 +15 +3 +5 +6 +6 +5 +4 +8 +3 +9 +2 +6 +3 +4 +3 +7 +4 +18 +3 +11 +3 +3 +8 +9 +7 +24 +3 +219 +7 +10 +4 +5 +9 +12 +2 +5 +4 +4 +4 +3 +3 +19 +5 +8 +16 +8 +6 +22 +3 +23 +3 +242 +9 +4 +3 +3 +5 +7 +3 +3 +5 +8 +3 +7 +5 +14 +8 +10 +3 +4 +3 +7 +4 +6 +7 +4 +10 +4 +3 +11 +3 +7 +10 +3 +13 +6 +8 +12 +10 +5 +7 +9 +3 +4 +7 +7 +10 +8 +30 +9 +19 +4 +3 +19 +15 +4 +13 +3 +215 +223 +4 +7 +4 +8 +17 +16 +3 +7 +6 +5 +5 +4 +12 +3 +7 +4 +4 +13 +4 +5 +2 +5 +6 +5 +6 +6 +7 +10 +18 +23 +9 +3 +3 +6 +5 +2 +4 +2 +7 +3 +3 +2 +5 +5 +14 +10 +224 +6 +3 +4 +3 +7 +5 +9 +3 +6 +4 +2 +5 +11 +4 +3 +3 +2 +8 +4 +7 +4 +10 +7 +3 +3 +18 +18 +17 +3 +3 +3 +4 +5 +3 +3 +4 +12 +7 +3 +11 +13 +5 +4 +7 +13 +5 +4 +11 +3 +12 +3 +6 +4 +4 +21 +4 +6 +9 +5 +3 +10 +8 +4 +6 +4 +4 +6 +5 +4 +8 +6 +4 +6 +4 +4 +5 +9 +6 +3 +4 +2 +9 +3 +18 +2 +4 +3 +13 +3 +6 +6 +8 +7 +9 +3 +2 +16 +3 +4 +6 +3 +2 +33 +22 +14 +4 +9 +12 +4 +5 +6 +3 +23 +9 +4 +3 +5 +5 +3 +4 +5 +3 +5 +3 +10 +4 +5 +5 +8 +4 +4 +6 +8 +5 +4 +3 +4 +6 +3 +3 +3 +5 +9 +12 +6 +5 +9 +3 +5 +3 +2 +2 +2 +18 +3 +2 +21 +2 +5 +4 +6 +4 +5 +10 +3 +9 +3 +2 +10 +7 +3 +6 +6 +4 +4 +8 +12 +7 +3 +7 +3 +3 +9 +3 +4 +5 +4 +4 +5 +5 +10 +15 +4 +4 +14 +6 +227 +3 +14 +5 +216 +22 +5 +4 +2 +2 +6 +3 +4 +2 +9 +9 +4 +3 +28 +13 +11 +4 +5 +3 +3 +2 +3 +3 +5 +3 +4 +3 +5 +23 +26 +3 +4 +5 +6 +4 +6 +3 +5 +5 +3 +4 +3 +2 +2 +2 +7 +14 +3 +6 +7 +17 +2 +2 +15 +14 +16 +4 +6 +7 +13 +6 +4 +5 +6 +16 +3 +3 +28 +3 +6 +15 +3 +9 +2 +4 +6 +3 +3 +22 +4 +12 +6 +7 +2 +5 +4 +10 +3 +16 +6 +9 +2 +5 +12 +7 +5 +5 +5 +5 +2 +11 +9 +17 +4 +3 +11 +7 +3 +5 +15 +4 +3 +4 +211 +8 +7 +5 +4 +7 +6 +7 +6 +3 +6 +5 +6 +5 +3 +4 +4 +26 +4 +6 +10 +4 +4 +3 +2 +3 +3 +4 +5 +9 +3 +9 +4 +4 +5 +5 +8 +2 +4 +2 +3 +8 +4 +11 +19 +5 +8 +6 +3 +5 +6 +12 +3 +2 +4 +16 +12 +3 +4 +4 +8 +6 +5 +6 +6 +219 +8 +222 +6 +16 +3 +13 +19 +5 +4 +3 +11 +6 +10 +4 +7 +7 +12 +5 +3 +3 +5 +6 +10 +3 +8 +2 +5 +4 +7 +2 +4 +4 +2 +12 +9 +6 +4 +2 +40 +2 +4 +10 +4 +223 +4 +2 +20 +6 +7 +24 +5 +4 +5 +2 +20 +16 +6 +5 +13 +2 +3 +3 +19 +3 +2 +4 +5 +6 +7 +11 +12 +5 +6 +7 +7 +3 +5 +3 +5 +3 +14 +3 +4 +4 +2 +11 +1 +7 +3 +9 +6 +11 +12 +5 +8 +6 +221 +4 +2 +12 +4 +3 +15 +4 +5 +226 +7 +218 +7 +5 +4 +5 +18 +4 +5 +9 +4 +4 +2 +9 +18 +18 +9 +5 +6 +6 +3 +3 +7 +3 +5 +4 +4 +4 +12 +3 +6 +31 +5 +4 +7 +3 +6 +5 +6 +5 +11 +2 +2 +11 +11 +6 +7 +5 +8 +7 +10 +5 +23 +7 +4 +3 +5 +34 +2 +5 +23 +7 +3 +6 +8 +4 +4 +4 +2 +5 +3 +8 +5 +4 +8 +25 +2 +3 +17 +8 +3 +4 +8 +7 +3 +15 +6 +5 +7 +21 +9 +5 +6 +6 +5 +3 +2 +3 +10 +3 +6 +3 +14 +7 +4 +4 +8 +7 +8 +2 +6 +12 +4 +213 +6 +5 +21 +8 +2 +5 +23 +3 +11 +2 +3 +6 +25 +2 +3 +6 +7 +6 +6 +4 +4 +6 +3 +17 +9 +7 +6 +4 +3 +10 +7 +2 +3 +3 +3 +11 +8 +3 +7 +6 +4 +14 +36 +3 +4 +3 +3 +22 +13 +21 +4 +2 +7 +4 +4 +17 +15 +3 +7 +11 +2 +4 +7 +6 +209 +6 +3 +2 +2 +24 +4 +9 +4 +3 +3 +3 +29 +2 +2 +4 +3 +3 +5 +4 +6 +3 +3 +2 +4 diff -Nru containerd-1.2.6/vendor/github.com/beorn7/perks/quantile/stream.go containerd-1.5.9/vendor/github.com/beorn7/perks/quantile/stream.go --- containerd-1.2.6/vendor/github.com/beorn7/perks/quantile/stream.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/beorn7/perks/quantile/stream.go 2022-01-05 17:30:58.000000000 +0000 @@ -77,15 +77,20 @@ // is guaranteed to be within (Quantile±Epsilon). // // See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties. -func NewTargeted(targets map[float64]float64) *Stream { +func NewTargeted(targetMap map[float64]float64) *Stream { + // Convert map to slice to avoid slow iterations on a map. + // ƒ is called on the hot path, so converting the map to a slice + // beforehand results in significant CPU savings. + targets := targetMapToSlice(targetMap) + ƒ := func(s *stream, r float64) float64 { var m = math.MaxFloat64 var f float64 - for quantile, epsilon := range targets { - if quantile*s.n <= r { - f = (2 * epsilon * r) / quantile + for _, t := range targets { + if t.quantile*s.n <= r { + f = (2 * t.epsilon * r) / t.quantile } else { - f = (2 * epsilon * (s.n - r)) / (1 - quantile) + f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile) } if f < m { m = f @@ -96,6 +101,25 @@ return newStream(ƒ) } +type target struct { + quantile float64 + epsilon float64 +} + +func targetMapToSlice(targetMap map[float64]float64) []target { + targets := make([]target, 0, len(targetMap)) + + for quantile, epsilon := range targetMap { + t := target{ + quantile: quantile, + epsilon: epsilon, + } + targets = append(targets, t) + } + + return targets +} + // Stream computes quantiles for a stream of float64s. It is not thread-safe by // design. Take care when using across multiple goroutines. type Stream struct { diff -Nru containerd-1.2.6/vendor/github.com/beorn7/perks/README.md containerd-1.5.9/vendor/github.com/beorn7/perks/README.md --- containerd-1.2.6/vendor/github.com/beorn7/perks/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/beorn7/perks/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# Perks for Go (golang.org) - -Perks contains the Go package quantile that computes approximate quantiles over -an unbounded data stream within low memory and CPU bounds. - -For more information and examples, see: -http://godoc.org/github.com/bmizerany/perks - -A very special thank you and shout out to Graham Cormode (Rutgers University), -Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and -Divesh Srivastava (AT&T Labs–Research) for their research and publication of -[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf) - -Thank you, also: -* Armon Dadgar (@armon) -* Andrew Gerrand (@nf) -* Brad Fitzpatrick (@bradfitz) -* Keith Rarick (@kr) - -FAQ: - -Q: Why not move the quantile package into the project root? -A: I want to add more packages to perks later. - -Copyright (C) 2013 Blake Mizerany - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,39 @@ +# Go +# Build your Go project. +# Add steps that test, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/go + +trigger: +- master + +pool: + vmImage: 'Ubuntu-16.04' + +variables: + GOBIN: '$(GOPATH)/bin' # Go binaries path + GOROOT: '/usr/local/go1.11' # Go installation path + GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path + modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code + +steps: +- script: | + mkdir -p '$(GOBIN)' + mkdir -p '$(GOPATH)/pkg' + mkdir -p '$(modulePath)' + shopt -s extglob + shopt -s dotglob + mv !(gopath) '$(modulePath)' + echo '##vso[task.prependpath]$(GOBIN)' + echo '##vso[task.prependpath]$(GOROOT)/bin' + displayName: 'Set up the Go workspace' + +- script: | + go version + go get -v -t -d ./... + if [ -f Gopkg.toml ]; then + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + dep ensure + fi + go build -v . + workingDirectory: '$(modulePath)' + displayName: 'Get dependencies, then build' diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/bitset.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/bitset.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/bitset.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/bitset.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,952 @@ +/* +Package bitset implements bitsets, a mapping +between non-negative integers and boolean values. It should be more +efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing +individual integers. + +But it also provides set intersection, union, difference, +complement, and symmetric operations, as well as tests to +check whether any, all, or no bits are set, and querying a +bitset's current length and number of positive bits. + +BitSets are expanded to the size of the largest set bit; the +memory allocation is approximately Max bits, where Max is +the largest set bit. BitSets are never shrunk. On creation, +a hint can be given for the number of bits that will be used. + +Many of the methods, including Set,Clear, and Flip, return +a BitSet pointer, which allows for chaining. + +Example use: + + import "bitset" + var b BitSet + b.Set(10).Set(11) + if b.Test(1000) { + b.Clear(1000) + } + if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { + fmt.Println("Intersection works.") + } + +As an alternative to BitSets, one should check out the 'big' package, +which provides a (less set-theoretical) view of bitsets. + +*/ +package bitset + +import ( + "bufio" + "bytes" + "encoding/base64" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "io" + "strconv" +) + +// the wordSize of a bit set +const wordSize = uint(64) + +// log2WordSize is lg(wordSize) +const log2WordSize = uint(6) + +// allBits has every bit set +const allBits uint64 = 0xffffffffffffffff + +// default binary BigEndian +var binaryOrder binary.ByteOrder = binary.BigEndian + +// default json encoding base64.URLEncoding +var base64Encoding = base64.URLEncoding + +// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) +func Base64StdEncoding() { base64Encoding = base64.StdEncoding } + +// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) +func LittleEndian() { binaryOrder = binary.LittleEndian } + +// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. +type BitSet struct { + length uint + set []uint64 +} + +// Error is used to distinguish errors (panics) generated in this package. +type Error string + +// safeSet will fixup b.set to be non-nil and return the field value +func (b *BitSet) safeSet() []uint64 { + if b.set == nil { + b.set = make([]uint64, wordsNeeded(0)) + } + return b.set +} + +// From is a constructor used to create a BitSet from an array of integers +func From(buf []uint64) *BitSet { + return &BitSet{uint(len(buf)) * 64, buf} +} + +// Bytes returns the bitset as array of integers +func (b *BitSet) Bytes() []uint64 { + return b.set +} + +// wordsNeeded calculates the number of words needed for i bits +func wordsNeeded(i uint) int { + if i > (Cap() - wordSize + 1) { + return int(Cap() >> log2WordSize) + } + return int((i + (wordSize - 1)) >> log2WordSize) +} + +// New creates a new BitSet with a hint that length bits will be required +func New(length uint) (bset *BitSet) { + defer func() { + if r := recover(); r != nil { + bset = &BitSet{ + 0, + make([]uint64, 0), + } + } + }() + + bset = &BitSet{ + length, + make([]uint64, wordsNeeded(length)), + } + + return bset +} + +// Cap returns the total possible capacity, or number of bits +func Cap() uint { + return ^uint(0) +} + +// Len returns the number of bits in the BitSet. +// Note the difference to method Count, see example. +func (b *BitSet) Len() uint { + return b.length +} + +// extendSetMaybe adds additional words to incorporate new bits if needed +func (b *BitSet) extendSetMaybe(i uint) { + if i >= b.length { // if we need more bits, make 'em + if i >= Cap() { + panic("You are exceeding the capacity") + } + nsize := wordsNeeded(i + 1) + if b.set == nil { + b.set = make([]uint64, nsize) + } else if cap(b.set) >= nsize { + b.set = b.set[:nsize] // fast resize + } else if len(b.set) < nsize { + newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x + copy(newset, b.set) + b.set = newset + } + b.length = i + 1 + } +} + +// Test whether bit i is set. +func (b *BitSet) Test(i uint) bool { + if i >= b.length { + return false + } + return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0 +} + +// Set bit i to 1, the capacity of the bitset is automatically +// increased accordingly. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) Set(i uint) *BitSet { + b.extendSetMaybe(i) + b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1)) + return b +} + +// Clear bit i to 0 +func (b *BitSet) Clear(i uint) *BitSet { + if i >= b.length { + return b + } + b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1)) + return b +} + +// SetTo sets bit i to value. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) SetTo(i uint, value bool) *BitSet { + if value { + return b.Set(i) + } + return b.Clear(i) +} + +// Flip bit at i. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) Flip(i uint) *BitSet { + if i >= b.length { + return b.Set(i) + } + b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1)) + return b +} + +// FlipRange bit in [start, end). +// If end>= Cap(), this function will panic. +// Warning: using a very large value for 'end' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) FlipRange(start, end uint) *BitSet { + if start >= end { + return b + } + + b.extendSetMaybe(end - 1) + var startWord uint = start >> log2WordSize + var endWord uint = end >> log2WordSize + b.set[startWord] ^= ^(^uint64(0) << (start & (wordSize - 1))) + for i := startWord; i < endWord; i++ { + b.set[i] = ^b.set[i] + } + b.set[endWord] ^= ^uint64(0) >> (-end & (wordSize - 1)) + return b +} + +// Shrink shrinks BitSet so that the provided value is the last possible +// set value. It clears all bits > the provided index and reduces the size +// and length of the set. +// +// Note that the parameter value is not the new length in bits: it is the +// maximal value that can be stored in the bitset after the function call. +// The new length in bits is the parameter value + 1. Thus it is not possible +// to use this function to set the length to 0, the minimal value of the length +// after this function call is 1. +// +// A new slice is allocated to store the new bits, so you may see an increase in +// memory usage until the GC runs. Normally this should not be a problem, but if you +// have an extremely large BitSet its important to understand that the old BitSet will +// remain in memory until the GC frees it. +func (b *BitSet) Shrink(lastbitindex uint) *BitSet { + length := lastbitindex + 1 + idx := wordsNeeded(length) + if idx > len(b.set) { + return b + } + shrunk := make([]uint64, idx) + copy(shrunk, b.set[:idx]) + b.set = shrunk + b.length = length + b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)))) + return b +} + +// Compact shrinks BitSet to so that we preserve all set bits, while minimizing +// memory usage. Compact calls Shrink. +func (b *BitSet) Compact() *BitSet { + idx := len(b.set) - 1 + for ; idx >= 0 && b.set[idx] == 0; idx-- { + } + newlength := uint((idx + 1) << log2WordSize) + if newlength >= b.length { + return b // nothing to do + } + if newlength > 0 { + return b.Shrink(newlength - 1) + } + // We preserve one word + return b.Shrink(63) +} + +// InsertAt takes an index which indicates where a bit should be +// inserted. Then it shifts all the bits in the set to the left by 1, starting +// from the given index position, and sets the index position to 0. +// +// Depending on the size of your BitSet, and where you are inserting the new entry, +// this method could be extremely slow and in some cases might cause the entire BitSet +// to be recopied. +func (b *BitSet) InsertAt(idx uint) *BitSet { + insertAtElement := (idx >> log2WordSize) + + // if length of set is a multiple of wordSize we need to allocate more space first + if b.isLenExactMultiple() { + b.set = append(b.set, uint64(0)) + } + + var i uint + for i = uint(len(b.set) - 1); i > insertAtElement; i-- { + // all elements above the position where we want to insert can simply by shifted + b.set[i] <<= 1 + + // we take the most significant bit of the previous element and set it as + // the least significant bit of the current element + b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 + } + + // generate a mask to extract the data that we need to shift left + // within the element where we insert a bit + dataMask := ^(uint64(1)< 0x40000 { + buffer.WriteString("...") + break + } + buffer.WriteString(strconv.FormatInt(int64(i), 10)) + i, e = b.NextSet(i + 1) + if e { + buffer.WriteString(",") + } + } + buffer.WriteString("}") + return buffer.String() +} + +// DeleteAt deletes the bit at the given index position from +// within the bitset +// All the bits residing on the left of the deleted bit get +// shifted right by 1 +// The running time of this operation may potentially be +// relatively slow, O(length) +func (b *BitSet) DeleteAt(i uint) *BitSet { + // the index of the slice element where we'll delete a bit + deleteAtElement := i >> log2WordSize + + // generate a mask for the data that needs to be shifted right + // within that slice element that gets modified + dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1) + + // extract the data that we'll shift right from the slice element + data := b.set[deleteAtElement] & dataMask + + // set the masked area to 0 while leaving the rest as it is + b.set[deleteAtElement] &= ^dataMask + + // shift the previously extracted data to the right and then + // set it in the previously masked area + b.set[deleteAtElement] |= (data >> 1) & dataMask + + // loop over all the consecutive slice elements to copy each + // lowest bit into the highest position of the previous element, + // then shift the entire content to the right by 1 + for i := int(deleteAtElement) + 1; i < len(b.set); i++ { + b.set[i-1] |= (b.set[i] & 1) << 63 + b.set[i] >>= 1 + } + + b.length = b.length - 1 + + return b +} + +// NextSet returns the next bit set from the specified index, +// including possibly the current index +// along with an error code (true = valid, false = no set bit found) +// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} +// +// Users concerned with performance may want to use NextSetMany to +// retrieve several values at once. +func (b *BitSet) NextSet(i uint) (uint, bool) { + x := int(i >> log2WordSize) + if x >= len(b.set) { + return 0, false + } + w := b.set[x] + w = w >> (i & (wordSize - 1)) + if w != 0 { + return i + trailingZeroes64(w), true + } + x = x + 1 + for x < len(b.set) { + if b.set[x] != 0 { + return uint(x)*wordSize + trailingZeroes64(b.set[x]), true + } + x = x + 1 + + } + return 0, false +} + +// NextSetMany returns many next bit sets from the specified index, +// including possibly the current index and up to cap(buffer). +// If the returned slice has len zero, then no more set bits were found +// +// buffer := make([]uint, 256) // this should be reused +// j := uint(0) +// j, buffer = bitmap.NextSetMany(j, buffer) +// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { +// for k := range buffer { +// do something with buffer[k] +// } +// j += 1 +// } +// +// +// It is possible to retrieve all set bits as follow: +// +// indices := make([]uint, bitmap.Count()) +// bitmap.NextSetMany(0, indices) +// +// However if bitmap.Count() is large, it might be preferable to +// use several calls to NextSetMany, for performance reasons. +func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { + myanswer := buffer + capacity := cap(buffer) + x := int(i >> log2WordSize) + if x >= len(b.set) || capacity == 0 { + return 0, myanswer[:0] + } + skip := i & (wordSize - 1) + word := b.set[x] >> skip + myanswer = myanswer[:capacity] + size := int(0) + for word != 0 { + r := trailingZeroes64(word) + t := word & ((^word) + 1) + myanswer[size] = r + i + size++ + if size == capacity { + goto End + } + word = word ^ t + } + x++ + for idx, word := range b.set[x:] { + for word != 0 { + r := trailingZeroes64(word) + t := word & ((^word) + 1) + myanswer[size] = r + (uint(x+idx) << 6) + size++ + if size == capacity { + goto End + } + word = word ^ t + } + } +End: + if size > 0 { + return myanswer[size-1], myanswer[:size] + } + return 0, myanswer[:0] +} + +// NextClear returns the next clear bit from the specified index, +// including possibly the current index +// along with an error code (true = valid, false = no bit found i.e. all bits are set) +func (b *BitSet) NextClear(i uint) (uint, bool) { + x := int(i >> log2WordSize) + if x >= len(b.set) { + return 0, false + } + w := b.set[x] + w = w >> (i & (wordSize - 1)) + wA := allBits >> (i & (wordSize - 1)) + index := i + trailingZeroes64(^w) + if w != wA && index < b.length { + return index, true + } + x++ + for x < len(b.set) { + index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) + if b.set[x] != allBits && index < b.length { + return index, true + } + x++ + } + return 0, false +} + +// ClearAll clears the entire BitSet +func (b *BitSet) ClearAll() *BitSet { + if b != nil && b.set != nil { + for i := range b.set { + b.set[i] = 0 + } + } + return b +} + +// wordCount returns the number of words used in a bit set +func (b *BitSet) wordCount() int { + return len(b.set) +} + +// Clone this BitSet +func (b *BitSet) Clone() *BitSet { + c := New(b.length) + if b.set != nil { // Clone should not modify current object + copy(c.set, b.set) + } + return c +} + +// Copy into a destination BitSet +// Returning the size of the destination BitSet +// like array copy +func (b *BitSet) Copy(c *BitSet) (count uint) { + if c == nil { + return + } + if b.set != nil { // Copy should not modify current object + copy(c.set, b.set) + } + count = c.length + if b.length < c.length { + count = b.length + } + return +} + +// Count (number of set bits). +// Also known as "popcount" or "population count". +func (b *BitSet) Count() uint { + if b != nil && b.set != nil { + return uint(popcntSlice(b.set)) + } + return 0 +} + +// Equal tests the equivalence of two BitSets. +// False if they are of different sizes, otherwise true +// only if all the same bits are set +func (b *BitSet) Equal(c *BitSet) bool { + if c == nil || b == nil { + return c == b + } + if b.length != c.length { + return false + } + if b.length == 0 { // if they have both length == 0, then could have nil set + return true + } + // testing for equality shoud not transform the bitset (no call to safeSet) + + for p, v := range b.set { + if c.set[p] != v { + return false + } + } + return true +} + +func panicIfNull(b *BitSet) { + if b == nil { + panic(Error("BitSet must not be null")) + } +} + +// Difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + result = b.Clone() // clone b (in case b is bigger than compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + result.set[i] = b.set[i] &^ compare.set[i] + } + return +} + +// DifferenceCardinality computes the cardinality of the differnce +func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + cnt := uint64(0) + cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) + cnt += popcntSlice(b.set[l:]) + return uint(cnt) +} + +// InPlaceDifference computes the difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +func (b *BitSet) InPlaceDifference(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + b.set[i] &^= compare.set[i] + } +} + +// Convenience function: return two bitsets ordered by +// increasing length. Note: neither can be nil +func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { + if a.length <= b.length { + ap, bp = a, b + } else { + ap, bp = b, a + } + return +} + +// Intersection of base set and other set +// This is the BitSet equivalent of & (and) +func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = New(b.length) + for i, word := range b.set { + result.set[i] = word & compare.set[i] + } + return +} + +// IntersectionCardinality computes the cardinality of the union +func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntAndSlice(b.set, compare.set) + return uint(cnt) +} + +// InPlaceIntersection destructively computes the intersection of +// base set and the compare set. +// This is the BitSet equivalent of & (and) +func (b *BitSet) InPlaceIntersection(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + for i := 0; i < l; i++ { + b.set[i] &= compare.set[i] + } + for i := l; i < len(b.set); i++ { + b.set[i] = 0 + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } +} + +// Union of base set and other set +// This is the BitSet equivalent of | (or) +func (b *BitSet) Union(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word | compare.set[i] + } + return +} + +// UnionCardinality computes the cardinality of the uniton of the base set +// and the compare set. +func (b *BitSet) UnionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntOrSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceUnion creates the destructive union of base set and compare set. +// This is the BitSet equivalent of | (or). +func (b *BitSet) InPlaceUnion(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } + for i := 0; i < l; i++ { + b.set[i] |= compare.set[i] + } + if len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + // compare is bigger, so clone it + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word ^ compare.set[i] + } + return +} + +// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference +func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntXorSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + if compare.length > 0 { + b.extendSetMaybe(compare.length - 1) + } + for i := 0; i < l; i++ { + b.set[i] ^= compare.set[i] + } + if len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// Is the length an exact multiple of word sizes? +func (b *BitSet) isLenExactMultiple() bool { + return b.length%wordSize == 0 +} + +// Clean last word by setting unused bits to 0 +func (b *BitSet) cleanLastWord() { + if !b.isLenExactMultiple() { + b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize) + } +} + +// Complement computes the (local) complement of a biset (up to length bits) +func (b *BitSet) Complement() (result *BitSet) { + panicIfNull(b) + result = New(b.length) + for i, word := range b.set { + result.set[i] = ^word + } + result.cleanLastWord() + return +} + +// All returns true if all bits are set, false otherwise. Returns true for +// empty sets. +func (b *BitSet) All() bool { + panicIfNull(b) + return b.Count() == b.length +} + +// None returns true if no bit is set, false otherwise. Returns true for +// empty sets. +func (b *BitSet) None() bool { + panicIfNull(b) + if b != nil && b.set != nil { + for _, word := range b.set { + if word > 0 { + return false + } + } + return true + } + return true +} + +// Any returns true if any bit is set, false otherwise +func (b *BitSet) Any() bool { + panicIfNull(b) + return !b.None() +} + +// IsSuperSet returns true if this is a superset of the other set +func (b *BitSet) IsSuperSet(other *BitSet) bool { + for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) { + if !b.Test(i) { + return false + } + } + return true +} + +// IsStrictSuperSet returns true if this is a strict superset of the other set +func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { + return b.Count() > other.Count() && b.IsSuperSet(other) +} + +// DumpAsBits dumps a bit set as a string of bits +func (b *BitSet) DumpAsBits() string { + if b.set == nil { + return "." + } + buffer := bytes.NewBufferString("") + i := len(b.set) - 1 + for ; i >= 0; i-- { + fmt.Fprintf(buffer, "%064b.", b.set[i]) + } + return buffer.String() +} + +// BinaryStorageSize returns the binary storage requirements +func (b *BitSet) BinaryStorageSize() int { + return binary.Size(uint64(0)) + binary.Size(b.set) +} + +// WriteTo writes a BitSet to a stream +func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { + length := uint64(b.length) + + // Write length + err := binary.Write(stream, binaryOrder, length) + if err != nil { + return 0, err + } + + // Write set + err = binary.Write(stream, binaryOrder, b.set) + return int64(b.BinaryStorageSize()), err +} + +// ReadFrom reads a BitSet from a stream written using WriteTo +func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { + var length uint64 + + // Read length first + err := binary.Read(stream, binaryOrder, &length) + if err != nil { + return 0, err + } + newset := New(uint(length)) + + if uint64(newset.length) != length { + return 0, errors.New("unmarshalling error: type mismatch") + } + + // Read remaining bytes as set + err = binary.Read(stream, binaryOrder, newset.set) + if err != nil { + return 0, err + } + + *b = *newset + return int64(b.BinaryStorageSize()), nil +} + +// MarshalBinary encodes a BitSet into a binary form and returns the result. +func (b *BitSet) MarshalBinary() ([]byte, error) { + var buf bytes.Buffer + writer := bufio.NewWriter(&buf) + + _, err := b.WriteTo(writer) + if err != nil { + return []byte{}, err + } + + err = writer.Flush() + + return buf.Bytes(), err +} + +// UnmarshalBinary decodes the binary form generated by MarshalBinary. +func (b *BitSet) UnmarshalBinary(data []byte) error { + buf := bytes.NewReader(data) + reader := bufio.NewReader(buf) + + _, err := b.ReadFrom(reader) + + return err +} + +// MarshalJSON marshals a BitSet as a JSON structure +func (b *BitSet) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) + _, err := b.WriteTo(buffer) + if err != nil { + return nil, err + } + + // URLEncode all bytes + return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) +} + +// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON +func (b *BitSet) UnmarshalJSON(data []byte) error { + // Unmarshal as string + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + // URLDecode string + buf, err := base64Encoding.DecodeString(s) + if err != nil { + return err + } + + _, err = b.ReadFrom(bytes.NewReader(buf)) + return err +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/.gitignore containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/.gitignore --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +target diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/go.mod containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/go.mod --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,3 @@ +module github.com/bits-and-blooms/bitset + +go 1.14 diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/LICENSE containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/LICENSE --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,27 @@ +Copyright (c) 2014 Will Fitzgerald. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,45 @@ +// +build go1.9 + +package bitset + +import "math/bits" + +func popcntSlice(s []uint64) uint64 { + var cnt int + for _, x := range s { + cnt += bits.OnesCount64(x) + } + return uint64(cnt) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] &^ m[i]) + } + return uint64(cnt) +} + +func popcntAndSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] & m[i]) + } + return uint64(cnt) +} + +func popcntOrSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] | m[i]) + } + return uint64(cnt) +} + +func popcntXorSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] ^ m[i]) + } + return uint64(cnt) +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,68 @@ +// +build !go1.9 +// +build amd64,!appengine + +package bitset + +// *** the following functions are defined in popcnt_amd64.s + +//go:noescape + +func hasAsm() bool + +// useAsm is a flag used to select the GO or ASM implementation of the popcnt function +var useAsm = hasAsm() + +//go:noescape + +func popcntSliceAsm(s []uint64) uint64 + +//go:noescape + +func popcntMaskSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntAndSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntOrSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntXorSliceAsm(s, m []uint64) uint64 + +func popcntSlice(s []uint64) uint64 { + if useAsm { + return popcntSliceAsm(s) + } + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + if useAsm { + return popcntMaskSliceAsm(s, m) + } + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + if useAsm { + return popcntAndSliceAsm(s, m) + } + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + if useAsm { + return popcntOrSliceAsm(s, m) + } + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + if useAsm { + return popcntXorSliceAsm(s, m) + } + return popcntXorSliceGo(s, m) +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,104 @@ +// +build !go1.9 +// +build amd64,!appengine + +TEXT ·hasAsm(SB),4,$0-1 +MOVQ $1, AX +CPUID +SHRQ $23, CX +ANDQ $1, CX +MOVB CX, ret+0(FP) +RET + +#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 + +TEXT ·popcntSliceAsm(SB),4,$0-32 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntSliceEnd +popcntSliceLoop: +BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX +ADDQ DX, AX +ADDQ $8, SI +LOOP popcntSliceLoop +popcntSliceEnd: +MOVQ AX, ret+24(FP) +RET + +TEXT ·popcntMaskSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntMaskSliceEnd +MOVQ m+24(FP), DI +popcntMaskSliceLoop: +MOVQ (DI), DX +NOTQ DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntMaskSliceLoop +popcntMaskSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntAndSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntAndSliceEnd +MOVQ m+24(FP), DI +popcntAndSliceLoop: +MOVQ (DI), DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntAndSliceLoop +popcntAndSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntOrSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntOrSliceEnd +MOVQ m+24(FP), DI +popcntOrSliceLoop: +MOVQ (DI), DX +ORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntOrSliceLoop +popcntOrSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntXorSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntXorSliceEnd +MOVQ m+24(FP), DI +popcntXorSliceLoop: +MOVQ (DI), DX +XORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntXorSliceLoop +popcntXorSliceEnd: +MOVQ AX, ret+48(FP) +RET diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,24 @@ +// +build !go1.9 +// +build !amd64 appengine + +package bitset + +func popcntSlice(s []uint64) uint64 { + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + return popcntXorSliceGo(s, m) +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/popcnt.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/popcnt.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,53 @@ +package bitset + +// bit population count, take from +// https://code.google.com/p/go/issues/detail?id=4988#c11 +// credit: https://code.google.com/u/arnehormann/ +func popcount(x uint64) (n uint64) { + x -= (x >> 1) & 0x5555555555555555 + x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 + x += x >> 4 + x &= 0x0f0f0f0f0f0f0f0f + x *= 0x0101010101010101 + return x >> 56 +} + +func popcntSliceGo(s []uint64) uint64 { + cnt := uint64(0) + for _, x := range s { + cnt += popcount(x) + } + return cnt +} + +func popcntMaskSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] &^ m[i]) + } + return cnt +} + +func popcntAndSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] & m[i]) + } + return cnt +} + +func popcntOrSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] | m[i]) + } + return cnt +} + +func popcntXorSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] ^ m[i]) + } + return cnt +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/README.md containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/README.md --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,93 @@ +# bitset + +*Go language library to map between non-negative integers and boolean values* + +[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) +[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc) + + +## Description + +Package bitset implements bitsets, a mapping between non-negative integers and boolean values. +It should be more efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing individual integers. + +But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. + +BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. + +Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining. + +### Example use: + +```go +package main + +import ( + "fmt" + "math/rand" + + "github.com/bits-and-blooms/bitset" +) + +func main() { + fmt.Printf("Hello from BitSet!\n") + var b bitset.BitSet + // play some Go Fish + for i := 0; i < 100; i++ { + card1 := uint(rand.Intn(52)) + card2 := uint(rand.Intn(52)) + b.Set(card1) + if b.Test(card2) { + fmt.Println("Go Fish!") + } + b.Clear(card1) + } + + // Chaining + b.Set(10).Set(11) + + for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { + fmt.Println("The following bit is set:", i) + } + if b.Intersection(bitset.New(100).Set(10)).Count() == 1 { + fmt.Println("Intersection works.") + } else { + fmt.Println("Intersection doesn't work???") + } +} +``` + +As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. + +Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc + +## Memory Usage + +The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). + +## Implementation Note + +Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. + +It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped. + +## Installation + +```bash +go get github.com/bits-and-blooms/bitset +``` + +## Contributing + +If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") + +## Running all tests + +Before committing the code, please check if it passes tests, has adequate coverage, etc. +```bash +go test +go test -cover +``` diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +// +build !go1.9 + +package bitset + +var deBruijn = [...]byte{ + 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, + 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, + 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, + 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, +} + +func trailingZeroes64(v uint64) uint { + return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,9 @@ +// +build go1.9 + +package bitset + +import "math/bits" + +func trailingZeroes64(v uint64) uint { + return uint(bits.TrailingZeros64(v)) +} diff -Nru containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/.travis.yml containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/.travis.yml --- containerd-1.2.6/vendor/github.com/bits-and-blooms/bitset/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/bits-and-blooms/bitset/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +language: go + +sudo: false + +branches: + except: + - release + +branches: + only: + - master + - travis + +go: + - "1.11.x" + - tip + +matrix: + allow_failures: + - go: tip + +before_install: + - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi; + - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi; + - go get github.com/mattn/goveralls + +before_script: + - make deps + +script: + - make qa + +after_failure: + - cat ./target/test/report.xml + +after_success: + - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/json.go containerd-1.5.9/vendor/github.com/blang/semver/json.go --- containerd-1.2.6/vendor/github.com/blang/semver/json.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/json.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -package semver - -import ( - "encoding/json" -) - -// MarshalJSON implements the encoding/json.Marshaler interface. -func (v Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON implements the encoding/json.Unmarshaler interface. -func (v *Version) UnmarshalJSON(data []byte) (err error) { - var versionString string - - if err = json.Unmarshal(data, &versionString); err != nil { - return - } - - *v, err = Parse(versionString) - - return -} diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/LICENSE containerd-1.5.9/vendor/github.com/blang/semver/LICENSE --- containerd-1.2.6/vendor/github.com/blang/semver/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -The MIT License - -Copyright (c) 2014 Benedikt Lang - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/range.go containerd-1.5.9/vendor/github.com/blang/semver/range.go --- containerd-1.2.6/vendor/github.com/blang/semver/range.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/range.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,224 +0,0 @@ -package semver - -import ( - "fmt" - "strings" - "unicode" -) - -type comparator func(Version, Version) bool - -var ( - compEQ comparator = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 0 - } - compNE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) != 0 - } - compGT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 1 - } - compGE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) >= 0 - } - compLT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == -1 - } - compLE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) <= 0 - } -) - -type versionRange struct { - v Version - c comparator -} - -// rangeFunc creates a Range from the given versionRange. -func (vr *versionRange) rangeFunc() Range { - return Range(func(v Version) bool { - return vr.c(v, vr.v) - }) -} - -// Range represents a range of versions. -// A Range can be used to check if a Version satisfies it: -// -// range, err := semver.ParseRange(">1.0.0 <2.0.0") -// range(semver.MustParse("1.1.1") // returns true -type Range func(Version) bool - -// OR combines the existing Range with another Range using logical OR. -func (rf Range) OR(f Range) Range { - return Range(func(v Version) bool { - return rf(v) || f(v) - }) -} - -// AND combines the existing Range with another Range using logical AND. -func (rf Range) AND(f Range) Range { - return Range(func(v Version) bool { - return rf(v) && f(v) - }) -} - -// ParseRange parses a range and returns a Range. -// If the range could not be parsed an error is returned. -// -// Valid ranges are: -// - "<1.0.0" -// - "<=1.0.0" -// - ">1.0.0" -// - ">=1.0.0" -// - "1.0.0", "=1.0.0", "==1.0.0" -// - "!1.0.0", "!=1.0.0" -// -// A Range can consist of multiple ranges separated by space: -// Ranges can be linked by logical AND: -// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" -// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 -// -// Ranges can also be linked by logical OR: -// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" -// -// AND has a higher precedence than OR. It's not possible to use brackets. -// -// Ranges can be combined by both AND and OR -// -// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` -func ParseRange(s string) (Range, error) { - parts := splitAndTrim(s) - orParts, err := splitORParts(parts) - if err != nil { - return nil, err - } - var orFn Range - for _, p := range orParts { - var andFn Range - for _, ap := range p { - opStr, vStr, err := splitComparatorVersion(ap) - if err != nil { - return nil, err - } - vr, err := buildVersionRange(opStr, vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) - } - rf := vr.rangeFunc() - - // Set function - if andFn == nil { - andFn = rf - } else { // Combine with existing function - andFn = andFn.AND(rf) - } - } - if orFn == nil { - orFn = andFn - } else { - orFn = orFn.OR(andFn) - } - - } - return orFn, nil -} - -// splitORParts splits the already cleaned parts by '||'. -// Checks for invalid positions of the operator and returns an -// error if found. -func splitORParts(parts []string) ([][]string, error) { - var ORparts [][]string - last := 0 - for i, p := range parts { - if p == "||" { - if i == 0 { - return nil, fmt.Errorf("First element in range is '||'") - } - ORparts = append(ORparts, parts[last:i]) - last = i + 1 - } - } - if last == len(parts) { - return nil, fmt.Errorf("Last element in range is '||'") - } - ORparts = append(ORparts, parts[last:]) - return ORparts, nil -} - -// buildVersionRange takes a slice of 2: operator and version -// and builds a versionRange, otherwise an error. -func buildVersionRange(opStr, vStr string) (*versionRange, error) { - c := parseComparator(opStr) - if c == nil { - return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) - } - v, err := Parse(vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) - } - - return &versionRange{ - v: v, - c: c, - }, nil - -} - -// splitAndTrim splits a range string by spaces and cleans leading and trailing spaces -func splitAndTrim(s string) (result []string) { - last := 0 - for i := 0; i < len(s); i++ { - if s[i] == ' ' { - if last < i-1 { - result = append(result, s[last:i]) - } - last = i + 1 - } - } - if last < len(s)-1 { - result = append(result, s[last:]) - } - // parts := strings.Split(s, " ") - // for _, x := range parts { - // if s := strings.TrimSpace(x); len(s) != 0 { - // result = append(result, s) - // } - // } - return -} - -// splitComparatorVersion splits the comparator from the version. -// Spaces between the comparator and the version are not allowed. -// Input must be free of leading or trailing spaces. -func splitComparatorVersion(s string) (string, string, error) { - i := strings.IndexFunc(s, unicode.IsDigit) - if i == -1 { - return "", "", fmt.Errorf("Could not get version from string: %q", s) - } - return strings.TrimSpace(s[0:i]), s[i:], nil -} - -func parseComparator(s string) comparator { - switch s { - case "==": - fallthrough - case "": - fallthrough - case "=": - return compEQ - case ">": - return compGT - case ">=": - return compGE - case "<": - return compLT - case "<=": - return compLE - case "!": - fallthrough - case "!=": - return compNE - } - - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/README.md containerd-1.5.9/vendor/github.com/blang/semver/README.md --- containerd-1.2.6/vendor/github.com/blang/semver/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -semver for golang [![Build Status](https://drone.io/github.com/blang/semver/status.png)](https://drone.io/github.com/blang/semver/latest) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) -====== - -semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. - -Usage ------ -```bash -$ go get github.com/blang/semver -``` -Note: Always vendor your dependencies or fix on a specific version tag. - -```go -import github.com/blang/semver -v1, err := semver.Make("1.0.0-beta") -v2, err := semver.Make("2.0.0-beta") -v1.Compare(v2) -``` - -Also check the [GoDocs](http://godoc.org/github.com/blang/semver). - -Why should I use this lib? ------ - -- Fully spec compatible -- No reflection -- No regex -- Fully tested (Coverage >99%) -- Readable parsing/validation errors -- Fast (See [Benchmarks](#benchmarks)) -- Only Stdlib -- Uses values instead of pointers -- Many features, see below - - -Features ------ - -- Parsing and validation at all levels -- Comparator-like comparisons -- Compare Helper Methods -- InPlace manipulation -- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` -- Sortable (implements sort.Interface) -- database/sql compatible (sql.Scanner/Valuer) -- encoding/json compatible (json.Marshaler/Unmarshaler) - -Ranges ------- - -A `Range` is a set of conditions which specify which versions satisfy the range. - -A condition is composed of an operator and a version. The supported operators are: - -- `<1.0.0` Less than `1.0.0` -- `<=1.0.0` Less than or equal to `1.0.0` -- `>1.0.0` Greater than `1.0.0` -- `>=1.0.0` Greater than or equal to `1.0.0` -- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` -- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. - -A `Range` can link multiple `Ranges` separated by space: - -Ranges can be linked by logical AND: - - - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` - - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` - -Ranges can also be linked by logical OR: - - - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` - -AND has a higher precedence than OR. It's not possible to use brackets. - -Ranges can be combined by both AND and OR - - - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` - -Range usage: - -``` -v, err := semver.Parse("1.2.3") -range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") -if range(v) { - //valid -} - -``` - -Example ------ - -Have a look at full examples in [examples/main.go](examples/main.go) - -```go -import github.com/blang/semver - -v, err := semver.Make("0.0.1-alpha.preview+123.github") -fmt.Printf("Major: %d\n", v.Major) -fmt.Printf("Minor: %d\n", v.Minor) -fmt.Printf("Patch: %d\n", v.Patch) -fmt.Printf("Pre: %s\n", v.Pre) -fmt.Printf("Build: %s\n", v.Build) - -// Prerelease versions array -if len(v.Pre) > 0 { - fmt.Println("Prerelease versions:") - for i, pre := range v.Pre { - fmt.Printf("%d: %q\n", i, pre) - } -} - -// Build meta data array -if len(v.Build) > 0 { - fmt.Println("Build meta data:") - for i, build := range v.Build { - fmt.Printf("%d: %q\n", i, build) - } -} - -v001, err := semver.Make("0.0.1") -// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE -v001.GT(v) == true -v.LT(v001) == true -v.GTE(v) == true -v.LTE(v) == true - -// Or use v.Compare(v2) for comparisons (-1, 0, 1): -v001.Compare(v) == 1 -v.Compare(v001) == -1 -v.Compare(v) == 0 - -// Manipulate Version in place: -v.Pre[0], err = semver.NewPRVersion("beta") -if err != nil { - fmt.Printf("Error parsing pre release version: %q", err) -} - -fmt.Println("\nValidate versions:") -v.Build[0] = "?" - -err = v.Validate() -if err != nil { - fmt.Printf("Validation failed: %s\n", err) -} -``` - - -Benchmarks ------ - - BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op - BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op - BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op - BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op - BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op - BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op - BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op - BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op - BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op - BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op - BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op - BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op - BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op - BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op - BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op - BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op - -See benchmark cases at [semver_test.go](semver_test.go) - - -Motivation ------ - -I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. - - -Contribution ------ - -Feel free to make a pull request. For bigger changes create a issue first to discuss about it. - - -License ------ - -See [LICENSE](LICENSE) file. diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/semver.go containerd-1.5.9/vendor/github.com/blang/semver/semver.go --- containerd-1.2.6/vendor/github.com/blang/semver/semver.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/semver.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,395 +0,0 @@ -package semver - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - numbers string = "0123456789" - alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" - alphanum = alphas + numbers -) - -// SpecVersion is the latest fully supported spec version of semver -var SpecVersion = Version{ - Major: 2, - Minor: 0, - Patch: 0, -} - -// Version represents a semver compatible version -type Version struct { - Major uint64 - Minor uint64 - Patch uint64 - Pre []PRVersion - Build []string //No Precendence -} - -// Version to string -func (v Version) String() string { - b := make([]byte, 0, 5) - b = strconv.AppendUint(b, v.Major, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Minor, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Patch, 10) - - if len(v.Pre) > 0 { - b = append(b, '-') - b = append(b, v.Pre[0].String()...) - - for _, pre := range v.Pre[1:] { - b = append(b, '.') - b = append(b, pre.String()...) - } - } - - if len(v.Build) > 0 { - b = append(b, '+') - b = append(b, v.Build[0]...) - - for _, build := range v.Build[1:] { - b = append(b, '.') - b = append(b, build...) - } - } - - return string(b) -} - -// Equals checks if v is equal to o. -func (v Version) Equals(o Version) bool { - return (v.Compare(o) == 0) -} - -// EQ checks if v is equal to o. -func (v Version) EQ(o Version) bool { - return (v.Compare(o) == 0) -} - -// NE checks if v is not equal to o. -func (v Version) NE(o Version) bool { - return (v.Compare(o) != 0) -} - -// GT checks if v is greater than o. -func (v Version) GT(o Version) bool { - return (v.Compare(o) == 1) -} - -// GTE checks if v is greater than or equal to o. -func (v Version) GTE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// GE checks if v is greater than or equal to o. -func (v Version) GE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// LT checks if v is less than o. -func (v Version) LT(o Version) bool { - return (v.Compare(o) == -1) -} - -// LTE checks if v is less than or equal to o. -func (v Version) LTE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// LE checks if v is less than or equal to o. -func (v Version) LE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// Compare compares Versions v to o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v Version) Compare(o Version) int { - if v.Major != o.Major { - if v.Major > o.Major { - return 1 - } - return -1 - } - if v.Minor != o.Minor { - if v.Minor > o.Minor { - return 1 - } - return -1 - } - if v.Patch != o.Patch { - if v.Patch > o.Patch { - return 1 - } - return -1 - } - - // Quick comparison if a version has no prerelease versions - if len(v.Pre) == 0 && len(o.Pre) == 0 { - return 0 - } else if len(v.Pre) == 0 && len(o.Pre) > 0 { - return 1 - } else if len(v.Pre) > 0 && len(o.Pre) == 0 { - return -1 - } - - i := 0 - for ; i < len(v.Pre) && i < len(o.Pre); i++ { - if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { - continue - } else if comp == 1 { - return 1 - } else { - return -1 - } - } - - // If all pr versions are the equal but one has further prversion, this one greater - if i == len(v.Pre) && i == len(o.Pre) { - return 0 - } else if i == len(v.Pre) && i < len(o.Pre) { - return -1 - } else { - return 1 - } - -} - -// Validate validates v and returns error in case -func (v Version) Validate() error { - // Major, Minor, Patch already validated using uint64 - - for _, pre := range v.Pre { - if !pre.IsNum { //Numeric prerelease versions already uint64 - if len(pre.VersionStr) == 0 { - return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) - } - if !containsOnly(pre.VersionStr, alphanum) { - return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) - } - } - } - - for _, build := range v.Build { - if len(build) == 0 { - return fmt.Errorf("Build meta data can not be empty %q", build) - } - if !containsOnly(build, alphanum) { - return fmt.Errorf("Invalid character(s) found in build meta data %q", build) - } - } - - return nil -} - -// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error -func New(s string) (vp *Version, err error) { - v, err := Parse(s) - vp = &v - return -} - -// Make is an alias for Parse, parses version string and returns a validated Version or error -func Make(s string) (Version, error) { - return Parse(s) -} - -// Parse parses version string and returns a validated Version or error -func Parse(s string) (Version, error) { - if len(s) == 0 { - return Version{}, errors.New("Version string empty") - } - - // Split into major.minor.(patch+pr+meta) - parts := strings.SplitN(s, ".", 3) - if len(parts) != 3 { - return Version{}, errors.New("No Major.Minor.Patch elements found") - } - - // Major - if !containsOnly(parts[0], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) - } - if hasLeadingZeroes(parts[0]) { - return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) - } - major, err := strconv.ParseUint(parts[0], 10, 64) - if err != nil { - return Version{}, err - } - - // Minor - if !containsOnly(parts[1], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) - } - if hasLeadingZeroes(parts[1]) { - return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) - } - minor, err := strconv.ParseUint(parts[1], 10, 64) - if err != nil { - return Version{}, err - } - - v := Version{} - v.Major = major - v.Minor = minor - - var build, prerelease []string - patchStr := parts[2] - - if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { - build = strings.Split(patchStr[buildIndex+1:], ".") - patchStr = patchStr[:buildIndex] - } - - if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { - prerelease = strings.Split(patchStr[preIndex+1:], ".") - patchStr = patchStr[:preIndex] - } - - if !containsOnly(patchStr, numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) - } - if hasLeadingZeroes(patchStr) { - return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) - } - patch, err := strconv.ParseUint(patchStr, 10, 64) - if err != nil { - return Version{}, err - } - - v.Patch = patch - - // Prerelease - for _, prstr := range prerelease { - parsedPR, err := NewPRVersion(prstr) - if err != nil { - return Version{}, err - } - v.Pre = append(v.Pre, parsedPR) - } - - // Build meta data - for _, str := range build { - if len(str) == 0 { - return Version{}, errors.New("Build meta data is empty") - } - if !containsOnly(str, alphanum) { - return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) - } - v.Build = append(v.Build, str) - } - - return v, nil -} - -// MustParse is like Parse but panics if the version cannot be parsed. -func MustParse(s string) Version { - v, err := Parse(s) - if err != nil { - panic(`semver: Parse(` + s + `): ` + err.Error()) - } - return v -} - -// PRVersion represents a PreRelease Version -type PRVersion struct { - VersionStr string - VersionNum uint64 - IsNum bool -} - -// NewPRVersion creates a new valid prerelease version -func NewPRVersion(s string) (PRVersion, error) { - if len(s) == 0 { - return PRVersion{}, errors.New("Prerelease is empty") - } - v := PRVersion{} - if containsOnly(s, numbers) { - if hasLeadingZeroes(s) { - return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) - } - num, err := strconv.ParseUint(s, 10, 64) - - // Might never be hit, but just in case - if err != nil { - return PRVersion{}, err - } - v.VersionNum = num - v.IsNum = true - } else if containsOnly(s, alphanum) { - v.VersionStr = s - v.IsNum = false - } else { - return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) - } - return v, nil -} - -// IsNumeric checks if prerelease-version is numeric -func (v PRVersion) IsNumeric() bool { - return v.IsNum -} - -// Compare compares two PreRelease Versions v and o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v PRVersion) Compare(o PRVersion) int { - if v.IsNum && !o.IsNum { - return -1 - } else if !v.IsNum && o.IsNum { - return 1 - } else if v.IsNum && o.IsNum { - if v.VersionNum == o.VersionNum { - return 0 - } else if v.VersionNum > o.VersionNum { - return 1 - } else { - return -1 - } - } else { // both are Alphas - if v.VersionStr == o.VersionStr { - return 0 - } else if v.VersionStr > o.VersionStr { - return 1 - } else { - return -1 - } - } -} - -// PreRelease version to string -func (v PRVersion) String() string { - if v.IsNum { - return strconv.FormatUint(v.VersionNum, 10) - } - return v.VersionStr -} - -func containsOnly(s string, set string) bool { - return strings.IndexFunc(s, func(r rune) bool { - return !strings.ContainsRune(set, r) - }) == -1 -} - -func hasLeadingZeroes(s string) bool { - return len(s) > 1 && s[0] == '0' -} - -// NewBuildVersion creates a new valid build version -func NewBuildVersion(s string) (string, error) { - if len(s) == 0 { - return "", errors.New("Buildversion is empty") - } - if !containsOnly(s, alphanum) { - return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) - } - return s, nil -} diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/sort.go containerd-1.5.9/vendor/github.com/blang/semver/sort.go --- containerd-1.2.6/vendor/github.com/blang/semver/sort.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/sort.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -package semver - -import ( - "sort" -) - -// Versions represents multiple versions. -type Versions []Version - -// Len returns length of version collection -func (s Versions) Len() int { - return len(s) -} - -// Swap swaps two versions inside the collection by its indices -func (s Versions) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less checks if version at index i is less than version at index j -func (s Versions) Less(i, j int) bool { - return s[i].LT(s[j]) -} - -// Sort sorts a slice of versions -func Sort(versions []Version) { - sort.Sort(Versions(versions)) -} diff -Nru containerd-1.2.6/vendor/github.com/blang/semver/sql.go containerd-1.5.9/vendor/github.com/blang/semver/sql.go --- containerd-1.2.6/vendor/github.com/blang/semver/sql.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/blang/semver/sql.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -package semver - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements the database/sql.Scanner interface. -func (v *Version) Scan(src interface{}) (err error) { - var str string - switch src := src.(type) { - case string: - str = src - case []byte: - str = string(src) - default: - return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) - } - - if t, err := Parse(str); err == nil { - *v = t - } - - return -} - -// Value implements the database/sql/driver.Valuer interface. -func (v Version) Value() (driver.Value, error) { - return v.String(), nil -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/COPYING containerd-1.5.9/vendor/github.com/BurntSushi/toml/COPYING --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/COPYING 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/COPYING 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 TOML authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/decode.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/decode.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/decode.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/decode.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,509 +0,0 @@ -package toml - -import ( - "fmt" - "io" - "io/ioutil" - "math" - "reflect" - "strings" - "time" -) - -func e(format string, args ...interface{}) error { - return fmt.Errorf("toml: "+format, args...) -} - -// Unmarshaler is the interface implemented by objects that can unmarshal a -// TOML description of themselves. -type Unmarshaler interface { - UnmarshalTOML(interface{}) error -} - -// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`. -func Unmarshal(p []byte, v interface{}) error { - _, err := Decode(string(p), v) - return err -} - -// Primitive is a TOML value that hasn't been decoded into a Go value. -// When using the various `Decode*` functions, the type `Primitive` may -// be given to any value, and its decoding will be delayed. -// -// A `Primitive` value can be decoded using the `PrimitiveDecode` function. -// -// The underlying representation of a `Primitive` value is subject to change. -// Do not rely on it. -// -// N.B. Primitive values are still parsed, so using them will only avoid -// the overhead of reflection. They can be useful when you don't know the -// exact type of TOML data until run time. -type Primitive struct { - undecoded interface{} - context Key -} - -// DEPRECATED! -// -// Use MetaData.PrimitiveDecode instead. -func PrimitiveDecode(primValue Primitive, v interface{}) error { - md := MetaData{decoded: make(map[string]bool)} - return md.unify(primValue.undecoded, rvalue(v)) -} - -// PrimitiveDecode is just like the other `Decode*` functions, except it -// decodes a TOML value that has already been parsed. Valid primitive values -// can *only* be obtained from values filled by the decoder functions, -// including this method. (i.e., `v` may contain more `Primitive` -// values.) -// -// Meta data for primitive values is included in the meta data returned by -// the `Decode*` functions with one exception: keys returned by the Undecoded -// method will only reflect keys that were decoded. Namely, any keys hidden -// behind a Primitive will be considered undecoded. Executing this method will -// update the undecoded keys in the meta data. (See the example.) -func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { - md.context = primValue.context - defer func() { md.context = nil }() - return md.unify(primValue.undecoded, rvalue(v)) -} - -// Decode will decode the contents of `data` in TOML format into a pointer -// `v`. -// -// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be -// used interchangeably.) -// -// TOML arrays of tables correspond to either a slice of structs or a slice -// of maps. -// -// TOML datetimes correspond to Go `time.Time` values. -// -// All other TOML types (float, string, int, bool and array) correspond -// to the obvious Go types. -// -// An exception to the above rules is if a type implements the -// encoding.TextUnmarshaler interface. In this case, any primitive TOML value -// (floats, strings, integers, booleans and datetimes) will be converted to -// a byte string and given to the value's UnmarshalText method. See the -// Unmarshaler example for a demonstration with time duration strings. -// -// Key mapping -// -// TOML keys can map to either keys in a Go map or field names in a Go -// struct. The special `toml` struct tag may be used to map TOML keys to -// struct fields that don't match the key name exactly. (See the example.) -// A case insensitive match to struct names will be tried if an exact match -// can't be found. -// -// The mapping between TOML values and Go values is loose. That is, there -// may exist TOML values that cannot be placed into your representation, and -// there may be parts of your representation that do not correspond to -// TOML values. This loose mapping can be made stricter by using the IsDefined -// and/or Undecoded methods on the MetaData returned. -// -// This decoder will not handle cyclic types. If a cyclic type is passed, -// `Decode` will not terminate. -func Decode(data string, v interface{}) (MetaData, error) { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr { - return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v)) - } - if rv.IsNil() { - return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v)) - } - p, err := parse(data) - if err != nil { - return MetaData{}, err - } - md := MetaData{ - p.mapping, p.types, p.ordered, - make(map[string]bool, len(p.ordered)), nil, - } - return md, md.unify(p.mapping, indirect(rv)) -} - -// DecodeFile is just like Decode, except it will automatically read the -// contents of the file at `fpath` and decode it for you. -func DecodeFile(fpath string, v interface{}) (MetaData, error) { - bs, err := ioutil.ReadFile(fpath) - if err != nil { - return MetaData{}, err - } - return Decode(string(bs), v) -} - -// DecodeReader is just like Decode, except it will consume all bytes -// from the reader and decode it for you. -func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { - bs, err := ioutil.ReadAll(r) - if err != nil { - return MetaData{}, err - } - return Decode(string(bs), v) -} - -// unify performs a sort of type unification based on the structure of `rv`, -// which is the client representation. -// -// Any type mismatch produces an error. Finding a type that we don't know -// how to handle produces an unsupported type error. -func (md *MetaData) unify(data interface{}, rv reflect.Value) error { - - // Special case. Look for a `Primitive` value. - if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() { - // Save the undecoded data and the key context into the primitive - // value. - context := make(Key, len(md.context)) - copy(context, md.context) - rv.Set(reflect.ValueOf(Primitive{ - undecoded: data, - context: context, - })) - return nil - } - - // Special case. Unmarshaler Interface support. - if rv.CanAddr() { - if v, ok := rv.Addr().Interface().(Unmarshaler); ok { - return v.UnmarshalTOML(data) - } - } - - // Special case. Handle time.Time values specifically. - // TODO: Remove this code when we decide to drop support for Go 1.1. - // This isn't necessary in Go 1.2 because time.Time satisfies the encoding - // interfaces. - if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) { - return md.unifyDatetime(data, rv) - } - - // Special case. Look for a value satisfying the TextUnmarshaler interface. - if v, ok := rv.Interface().(TextUnmarshaler); ok { - return md.unifyText(data, v) - } - // BUG(burntsushi) - // The behavior here is incorrect whenever a Go type satisfies the - // encoding.TextUnmarshaler interface but also corresponds to a TOML - // hash or array. In particular, the unmarshaler should only be applied - // to primitive TOML values. But at this point, it will be applied to - // all kinds of values and produce an incorrect error whenever those values - // are hashes or arrays (including arrays of tables). - - k := rv.Kind() - - // laziness - if k >= reflect.Int && k <= reflect.Uint64 { - return md.unifyInt(data, rv) - } - switch k { - case reflect.Ptr: - elem := reflect.New(rv.Type().Elem()) - err := md.unify(data, reflect.Indirect(elem)) - if err != nil { - return err - } - rv.Set(elem) - return nil - case reflect.Struct: - return md.unifyStruct(data, rv) - case reflect.Map: - return md.unifyMap(data, rv) - case reflect.Array: - return md.unifyArray(data, rv) - case reflect.Slice: - return md.unifySlice(data, rv) - case reflect.String: - return md.unifyString(data, rv) - case reflect.Bool: - return md.unifyBool(data, rv) - case reflect.Interface: - // we only support empty interfaces. - if rv.NumMethod() > 0 { - return e("unsupported type %s", rv.Type()) - } - return md.unifyAnything(data, rv) - case reflect.Float32: - fallthrough - case reflect.Float64: - return md.unifyFloat64(data, rv) - } - return e("unsupported type %s", rv.Kind()) -} - -func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { - tmap, ok := mapping.(map[string]interface{}) - if !ok { - if mapping == nil { - return nil - } - return e("type mismatch for %s: expected table but found %T", - rv.Type().String(), mapping) - } - - for key, datum := range tmap { - var f *field - fields := cachedTypeFields(rv.Type()) - for i := range fields { - ff := &fields[i] - if ff.name == key { - f = ff - break - } - if f == nil && strings.EqualFold(ff.name, key) { - f = ff - } - } - if f != nil { - subv := rv - for _, i := range f.index { - subv = indirect(subv.Field(i)) - } - if isUnifiable(subv) { - md.decoded[md.context.add(key).String()] = true - md.context = append(md.context, key) - if err := md.unify(datum, subv); err != nil { - return err - } - md.context = md.context[0 : len(md.context)-1] - } else if f.name != "" { - // Bad user! No soup for you! - return e("cannot write unexported field %s.%s", - rv.Type().String(), f.name) - } - } - } - return nil -} - -func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { - tmap, ok := mapping.(map[string]interface{}) - if !ok { - if tmap == nil { - return nil - } - return badtype("map", mapping) - } - if rv.IsNil() { - rv.Set(reflect.MakeMap(rv.Type())) - } - for k, v := range tmap { - md.decoded[md.context.add(k).String()] = true - md.context = append(md.context, k) - - rvkey := indirect(reflect.New(rv.Type().Key())) - rvval := reflect.Indirect(reflect.New(rv.Type().Elem())) - if err := md.unify(v, rvval); err != nil { - return err - } - md.context = md.context[0 : len(md.context)-1] - - rvkey.SetString(k) - rv.SetMapIndex(rvkey, rvval) - } - return nil -} - -func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { - datav := reflect.ValueOf(data) - if datav.Kind() != reflect.Slice { - if !datav.IsValid() { - return nil - } - return badtype("slice", data) - } - sliceLen := datav.Len() - if sliceLen != rv.Len() { - return e("expected array length %d; got TOML array of length %d", - rv.Len(), sliceLen) - } - return md.unifySliceArray(datav, rv) -} - -func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { - datav := reflect.ValueOf(data) - if datav.Kind() != reflect.Slice { - if !datav.IsValid() { - return nil - } - return badtype("slice", data) - } - n := datav.Len() - if rv.IsNil() || rv.Cap() < n { - rv.Set(reflect.MakeSlice(rv.Type(), n, n)) - } - rv.SetLen(n) - return md.unifySliceArray(datav, rv) -} - -func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { - sliceLen := data.Len() - for i := 0; i < sliceLen; i++ { - v := data.Index(i).Interface() - sliceval := indirect(rv.Index(i)) - if err := md.unify(v, sliceval); err != nil { - return err - } - } - return nil -} - -func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error { - if _, ok := data.(time.Time); ok { - rv.Set(reflect.ValueOf(data)) - return nil - } - return badtype("time.Time", data) -} - -func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { - if s, ok := data.(string); ok { - rv.SetString(s) - return nil - } - return badtype("string", data) -} - -func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { - if num, ok := data.(float64); ok { - switch rv.Kind() { - case reflect.Float32: - fallthrough - case reflect.Float64: - rv.SetFloat(num) - default: - panic("bug") - } - return nil - } - return badtype("float", data) -} - -func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { - if num, ok := data.(int64); ok { - if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 { - switch rv.Kind() { - case reflect.Int, reflect.Int64: - // No bounds checking necessary. - case reflect.Int8: - if num < math.MinInt8 || num > math.MaxInt8 { - return e("value %d is out of range for int8", num) - } - case reflect.Int16: - if num < math.MinInt16 || num > math.MaxInt16 { - return e("value %d is out of range for int16", num) - } - case reflect.Int32: - if num < math.MinInt32 || num > math.MaxInt32 { - return e("value %d is out of range for int32", num) - } - } - rv.SetInt(num) - } else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 { - unum := uint64(num) - switch rv.Kind() { - case reflect.Uint, reflect.Uint64: - // No bounds checking necessary. - case reflect.Uint8: - if num < 0 || unum > math.MaxUint8 { - return e("value %d is out of range for uint8", num) - } - case reflect.Uint16: - if num < 0 || unum > math.MaxUint16 { - return e("value %d is out of range for uint16", num) - } - case reflect.Uint32: - if num < 0 || unum > math.MaxUint32 { - return e("value %d is out of range for uint32", num) - } - } - rv.SetUint(unum) - } else { - panic("unreachable") - } - return nil - } - return badtype("integer", data) -} - -func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { - if b, ok := data.(bool); ok { - rv.SetBool(b) - return nil - } - return badtype("boolean", data) -} - -func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { - rv.Set(reflect.ValueOf(data)) - return nil -} - -func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error { - var s string - switch sdata := data.(type) { - case TextMarshaler: - text, err := sdata.MarshalText() - if err != nil { - return err - } - s = string(text) - case fmt.Stringer: - s = sdata.String() - case string: - s = sdata - case bool: - s = fmt.Sprintf("%v", sdata) - case int64: - s = fmt.Sprintf("%d", sdata) - case float64: - s = fmt.Sprintf("%f", sdata) - default: - return badtype("primitive (string-like)", data) - } - if err := v.UnmarshalText([]byte(s)); err != nil { - return err - } - return nil -} - -// rvalue returns a reflect.Value of `v`. All pointers are resolved. -func rvalue(v interface{}) reflect.Value { - return indirect(reflect.ValueOf(v)) -} - -// indirect returns the value pointed to by a pointer. -// Pointers are followed until the value is not a pointer. -// New values are allocated for each nil pointer. -// -// An exception to this rule is if the value satisfies an interface of -// interest to us (like encoding.TextUnmarshaler). -func indirect(v reflect.Value) reflect.Value { - if v.Kind() != reflect.Ptr { - if v.CanSet() { - pv := v.Addr() - if _, ok := pv.Interface().(TextUnmarshaler); ok { - return pv - } - } - return v - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - return indirect(reflect.Indirect(v)) -} - -func isUnifiable(rv reflect.Value) bool { - if rv.CanSet() { - return true - } - if _, ok := rv.Interface().(TextUnmarshaler); ok { - return true - } - return false -} - -func badtype(expected string, data interface{}) error { - return e("cannot load TOML value of type %T into a Go %s", data, expected) -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/decode_meta.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/decode_meta.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/decode_meta.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/decode_meta.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -package toml - -import "strings" - -// MetaData allows access to meta information about TOML data that may not -// be inferrable via reflection. In particular, whether a key has been defined -// and the TOML type of a key. -type MetaData struct { - mapping map[string]interface{} - types map[string]tomlType - keys []Key - decoded map[string]bool - context Key // Used only during decoding. -} - -// IsDefined returns true if the key given exists in the TOML data. The key -// should be specified hierarchially. e.g., -// -// // access the TOML key 'a.b.c' -// IsDefined("a", "b", "c") -// -// IsDefined will return false if an empty key given. Keys are case sensitive. -func (md *MetaData) IsDefined(key ...string) bool { - if len(key) == 0 { - return false - } - - var hash map[string]interface{} - var ok bool - var hashOrVal interface{} = md.mapping - for _, k := range key { - if hash, ok = hashOrVal.(map[string]interface{}); !ok { - return false - } - if hashOrVal, ok = hash[k]; !ok { - return false - } - } - return true -} - -// Type returns a string representation of the type of the key specified. -// -// Type will return the empty string if given an empty key or a key that -// does not exist. Keys are case sensitive. -func (md *MetaData) Type(key ...string) string { - fullkey := strings.Join(key, ".") - if typ, ok := md.types[fullkey]; ok { - return typ.typeString() - } - return "" -} - -// Key is the type of any TOML key, including key groups. Use (MetaData).Keys -// to get values of this type. -type Key []string - -func (k Key) String() string { - return strings.Join(k, ".") -} - -func (k Key) maybeQuotedAll() string { - var ss []string - for i := range k { - ss = append(ss, k.maybeQuoted(i)) - } - return strings.Join(ss, ".") -} - -func (k Key) maybeQuoted(i int) string { - quote := false - for _, c := range k[i] { - if !isBareKeyChar(c) { - quote = true - break - } - } - if quote { - return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" - } - return k[i] -} - -func (k Key) add(piece string) Key { - newKey := make(Key, len(k)+1) - copy(newKey, k) - newKey[len(k)] = piece - return newKey -} - -// Keys returns a slice of every key in the TOML data, including key groups. -// Each key is itself a slice, where the first element is the top of the -// hierarchy and the last is the most specific. -// -// The list will have the same order as the keys appeared in the TOML data. -// -// All keys returned are non-empty. -func (md *MetaData) Keys() []Key { - return md.keys -} - -// Undecoded returns all keys that have not been decoded in the order in which -// they appear in the original TOML document. -// -// This includes keys that haven't been decoded because of a Primitive value. -// Once the Primitive value is decoded, the keys will be considered decoded. -// -// Also note that decoding into an empty interface will result in no decoding, -// and so no keys will be considered decoded. -// -// In this sense, the Undecoded keys correspond to keys in the TOML document -// that do not have a concrete type in your representation. -func (md *MetaData) Undecoded() []Key { - undecoded := make([]Key, 0, len(md.keys)) - for _, key := range md.keys { - if !md.decoded[key.String()] { - undecoded = append(undecoded, key) - } - } - return undecoded -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/doc.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/doc.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/doc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/doc.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* -Package toml provides facilities for decoding and encoding TOML configuration -files via reflection. There is also support for delaying decoding with -the Primitive type, and querying the set of keys in a TOML document with the -MetaData type. - -The specification implemented: https://github.com/toml-lang/toml - -The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify -whether a file is a valid TOML document. It can also be used to print the -type of each key in a TOML document. - -Testing - -There are two important types of tests used for this package. The first is -contained inside '*_test.go' files and uses the standard Go unit testing -framework. These tests are primarily devoted to holistically testing the -decoder and encoder. - -The second type of testing is used to verify the implementation's adherence -to the TOML specification. These tests have been factored into their own -project: https://github.com/BurntSushi/toml-test - -The reason the tests are in a separate project is so that they can be used by -any implementation of TOML. Namely, it is language agnostic. -*/ -package toml diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/encode.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/encode.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/encode.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/encode.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,568 +0,0 @@ -package toml - -import ( - "bufio" - "errors" - "fmt" - "io" - "reflect" - "sort" - "strconv" - "strings" - "time" -) - -type tomlEncodeError struct{ error } - -var ( - errArrayMixedElementTypes = errors.New( - "toml: cannot encode array with mixed element types") - errArrayNilElement = errors.New( - "toml: cannot encode array with nil element") - errNonString = errors.New( - "toml: cannot encode a map with non-string key type") - errAnonNonStruct = errors.New( - "toml: cannot encode an anonymous field that is not a struct") - errArrayNoTable = errors.New( - "toml: TOML array element cannot contain a table") - errNoKey = errors.New( - "toml: top-level values must be Go maps or structs") - errAnything = errors.New("") // used in testing -) - -var quotedReplacer = strings.NewReplacer( - "\t", "\\t", - "\n", "\\n", - "\r", "\\r", - "\"", "\\\"", - "\\", "\\\\", -) - -// Encoder controls the encoding of Go values to a TOML document to some -// io.Writer. -// -// The indentation level can be controlled with the Indent field. -type Encoder struct { - // A single indentation level. By default it is two spaces. - Indent string - - // hasWritten is whether we have written any output to w yet. - hasWritten bool - w *bufio.Writer -} - -// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer -// given. By default, a single indentation level is 2 spaces. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: bufio.NewWriter(w), - Indent: " ", - } -} - -// Encode writes a TOML representation of the Go value to the underlying -// io.Writer. If the value given cannot be encoded to a valid TOML document, -// then an error is returned. -// -// The mapping between Go values and TOML values should be precisely the same -// as for the Decode* functions. Similarly, the TextMarshaler interface is -// supported by encoding the resulting bytes as strings. (If you want to write -// arbitrary binary data then you will need to use something like base64 since -// TOML does not have any binary types.) -// -// When encoding TOML hashes (i.e., Go maps or structs), keys without any -// sub-hashes are encoded first. -// -// If a Go map is encoded, then its keys are sorted alphabetically for -// deterministic output. More control over this behavior may be provided if -// there is demand for it. -// -// Encoding Go values without a corresponding TOML representation---like map -// types with non-string keys---will cause an error to be returned. Similarly -// for mixed arrays/slices, arrays/slices with nil elements, embedded -// non-struct types and nested slices containing maps or structs. -// (e.g., [][]map[string]string is not allowed but []map[string]string is OK -// and so is []map[string][]string.) -func (enc *Encoder) Encode(v interface{}) error { - rv := eindirect(reflect.ValueOf(v)) - if err := enc.safeEncode(Key([]string{}), rv); err != nil { - return err - } - return enc.w.Flush() -} - -func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) { - defer func() { - if r := recover(); r != nil { - if terr, ok := r.(tomlEncodeError); ok { - err = terr.error - return - } - panic(r) - } - }() - enc.encode(key, rv) - return nil -} - -func (enc *Encoder) encode(key Key, rv reflect.Value) { - // Special case. Time needs to be in ISO8601 format. - // Special case. If we can marshal the type to text, then we used that. - // Basically, this prevents the encoder for handling these types as - // generic structs (or whatever the underlying type of a TextMarshaler is). - switch rv.Interface().(type) { - case time.Time, TextMarshaler: - enc.keyEqElement(key, rv) - return - } - - k := rv.Kind() - switch k { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64, - reflect.Float32, reflect.Float64, reflect.String, reflect.Bool: - enc.keyEqElement(key, rv) - case reflect.Array, reflect.Slice: - if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) { - enc.eArrayOfTables(key, rv) - } else { - enc.keyEqElement(key, rv) - } - case reflect.Interface: - if rv.IsNil() { - return - } - enc.encode(key, rv.Elem()) - case reflect.Map: - if rv.IsNil() { - return - } - enc.eTable(key, rv) - case reflect.Ptr: - if rv.IsNil() { - return - } - enc.encode(key, rv.Elem()) - case reflect.Struct: - enc.eTable(key, rv) - default: - panic(e("unsupported type for key '%s': %s", key, k)) - } -} - -// eElement encodes any value that can be an array element (primitives and -// arrays). -func (enc *Encoder) eElement(rv reflect.Value) { - switch v := rv.Interface().(type) { - case time.Time: - // Special case time.Time as a primitive. Has to come before - // TextMarshaler below because time.Time implements - // encoding.TextMarshaler, but we need to always use UTC. - enc.wf(v.UTC().Format("2006-01-02T15:04:05Z")) - return - case TextMarshaler: - // Special case. Use text marshaler if it's available for this value. - if s, err := v.MarshalText(); err != nil { - encPanic(err) - } else { - enc.writeQuoted(string(s)) - } - return - } - switch rv.Kind() { - case reflect.Bool: - enc.wf(strconv.FormatBool(rv.Bool())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64: - enc.wf(strconv.FormatInt(rv.Int(), 10)) - case reflect.Uint, reflect.Uint8, reflect.Uint16, - reflect.Uint32, reflect.Uint64: - enc.wf(strconv.FormatUint(rv.Uint(), 10)) - case reflect.Float32: - enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32))) - case reflect.Float64: - enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64))) - case reflect.Array, reflect.Slice: - enc.eArrayOrSliceElement(rv) - case reflect.Interface: - enc.eElement(rv.Elem()) - case reflect.String: - enc.writeQuoted(rv.String()) - default: - panic(e("unexpected primitive type: %s", rv.Kind())) - } -} - -// By the TOML spec, all floats must have a decimal with at least one -// number on either side. -func floatAddDecimal(fstr string) string { - if !strings.Contains(fstr, ".") { - return fstr + ".0" - } - return fstr -} - -func (enc *Encoder) writeQuoted(s string) { - enc.wf("\"%s\"", quotedReplacer.Replace(s)) -} - -func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) { - length := rv.Len() - enc.wf("[") - for i := 0; i < length; i++ { - elem := rv.Index(i) - enc.eElement(elem) - if i != length-1 { - enc.wf(", ") - } - } - enc.wf("]") -} - -func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) { - if len(key) == 0 { - encPanic(errNoKey) - } - for i := 0; i < rv.Len(); i++ { - trv := rv.Index(i) - if isNil(trv) { - continue - } - panicIfInvalidKey(key) - enc.newline() - enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll()) - enc.newline() - enc.eMapOrStruct(key, trv) - } -} - -func (enc *Encoder) eTable(key Key, rv reflect.Value) { - panicIfInvalidKey(key) - if len(key) == 1 { - // Output an extra newline between top-level tables. - // (The newline isn't written if nothing else has been written though.) - enc.newline() - } - if len(key) > 0 { - enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll()) - enc.newline() - } - enc.eMapOrStruct(key, rv) -} - -func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) { - switch rv := eindirect(rv); rv.Kind() { - case reflect.Map: - enc.eMap(key, rv) - case reflect.Struct: - enc.eStruct(key, rv) - default: - panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String()) - } -} - -func (enc *Encoder) eMap(key Key, rv reflect.Value) { - rt := rv.Type() - if rt.Key().Kind() != reflect.String { - encPanic(errNonString) - } - - // Sort keys so that we have deterministic output. And write keys directly - // underneath this key first, before writing sub-structs or sub-maps. - var mapKeysDirect, mapKeysSub []string - for _, mapKey := range rv.MapKeys() { - k := mapKey.String() - if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) { - mapKeysSub = append(mapKeysSub, k) - } else { - mapKeysDirect = append(mapKeysDirect, k) - } - } - - var writeMapKeys = func(mapKeys []string) { - sort.Strings(mapKeys) - for _, mapKey := range mapKeys { - mrv := rv.MapIndex(reflect.ValueOf(mapKey)) - if isNil(mrv) { - // Don't write anything for nil fields. - continue - } - enc.encode(key.add(mapKey), mrv) - } - } - writeMapKeys(mapKeysDirect) - writeMapKeys(mapKeysSub) -} - -func (enc *Encoder) eStruct(key Key, rv reflect.Value) { - // Write keys for fields directly under this key first, because if we write - // a field that creates a new table, then all keys under it will be in that - // table (not the one we're writing here). - rt := rv.Type() - var fieldsDirect, fieldsSub [][]int - var addFields func(rt reflect.Type, rv reflect.Value, start []int) - addFields = func(rt reflect.Type, rv reflect.Value, start []int) { - for i := 0; i < rt.NumField(); i++ { - f := rt.Field(i) - // skip unexported fields - if f.PkgPath != "" && !f.Anonymous { - continue - } - frv := rv.Field(i) - if f.Anonymous { - t := f.Type - switch t.Kind() { - case reflect.Struct: - // Treat anonymous struct fields with - // tag names as though they are not - // anonymous, like encoding/json does. - if getOptions(f.Tag).name == "" { - addFields(t, frv, f.Index) - continue - } - case reflect.Ptr: - if t.Elem().Kind() == reflect.Struct && - getOptions(f.Tag).name == "" { - if !frv.IsNil() { - addFields(t.Elem(), frv.Elem(), f.Index) - } - continue - } - // Fall through to the normal field encoding logic below - // for non-struct anonymous fields. - } - } - - if typeIsHash(tomlTypeOfGo(frv)) { - fieldsSub = append(fieldsSub, append(start, f.Index...)) - } else { - fieldsDirect = append(fieldsDirect, append(start, f.Index...)) - } - } - } - addFields(rt, rv, nil) - - var writeFields = func(fields [][]int) { - for _, fieldIndex := range fields { - sft := rt.FieldByIndex(fieldIndex) - sf := rv.FieldByIndex(fieldIndex) - if isNil(sf) { - // Don't write anything for nil fields. - continue - } - - opts := getOptions(sft.Tag) - if opts.skip { - continue - } - keyName := sft.Name - if opts.name != "" { - keyName = opts.name - } - if opts.omitempty && isEmpty(sf) { - continue - } - if opts.omitzero && isZero(sf) { - continue - } - - enc.encode(key.add(keyName), sf) - } - } - writeFields(fieldsDirect) - writeFields(fieldsSub) -} - -// tomlTypeName returns the TOML type name of the Go value's type. It is -// used to determine whether the types of array elements are mixed (which is -// forbidden). If the Go value is nil, then it is illegal for it to be an array -// element, and valueIsNil is returned as true. - -// Returns the TOML type of a Go value. The type may be `nil`, which means -// no concrete TOML type could be found. -func tomlTypeOfGo(rv reflect.Value) tomlType { - if isNil(rv) || !rv.IsValid() { - return nil - } - switch rv.Kind() { - case reflect.Bool: - return tomlBool - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, - reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, - reflect.Uint64: - return tomlInteger - case reflect.Float32, reflect.Float64: - return tomlFloat - case reflect.Array, reflect.Slice: - if typeEqual(tomlHash, tomlArrayType(rv)) { - return tomlArrayHash - } - return tomlArray - case reflect.Ptr, reflect.Interface: - return tomlTypeOfGo(rv.Elem()) - case reflect.String: - return tomlString - case reflect.Map: - return tomlHash - case reflect.Struct: - switch rv.Interface().(type) { - case time.Time: - return tomlDatetime - case TextMarshaler: - return tomlString - default: - return tomlHash - } - default: - panic("unexpected reflect.Kind: " + rv.Kind().String()) - } -} - -// tomlArrayType returns the element type of a TOML array. The type returned -// may be nil if it cannot be determined (e.g., a nil slice or a zero length -// slize). This function may also panic if it finds a type that cannot be -// expressed in TOML (such as nil elements, heterogeneous arrays or directly -// nested arrays of tables). -func tomlArrayType(rv reflect.Value) tomlType { - if isNil(rv) || !rv.IsValid() || rv.Len() == 0 { - return nil - } - firstType := tomlTypeOfGo(rv.Index(0)) - if firstType == nil { - encPanic(errArrayNilElement) - } - - rvlen := rv.Len() - for i := 1; i < rvlen; i++ { - elem := rv.Index(i) - switch elemType := tomlTypeOfGo(elem); { - case elemType == nil: - encPanic(errArrayNilElement) - case !typeEqual(firstType, elemType): - encPanic(errArrayMixedElementTypes) - } - } - // If we have a nested array, then we must make sure that the nested - // array contains ONLY primitives. - // This checks arbitrarily nested arrays. - if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) { - nest := tomlArrayType(eindirect(rv.Index(0))) - if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) { - encPanic(errArrayNoTable) - } - } - return firstType -} - -type tagOptions struct { - skip bool // "-" - name string - omitempty bool - omitzero bool -} - -func getOptions(tag reflect.StructTag) tagOptions { - t := tag.Get("toml") - if t == "-" { - return tagOptions{skip: true} - } - var opts tagOptions - parts := strings.Split(t, ",") - opts.name = parts[0] - for _, s := range parts[1:] { - switch s { - case "omitempty": - opts.omitempty = true - case "omitzero": - opts.omitzero = true - } - } - return opts -} - -func isZero(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint() == 0 - case reflect.Float32, reflect.Float64: - return rv.Float() == 0.0 - } - return false -} - -func isEmpty(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Array, reflect.Slice, reflect.Map, reflect.String: - return rv.Len() == 0 - case reflect.Bool: - return !rv.Bool() - } - return false -} - -func (enc *Encoder) newline() { - if enc.hasWritten { - enc.wf("\n") - } -} - -func (enc *Encoder) keyEqElement(key Key, val reflect.Value) { - if len(key) == 0 { - encPanic(errNoKey) - } - panicIfInvalidKey(key) - enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1)) - enc.eElement(val) - enc.newline() -} - -func (enc *Encoder) wf(format string, v ...interface{}) { - if _, err := fmt.Fprintf(enc.w, format, v...); err != nil { - encPanic(err) - } - enc.hasWritten = true -} - -func (enc *Encoder) indentStr(key Key) string { - return strings.Repeat(enc.Indent, len(key)-1) -} - -func encPanic(err error) { - panic(tomlEncodeError{err}) -} - -func eindirect(v reflect.Value) reflect.Value { - switch v.Kind() { - case reflect.Ptr, reflect.Interface: - return eindirect(v.Elem()) - default: - return v - } -} - -func isNil(rv reflect.Value) bool { - switch rv.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return rv.IsNil() - default: - return false - } -} - -func panicIfInvalidKey(key Key) { - for _, k := range key { - if len(k) == 0 { - encPanic(e("Key '%s' is not a valid table name. Key names "+ - "cannot be empty.", key.maybeQuotedAll())) - } - } -} - -func isValidKeyName(s string) bool { - return len(s) != 0 -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/encoding_types_1.1.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -// +build !go1.2 - -package toml - -// These interfaces were introduced in Go 1.2, so we add them manually when -// compiling for Go 1.1. - -// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here -// so that Go 1.1 can be supported. -type TextMarshaler interface { - MarshalText() (text []byte, err error) -} - -// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined -// here so that Go 1.1 can be supported. -type TextUnmarshaler interface { - UnmarshalText(text []byte) error -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/encoding_types.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/encoding_types.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/encoding_types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/encoding_types.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -// +build go1.2 - -package toml - -// In order to support Go 1.1, we define our own TextMarshaler and -// TextUnmarshaler types. For Go 1.2+, we just alias them with the -// standard library interfaces. - -import ( - "encoding" -) - -// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here -// so that Go 1.1 can be supported. -type TextMarshaler encoding.TextMarshaler - -// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined -// here so that Go 1.1 can be supported. -type TextUnmarshaler encoding.TextUnmarshaler diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/lex.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/lex.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/lex.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/lex.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,953 +0,0 @@ -package toml - -import ( - "fmt" - "strings" - "unicode" - "unicode/utf8" -) - -type itemType int - -const ( - itemError itemType = iota - itemNIL // used in the parser to indicate no type - itemEOF - itemText - itemString - itemRawString - itemMultilineString - itemRawMultilineString - itemBool - itemInteger - itemFloat - itemDatetime - itemArray // the start of an array - itemArrayEnd - itemTableStart - itemTableEnd - itemArrayTableStart - itemArrayTableEnd - itemKeyStart - itemCommentStart - itemInlineTableStart - itemInlineTableEnd -) - -const ( - eof = 0 - comma = ',' - tableStart = '[' - tableEnd = ']' - arrayTableStart = '[' - arrayTableEnd = ']' - tableSep = '.' - keySep = '=' - arrayStart = '[' - arrayEnd = ']' - commentStart = '#' - stringStart = '"' - stringEnd = '"' - rawStringStart = '\'' - rawStringEnd = '\'' - inlineTableStart = '{' - inlineTableEnd = '}' -) - -type stateFn func(lx *lexer) stateFn - -type lexer struct { - input string - start int - pos int - line int - state stateFn - items chan item - - // Allow for backing up up to three runes. - // This is necessary because TOML contains 3-rune tokens (""" and '''). - prevWidths [3]int - nprev int // how many of prevWidths are in use - // If we emit an eof, we can still back up, but it is not OK to call - // next again. - atEOF bool - - // A stack of state functions used to maintain context. - // The idea is to reuse parts of the state machine in various places. - // For example, values can appear at the top level or within arbitrarily - // nested arrays. The last state on the stack is used after a value has - // been lexed. Similarly for comments. - stack []stateFn -} - -type item struct { - typ itemType - val string - line int -} - -func (lx *lexer) nextItem() item { - for { - select { - case item := <-lx.items: - return item - default: - lx.state = lx.state(lx) - } - } -} - -func lex(input string) *lexer { - lx := &lexer{ - input: input, - state: lexTop, - line: 1, - items: make(chan item, 10), - stack: make([]stateFn, 0, 10), - } - return lx -} - -func (lx *lexer) push(state stateFn) { - lx.stack = append(lx.stack, state) -} - -func (lx *lexer) pop() stateFn { - if len(lx.stack) == 0 { - return lx.errorf("BUG in lexer: no states to pop") - } - last := lx.stack[len(lx.stack)-1] - lx.stack = lx.stack[0 : len(lx.stack)-1] - return last -} - -func (lx *lexer) current() string { - return lx.input[lx.start:lx.pos] -} - -func (lx *lexer) emit(typ itemType) { - lx.items <- item{typ, lx.current(), lx.line} - lx.start = lx.pos -} - -func (lx *lexer) emitTrim(typ itemType) { - lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line} - lx.start = lx.pos -} - -func (lx *lexer) next() (r rune) { - if lx.atEOF { - panic("next called after EOF") - } - if lx.pos >= len(lx.input) { - lx.atEOF = true - return eof - } - - if lx.input[lx.pos] == '\n' { - lx.line++ - } - lx.prevWidths[2] = lx.prevWidths[1] - lx.prevWidths[1] = lx.prevWidths[0] - if lx.nprev < 3 { - lx.nprev++ - } - r, w := utf8.DecodeRuneInString(lx.input[lx.pos:]) - lx.prevWidths[0] = w - lx.pos += w - return r -} - -// ignore skips over the pending input before this point. -func (lx *lexer) ignore() { - lx.start = lx.pos -} - -// backup steps back one rune. Can be called only twice between calls to next. -func (lx *lexer) backup() { - if lx.atEOF { - lx.atEOF = false - return - } - if lx.nprev < 1 { - panic("backed up too far") - } - w := lx.prevWidths[0] - lx.prevWidths[0] = lx.prevWidths[1] - lx.prevWidths[1] = lx.prevWidths[2] - lx.nprev-- - lx.pos -= w - if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { - lx.line-- - } -} - -// accept consumes the next rune if it's equal to `valid`. -func (lx *lexer) accept(valid rune) bool { - if lx.next() == valid { - return true - } - lx.backup() - return false -} - -// peek returns but does not consume the next rune in the input. -func (lx *lexer) peek() rune { - r := lx.next() - lx.backup() - return r -} - -// skip ignores all input that matches the given predicate. -func (lx *lexer) skip(pred func(rune) bool) { - for { - r := lx.next() - if pred(r) { - continue - } - lx.backup() - lx.ignore() - return - } -} - -// errorf stops all lexing by emitting an error and returning `nil`. -// Note that any value that is a character is escaped if it's a special -// character (newlines, tabs, etc.). -func (lx *lexer) errorf(format string, values ...interface{}) stateFn { - lx.items <- item{ - itemError, - fmt.Sprintf(format, values...), - lx.line, - } - return nil -} - -// lexTop consumes elements at the top level of TOML data. -func lexTop(lx *lexer) stateFn { - r := lx.next() - if isWhitespace(r) || isNL(r) { - return lexSkip(lx, lexTop) - } - switch r { - case commentStart: - lx.push(lexTop) - return lexCommentStart - case tableStart: - return lexTableStart - case eof: - if lx.pos > lx.start { - return lx.errorf("unexpected EOF") - } - lx.emit(itemEOF) - return nil - } - - // At this point, the only valid item can be a key, so we back up - // and let the key lexer do the rest. - lx.backup() - lx.push(lexTopEnd) - return lexKeyStart -} - -// lexTopEnd is entered whenever a top-level item has been consumed. (A value -// or a table.) It must see only whitespace, and will turn back to lexTop -// upon a newline. If it sees EOF, it will quit the lexer successfully. -func lexTopEnd(lx *lexer) stateFn { - r := lx.next() - switch { - case r == commentStart: - // a comment will read to a newline for us. - lx.push(lexTop) - return lexCommentStart - case isWhitespace(r): - return lexTopEnd - case isNL(r): - lx.ignore() - return lexTop - case r == eof: - lx.emit(itemEOF) - return nil - } - return lx.errorf("expected a top-level item to end with a newline, "+ - "comment, or EOF, but got %q instead", r) -} - -// lexTable lexes the beginning of a table. Namely, it makes sure that -// it starts with a character other than '.' and ']'. -// It assumes that '[' has already been consumed. -// It also handles the case that this is an item in an array of tables. -// e.g., '[[name]]'. -func lexTableStart(lx *lexer) stateFn { - if lx.peek() == arrayTableStart { - lx.next() - lx.emit(itemArrayTableStart) - lx.push(lexArrayTableEnd) - } else { - lx.emit(itemTableStart) - lx.push(lexTableEnd) - } - return lexTableNameStart -} - -func lexTableEnd(lx *lexer) stateFn { - lx.emit(itemTableEnd) - return lexTopEnd -} - -func lexArrayTableEnd(lx *lexer) stateFn { - if r := lx.next(); r != arrayTableEnd { - return lx.errorf("expected end of table array name delimiter %q, "+ - "but got %q instead", arrayTableEnd, r) - } - lx.emit(itemArrayTableEnd) - return lexTopEnd -} - -func lexTableNameStart(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.peek(); { - case r == tableEnd || r == eof: - return lx.errorf("unexpected end of table name " + - "(table names cannot be empty)") - case r == tableSep: - return lx.errorf("unexpected table separator " + - "(table names cannot be empty)") - case r == stringStart || r == rawStringStart: - lx.ignore() - lx.push(lexTableNameEnd) - return lexValue // reuse string lexing - default: - return lexBareTableName - } -} - -// lexBareTableName lexes the name of a table. It assumes that at least one -// valid character for the table has already been read. -func lexBareTableName(lx *lexer) stateFn { - r := lx.next() - if isBareKeyChar(r) { - return lexBareTableName - } - lx.backup() - lx.emit(itemText) - return lexTableNameEnd -} - -// lexTableNameEnd reads the end of a piece of a table name, optionally -// consuming whitespace. -func lexTableNameEnd(lx *lexer) stateFn { - lx.skip(isWhitespace) - switch r := lx.next(); { - case isWhitespace(r): - return lexTableNameEnd - case r == tableSep: - lx.ignore() - return lexTableNameStart - case r == tableEnd: - return lx.pop() - default: - return lx.errorf("expected '.' or ']' to end table name, "+ - "but got %q instead", r) - } -} - -// lexKeyStart consumes a key name up until the first non-whitespace character. -// lexKeyStart will ignore whitespace. -func lexKeyStart(lx *lexer) stateFn { - r := lx.peek() - switch { - case r == keySep: - return lx.errorf("unexpected key separator %q", keySep) - case isWhitespace(r) || isNL(r): - lx.next() - return lexSkip(lx, lexKeyStart) - case r == stringStart || r == rawStringStart: - lx.ignore() - lx.emit(itemKeyStart) - lx.push(lexKeyEnd) - return lexValue // reuse string lexing - default: - lx.ignore() - lx.emit(itemKeyStart) - return lexBareKey - } -} - -// lexBareKey consumes the text of a bare key. Assumes that the first character -// (which is not whitespace) has not yet been consumed. -func lexBareKey(lx *lexer) stateFn { - switch r := lx.next(); { - case isBareKeyChar(r): - return lexBareKey - case isWhitespace(r): - lx.backup() - lx.emit(itemText) - return lexKeyEnd - case r == keySep: - lx.backup() - lx.emit(itemText) - return lexKeyEnd - default: - return lx.errorf("bare keys cannot contain %q", r) - } -} - -// lexKeyEnd consumes the end of a key and trims whitespace (up to the key -// separator). -func lexKeyEnd(lx *lexer) stateFn { - switch r := lx.next(); { - case r == keySep: - return lexSkip(lx, lexValue) - case isWhitespace(r): - return lexSkip(lx, lexKeyEnd) - default: - return lx.errorf("expected key separator %q, but got %q instead", - keySep, r) - } -} - -// lexValue starts the consumption of a value anywhere a value is expected. -// lexValue will ignore whitespace. -// After a value is lexed, the last state on the next is popped and returned. -func lexValue(lx *lexer) stateFn { - // We allow whitespace to precede a value, but NOT newlines. - // In array syntax, the array states are responsible for ignoring newlines. - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexValue) - case isDigit(r): - lx.backup() // avoid an extra state and use the same as above - return lexNumberOrDateStart - } - switch r { - case arrayStart: - lx.ignore() - lx.emit(itemArray) - return lexArrayValue - case inlineTableStart: - lx.ignore() - lx.emit(itemInlineTableStart) - return lexInlineTableValue - case stringStart: - if lx.accept(stringStart) { - if lx.accept(stringStart) { - lx.ignore() // Ignore """ - return lexMultilineString - } - lx.backup() - } - lx.ignore() // ignore the '"' - return lexString - case rawStringStart: - if lx.accept(rawStringStart) { - if lx.accept(rawStringStart) { - lx.ignore() // Ignore """ - return lexMultilineRawString - } - lx.backup() - } - lx.ignore() // ignore the "'" - return lexRawString - case '+', '-': - return lexNumberStart - case '.': // special error case, be kind to users - return lx.errorf("floats must start with a digit, not '.'") - } - if unicode.IsLetter(r) { - // Be permissive here; lexBool will give a nice error if the - // user wrote something like - // x = foo - // (i.e. not 'true' or 'false' but is something else word-like.) - lx.backup() - return lexBool - } - return lx.errorf("expected value but found %q instead", r) -} - -// lexArrayValue consumes one value in an array. It assumes that '[' or ',' -// have already been consumed. All whitespace and newlines are ignored. -func lexArrayValue(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r) || isNL(r): - return lexSkip(lx, lexArrayValue) - case r == commentStart: - lx.push(lexArrayValue) - return lexCommentStart - case r == comma: - return lx.errorf("unexpected comma") - case r == arrayEnd: - // NOTE(caleb): The spec isn't clear about whether you can have - // a trailing comma or not, so we'll allow it. - return lexArrayEnd - } - - lx.backup() - lx.push(lexArrayValueEnd) - return lexValue -} - -// lexArrayValueEnd consumes everything between the end of an array value and -// the next value (or the end of the array): it ignores whitespace and newlines -// and expects either a ',' or a ']'. -func lexArrayValueEnd(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r) || isNL(r): - return lexSkip(lx, lexArrayValueEnd) - case r == commentStart: - lx.push(lexArrayValueEnd) - return lexCommentStart - case r == comma: - lx.ignore() - return lexArrayValue // move on to the next value - case r == arrayEnd: - return lexArrayEnd - } - return lx.errorf( - "expected a comma or array terminator %q, but got %q instead", - arrayEnd, r, - ) -} - -// lexArrayEnd finishes the lexing of an array. -// It assumes that a ']' has just been consumed. -func lexArrayEnd(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemArrayEnd) - return lx.pop() -} - -// lexInlineTableValue consumes one key/value pair in an inline table. -// It assumes that '{' or ',' have already been consumed. Whitespace is ignored. -func lexInlineTableValue(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexInlineTableValue) - case isNL(r): - return lx.errorf("newlines not allowed within inline tables") - case r == commentStart: - lx.push(lexInlineTableValue) - return lexCommentStart - case r == comma: - return lx.errorf("unexpected comma") - case r == inlineTableEnd: - return lexInlineTableEnd - } - lx.backup() - lx.push(lexInlineTableValueEnd) - return lexKeyStart -} - -// lexInlineTableValueEnd consumes everything between the end of an inline table -// key/value pair and the next pair (or the end of the table): -// it ignores whitespace and expects either a ',' or a '}'. -func lexInlineTableValueEnd(lx *lexer) stateFn { - r := lx.next() - switch { - case isWhitespace(r): - return lexSkip(lx, lexInlineTableValueEnd) - case isNL(r): - return lx.errorf("newlines not allowed within inline tables") - case r == commentStart: - lx.push(lexInlineTableValueEnd) - return lexCommentStart - case r == comma: - lx.ignore() - return lexInlineTableValue - case r == inlineTableEnd: - return lexInlineTableEnd - } - return lx.errorf("expected a comma or an inline table terminator %q, "+ - "but got %q instead", inlineTableEnd, r) -} - -// lexInlineTableEnd finishes the lexing of an inline table. -// It assumes that a '}' has just been consumed. -func lexInlineTableEnd(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemInlineTableEnd) - return lx.pop() -} - -// lexString consumes the inner contents of a string. It assumes that the -// beginning '"' has already been consumed and ignored. -func lexString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == eof: - return lx.errorf("unexpected EOF") - case isNL(r): - return lx.errorf("strings cannot contain newlines") - case r == '\\': - lx.push(lexString) - return lexStringEscape - case r == stringEnd: - lx.backup() - lx.emit(itemString) - lx.next() - lx.ignore() - return lx.pop() - } - return lexString -} - -// lexMultilineString consumes the inner contents of a string. It assumes that -// the beginning '"""' has already been consumed and ignored. -func lexMultilineString(lx *lexer) stateFn { - switch lx.next() { - case eof: - return lx.errorf("unexpected EOF") - case '\\': - return lexMultilineStringEscape - case stringEnd: - if lx.accept(stringEnd) { - if lx.accept(stringEnd) { - lx.backup() - lx.backup() - lx.backup() - lx.emit(itemMultilineString) - lx.next() - lx.next() - lx.next() - lx.ignore() - return lx.pop() - } - lx.backup() - } - } - return lexMultilineString -} - -// lexRawString consumes a raw string. Nothing can be escaped in such a string. -// It assumes that the beginning "'" has already been consumed and ignored. -func lexRawString(lx *lexer) stateFn { - r := lx.next() - switch { - case r == eof: - return lx.errorf("unexpected EOF") - case isNL(r): - return lx.errorf("strings cannot contain newlines") - case r == rawStringEnd: - lx.backup() - lx.emit(itemRawString) - lx.next() - lx.ignore() - return lx.pop() - } - return lexRawString -} - -// lexMultilineRawString consumes a raw string. Nothing can be escaped in such -// a string. It assumes that the beginning "'''" has already been consumed and -// ignored. -func lexMultilineRawString(lx *lexer) stateFn { - switch lx.next() { - case eof: - return lx.errorf("unexpected EOF") - case rawStringEnd: - if lx.accept(rawStringEnd) { - if lx.accept(rawStringEnd) { - lx.backup() - lx.backup() - lx.backup() - lx.emit(itemRawMultilineString) - lx.next() - lx.next() - lx.next() - lx.ignore() - return lx.pop() - } - lx.backup() - } - } - return lexMultilineRawString -} - -// lexMultilineStringEscape consumes an escaped character. It assumes that the -// preceding '\\' has already been consumed. -func lexMultilineStringEscape(lx *lexer) stateFn { - // Handle the special case first: - if isNL(lx.next()) { - return lexMultilineString - } - lx.backup() - lx.push(lexMultilineString) - return lexStringEscape(lx) -} - -func lexStringEscape(lx *lexer) stateFn { - r := lx.next() - switch r { - case 'b': - fallthrough - case 't': - fallthrough - case 'n': - fallthrough - case 'f': - fallthrough - case 'r': - fallthrough - case '"': - fallthrough - case '\\': - return lx.pop() - case 'u': - return lexShortUnicodeEscape - case 'U': - return lexLongUnicodeEscape - } - return lx.errorf("invalid escape character %q; only the following "+ - "escape characters are allowed: "+ - `\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r) -} - -func lexShortUnicodeEscape(lx *lexer) stateFn { - var r rune - for i := 0; i < 4; i++ { - r = lx.next() - if !isHexadecimal(r) { - return lx.errorf(`expected four hexadecimal digits after '\u', `+ - "but got %q instead", lx.current()) - } - } - return lx.pop() -} - -func lexLongUnicodeEscape(lx *lexer) stateFn { - var r rune - for i := 0; i < 8; i++ { - r = lx.next() - if !isHexadecimal(r) { - return lx.errorf(`expected eight hexadecimal digits after '\U', `+ - "but got %q instead", lx.current()) - } - } - return lx.pop() -} - -// lexNumberOrDateStart consumes either an integer, a float, or datetime. -func lexNumberOrDateStart(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexNumberOrDate - } - switch r { - case '_': - return lexNumber - case 'e', 'E': - return lexFloat - case '.': - return lx.errorf("floats must start with a digit, not '.'") - } - return lx.errorf("expected a digit but got %q", r) -} - -// lexNumberOrDate consumes either an integer, float or datetime. -func lexNumberOrDate(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexNumberOrDate - } - switch r { - case '-': - return lexDatetime - case '_': - return lexNumber - case '.', 'e', 'E': - return lexFloat - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexDatetime consumes a Datetime, to a first approximation. -// The parser validates that it matches one of the accepted formats. -func lexDatetime(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexDatetime - } - switch r { - case '-', 'T', ':', '.', 'Z', '+': - return lexDatetime - } - - lx.backup() - lx.emit(itemDatetime) - return lx.pop() -} - -// lexNumberStart consumes either an integer or a float. It assumes that a sign -// has already been read, but that *no* digits have been consumed. -// lexNumberStart will move to the appropriate integer or float states. -func lexNumberStart(lx *lexer) stateFn { - // We MUST see a digit. Even floats have to start with a digit. - r := lx.next() - if !isDigit(r) { - if r == '.' { - return lx.errorf("floats must start with a digit, not '.'") - } - return lx.errorf("expected a digit but got %q", r) - } - return lexNumber -} - -// lexNumber consumes an integer or a float after seeing the first digit. -func lexNumber(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexNumber - } - switch r { - case '_': - return lexNumber - case '.', 'e', 'E': - return lexFloat - } - - lx.backup() - lx.emit(itemInteger) - return lx.pop() -} - -// lexFloat consumes the elements of a float. It allows any sequence of -// float-like characters, so floats emitted by the lexer are only a first -// approximation and must be validated by the parser. -func lexFloat(lx *lexer) stateFn { - r := lx.next() - if isDigit(r) { - return lexFloat - } - switch r { - case '_', '.', '-', '+', 'e', 'E': - return lexFloat - } - - lx.backup() - lx.emit(itemFloat) - return lx.pop() -} - -// lexBool consumes a bool string: 'true' or 'false. -func lexBool(lx *lexer) stateFn { - var rs []rune - for { - r := lx.next() - if !unicode.IsLetter(r) { - lx.backup() - break - } - rs = append(rs, r) - } - s := string(rs) - switch s { - case "true", "false": - lx.emit(itemBool) - return lx.pop() - } - return lx.errorf("expected value but found %q instead", s) -} - -// lexCommentStart begins the lexing of a comment. It will emit -// itemCommentStart and consume no characters, passing control to lexComment. -func lexCommentStart(lx *lexer) stateFn { - lx.ignore() - lx.emit(itemCommentStart) - return lexComment -} - -// lexComment lexes an entire comment. It assumes that '#' has been consumed. -// It will consume *up to* the first newline character, and pass control -// back to the last state on the stack. -func lexComment(lx *lexer) stateFn { - r := lx.peek() - if isNL(r) || r == eof { - lx.emit(itemText) - return lx.pop() - } - lx.next() - return lexComment -} - -// lexSkip ignores all slurped input and moves on to the next state. -func lexSkip(lx *lexer, nextState stateFn) stateFn { - return func(lx *lexer) stateFn { - lx.ignore() - return nextState - } -} - -// isWhitespace returns true if `r` is a whitespace character according -// to the spec. -func isWhitespace(r rune) bool { - return r == '\t' || r == ' ' -} - -func isNL(r rune) bool { - return r == '\n' || r == '\r' -} - -func isDigit(r rune) bool { - return r >= '0' && r <= '9' -} - -func isHexadecimal(r rune) bool { - return (r >= '0' && r <= '9') || - (r >= 'a' && r <= 'f') || - (r >= 'A' && r <= 'F') -} - -func isBareKeyChar(r rune) bool { - return (r >= 'A' && r <= 'Z') || - (r >= 'a' && r <= 'z') || - (r >= '0' && r <= '9') || - r == '_' || - r == '-' -} - -func (itype itemType) String() string { - switch itype { - case itemError: - return "Error" - case itemNIL: - return "NIL" - case itemEOF: - return "EOF" - case itemText: - return "Text" - case itemString, itemRawString, itemMultilineString, itemRawMultilineString: - return "String" - case itemBool: - return "Bool" - case itemInteger: - return "Integer" - case itemFloat: - return "Float" - case itemDatetime: - return "DateTime" - case itemTableStart: - return "TableStart" - case itemTableEnd: - return "TableEnd" - case itemKeyStart: - return "KeyStart" - case itemArray: - return "Array" - case itemArrayEnd: - return "ArrayEnd" - case itemCommentStart: - return "CommentStart" - } - panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype))) -} - -func (item item) String() string { - return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val) -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/parse.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/parse.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/parse.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/parse.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,592 +0,0 @@ -package toml - -import ( - "fmt" - "strconv" - "strings" - "time" - "unicode" - "unicode/utf8" -) - -type parser struct { - mapping map[string]interface{} - types map[string]tomlType - lx *lexer - - // A list of keys in the order that they appear in the TOML data. - ordered []Key - - // the full key for the current hash in scope - context Key - - // the base key name for everything except hashes - currentKey string - - // rough approximation of line number - approxLine int - - // A map of 'key.group.names' to whether they were created implicitly. - implicits map[string]bool -} - -type parseError string - -func (pe parseError) Error() string { - return string(pe) -} - -func parse(data string) (p *parser, err error) { - defer func() { - if r := recover(); r != nil { - var ok bool - if err, ok = r.(parseError); ok { - return - } - panic(r) - } - }() - - p = &parser{ - mapping: make(map[string]interface{}), - types: make(map[string]tomlType), - lx: lex(data), - ordered: make([]Key, 0), - implicits: make(map[string]bool), - } - for { - item := p.next() - if item.typ == itemEOF { - break - } - p.topLevel(item) - } - - return p, nil -} - -func (p *parser) panicf(format string, v ...interface{}) { - msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s", - p.approxLine, p.current(), fmt.Sprintf(format, v...)) - panic(parseError(msg)) -} - -func (p *parser) next() item { - it := p.lx.nextItem() - if it.typ == itemError { - p.panicf("%s", it.val) - } - return it -} - -func (p *parser) bug(format string, v ...interface{}) { - panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) -} - -func (p *parser) expect(typ itemType) item { - it := p.next() - p.assertEqual(typ, it.typ) - return it -} - -func (p *parser) assertEqual(expected, got itemType) { - if expected != got { - p.bug("Expected '%s' but got '%s'.", expected, got) - } -} - -func (p *parser) topLevel(item item) { - switch item.typ { - case itemCommentStart: - p.approxLine = item.line - p.expect(itemText) - case itemTableStart: - kg := p.next() - p.approxLine = kg.line - - var key Key - for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() { - key = append(key, p.keyString(kg)) - } - p.assertEqual(itemTableEnd, kg.typ) - - p.establishContext(key, false) - p.setType("", tomlHash) - p.ordered = append(p.ordered, key) - case itemArrayTableStart: - kg := p.next() - p.approxLine = kg.line - - var key Key - for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() { - key = append(key, p.keyString(kg)) - } - p.assertEqual(itemArrayTableEnd, kg.typ) - - p.establishContext(key, true) - p.setType("", tomlArrayHash) - p.ordered = append(p.ordered, key) - case itemKeyStart: - kname := p.next() - p.approxLine = kname.line - p.currentKey = p.keyString(kname) - - val, typ := p.value(p.next()) - p.setValue(p.currentKey, val) - p.setType(p.currentKey, typ) - p.ordered = append(p.ordered, p.context.add(p.currentKey)) - p.currentKey = "" - default: - p.bug("Unexpected type at top level: %s", item.typ) - } -} - -// Gets a string for a key (or part of a key in a table name). -func (p *parser) keyString(it item) string { - switch it.typ { - case itemText: - return it.val - case itemString, itemMultilineString, - itemRawString, itemRawMultilineString: - s, _ := p.value(it) - return s.(string) - default: - p.bug("Unexpected key type: %s", it.typ) - panic("unreachable") - } -} - -// value translates an expected value from the lexer into a Go value wrapped -// as an empty interface. -func (p *parser) value(it item) (interface{}, tomlType) { - switch it.typ { - case itemString: - return p.replaceEscapes(it.val), p.typeOfPrimitive(it) - case itemMultilineString: - trimmed := stripFirstNewline(stripEscapedWhitespace(it.val)) - return p.replaceEscapes(trimmed), p.typeOfPrimitive(it) - case itemRawString: - return it.val, p.typeOfPrimitive(it) - case itemRawMultilineString: - return stripFirstNewline(it.val), p.typeOfPrimitive(it) - case itemBool: - switch it.val { - case "true": - return true, p.typeOfPrimitive(it) - case "false": - return false, p.typeOfPrimitive(it) - } - p.bug("Expected boolean value, but got '%s'.", it.val) - case itemInteger: - if !numUnderscoresOK(it.val) { - p.panicf("Invalid integer %q: underscores must be surrounded by digits", - it.val) - } - val := strings.Replace(it.val, "_", "", -1) - num, err := strconv.ParseInt(val, 10, 64) - if err != nil { - // Distinguish integer values. Normally, it'd be a bug if the lexer - // provides an invalid integer, but it's possible that the number is - // out of range of valid values (which the lexer cannot determine). - // So mark the former as a bug but the latter as a legitimate user - // error. - if e, ok := err.(*strconv.NumError); ok && - e.Err == strconv.ErrRange { - - p.panicf("Integer '%s' is out of the range of 64-bit "+ - "signed integers.", it.val) - } else { - p.bug("Expected integer value, but got '%s'.", it.val) - } - } - return num, p.typeOfPrimitive(it) - case itemFloat: - parts := strings.FieldsFunc(it.val, func(r rune) bool { - switch r { - case '.', 'e', 'E': - return true - } - return false - }) - for _, part := range parts { - if !numUnderscoresOK(part) { - p.panicf("Invalid float %q: underscores must be "+ - "surrounded by digits", it.val) - } - } - if !numPeriodsOK(it.val) { - // As a special case, numbers like '123.' or '1.e2', - // which are valid as far as Go/strconv are concerned, - // must be rejected because TOML says that a fractional - // part consists of '.' followed by 1+ digits. - p.panicf("Invalid float %q: '.' must be followed "+ - "by one or more digits", it.val) - } - val := strings.Replace(it.val, "_", "", -1) - num, err := strconv.ParseFloat(val, 64) - if err != nil { - if e, ok := err.(*strconv.NumError); ok && - e.Err == strconv.ErrRange { - - p.panicf("Float '%s' is out of the range of 64-bit "+ - "IEEE-754 floating-point numbers.", it.val) - } else { - p.panicf("Invalid float value: %q", it.val) - } - } - return num, p.typeOfPrimitive(it) - case itemDatetime: - var t time.Time - var ok bool - var err error - for _, format := range []string{ - "2006-01-02T15:04:05Z07:00", - "2006-01-02T15:04:05", - "2006-01-02", - } { - t, err = time.ParseInLocation(format, it.val, time.Local) - if err == nil { - ok = true - break - } - } - if !ok { - p.panicf("Invalid TOML Datetime: %q.", it.val) - } - return t, p.typeOfPrimitive(it) - case itemArray: - array := make([]interface{}, 0) - types := make([]tomlType, 0) - - for it = p.next(); it.typ != itemArrayEnd; it = p.next() { - if it.typ == itemCommentStart { - p.expect(itemText) - continue - } - - val, typ := p.value(it) - array = append(array, val) - types = append(types, typ) - } - return array, p.typeOfArray(types) - case itemInlineTableStart: - var ( - hash = make(map[string]interface{}) - outerContext = p.context - outerKey = p.currentKey - ) - - p.context = append(p.context, p.currentKey) - p.currentKey = "" - for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() { - if it.typ != itemKeyStart { - p.bug("Expected key start but instead found %q, around line %d", - it.val, p.approxLine) - } - if it.typ == itemCommentStart { - p.expect(itemText) - continue - } - - // retrieve key - k := p.next() - p.approxLine = k.line - kname := p.keyString(k) - - // retrieve value - p.currentKey = kname - val, typ := p.value(p.next()) - // make sure we keep metadata up to date - p.setType(kname, typ) - p.ordered = append(p.ordered, p.context.add(p.currentKey)) - hash[kname] = val - } - p.context = outerContext - p.currentKey = outerKey - return hash, tomlHash - } - p.bug("Unexpected value type: %s", it.typ) - panic("unreachable") -} - -// numUnderscoresOK checks whether each underscore in s is surrounded by -// characters that are not underscores. -func numUnderscoresOK(s string) bool { - accept := false - for _, r := range s { - if r == '_' { - if !accept { - return false - } - accept = false - continue - } - accept = true - } - return accept -} - -// numPeriodsOK checks whether every period in s is followed by a digit. -func numPeriodsOK(s string) bool { - period := false - for _, r := range s { - if period && !isDigit(r) { - return false - } - period = r == '.' - } - return !period -} - -// establishContext sets the current context of the parser, -// where the context is either a hash or an array of hashes. Which one is -// set depends on the value of the `array` parameter. -// -// Establishing the context also makes sure that the key isn't a duplicate, and -// will create implicit hashes automatically. -func (p *parser) establishContext(key Key, array bool) { - var ok bool - - // Always start at the top level and drill down for our context. - hashContext := p.mapping - keyContext := make(Key, 0) - - // We only need implicit hashes for key[0:-1] - for _, k := range key[0 : len(key)-1] { - _, ok = hashContext[k] - keyContext = append(keyContext, k) - - // No key? Make an implicit hash and move on. - if !ok { - p.addImplicit(keyContext) - hashContext[k] = make(map[string]interface{}) - } - - // If the hash context is actually an array of tables, then set - // the hash context to the last element in that array. - // - // Otherwise, it better be a table, since this MUST be a key group (by - // virtue of it not being the last element in a key). - switch t := hashContext[k].(type) { - case []map[string]interface{}: - hashContext = t[len(t)-1] - case map[string]interface{}: - hashContext = t - default: - p.panicf("Key '%s' was already created as a hash.", keyContext) - } - } - - p.context = keyContext - if array { - // If this is the first element for this array, then allocate a new - // list of tables for it. - k := key[len(key)-1] - if _, ok := hashContext[k]; !ok { - hashContext[k] = make([]map[string]interface{}, 0, 5) - } - - // Add a new table. But make sure the key hasn't already been used - // for something else. - if hash, ok := hashContext[k].([]map[string]interface{}); ok { - hashContext[k] = append(hash, make(map[string]interface{})) - } else { - p.panicf("Key '%s' was already created and cannot be used as "+ - "an array.", keyContext) - } - } else { - p.setValue(key[len(key)-1], make(map[string]interface{})) - } - p.context = append(p.context, key[len(key)-1]) -} - -// setValue sets the given key to the given value in the current context. -// It will make sure that the key hasn't already been defined, account for -// implicit key groups. -func (p *parser) setValue(key string, value interface{}) { - var tmpHash interface{} - var ok bool - - hash := p.mapping - keyContext := make(Key, 0) - for _, k := range p.context { - keyContext = append(keyContext, k) - if tmpHash, ok = hash[k]; !ok { - p.bug("Context for key '%s' has not been established.", keyContext) - } - switch t := tmpHash.(type) { - case []map[string]interface{}: - // The context is a table of hashes. Pick the most recent table - // defined as the current hash. - hash = t[len(t)-1] - case map[string]interface{}: - hash = t - default: - p.bug("Expected hash to have type 'map[string]interface{}', but "+ - "it has '%T' instead.", tmpHash) - } - } - keyContext = append(keyContext, key) - - if _, ok := hash[key]; ok { - // Typically, if the given key has already been set, then we have - // to raise an error since duplicate keys are disallowed. However, - // it's possible that a key was previously defined implicitly. In this - // case, it is allowed to be redefined concretely. (See the - // `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.) - // - // But we have to make sure to stop marking it as an implicit. (So that - // another redefinition provokes an error.) - // - // Note that since it has already been defined (as a hash), we don't - // want to overwrite it. So our business is done. - if p.isImplicit(keyContext) { - p.removeImplicit(keyContext) - return - } - - // Otherwise, we have a concrete key trying to override a previous - // key, which is *always* wrong. - p.panicf("Key '%s' has already been defined.", keyContext) - } - hash[key] = value -} - -// setType sets the type of a particular value at a given key. -// It should be called immediately AFTER setValue. -// -// Note that if `key` is empty, then the type given will be applied to the -// current context (which is either a table or an array of tables). -func (p *parser) setType(key string, typ tomlType) { - keyContext := make(Key, 0, len(p.context)+1) - for _, k := range p.context { - keyContext = append(keyContext, k) - } - if len(key) > 0 { // allow type setting for hashes - keyContext = append(keyContext, key) - } - p.types[keyContext.String()] = typ -} - -// addImplicit sets the given Key as having been created implicitly. -func (p *parser) addImplicit(key Key) { - p.implicits[key.String()] = true -} - -// removeImplicit stops tagging the given key as having been implicitly -// created. -func (p *parser) removeImplicit(key Key) { - p.implicits[key.String()] = false -} - -// isImplicit returns true if the key group pointed to by the key was created -// implicitly. -func (p *parser) isImplicit(key Key) bool { - return p.implicits[key.String()] -} - -// current returns the full key name of the current context. -func (p *parser) current() string { - if len(p.currentKey) == 0 { - return p.context.String() - } - if len(p.context) == 0 { - return p.currentKey - } - return fmt.Sprintf("%s.%s", p.context, p.currentKey) -} - -func stripFirstNewline(s string) string { - if len(s) == 0 || s[0] != '\n' { - return s - } - return s[1:] -} - -func stripEscapedWhitespace(s string) string { - esc := strings.Split(s, "\\\n") - if len(esc) > 1 { - for i := 1; i < len(esc); i++ { - esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace) - } - } - return strings.Join(esc, "") -} - -func (p *parser) replaceEscapes(str string) string { - var replaced []rune - s := []byte(str) - r := 0 - for r < len(s) { - if s[r] != '\\' { - c, size := utf8.DecodeRune(s[r:]) - r += size - replaced = append(replaced, c) - continue - } - r += 1 - if r >= len(s) { - p.bug("Escape sequence at end of string.") - return "" - } - switch s[r] { - default: - p.bug("Expected valid escape code after \\, but got %q.", s[r]) - return "" - case 'b': - replaced = append(replaced, rune(0x0008)) - r += 1 - case 't': - replaced = append(replaced, rune(0x0009)) - r += 1 - case 'n': - replaced = append(replaced, rune(0x000A)) - r += 1 - case 'f': - replaced = append(replaced, rune(0x000C)) - r += 1 - case 'r': - replaced = append(replaced, rune(0x000D)) - r += 1 - case '"': - replaced = append(replaced, rune(0x0022)) - r += 1 - case '\\': - replaced = append(replaced, rune(0x005C)) - r += 1 - case 'u': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+5). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(s[r+1 : r+5]) - replaced = append(replaced, escaped) - r += 5 - case 'U': - // At this point, we know we have a Unicode escape of the form - // `uXXXX` at [r, r+9). (Because the lexer guarantees this - // for us.) - escaped := p.asciiEscapeToUnicode(s[r+1 : r+9]) - replaced = append(replaced, escaped) - r += 9 - } - } - return string(replaced) -} - -func (p *parser) asciiEscapeToUnicode(bs []byte) rune { - s := string(bs) - hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32) - if err != nil { - p.bug("Could not parse '%s' as a hexadecimal number, but the "+ - "lexer claims it's OK: %s", s, err) - } - if !utf8.ValidRune(rune(hex)) { - p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s) - } - return rune(hex) -} - -func isStringType(ty itemType) bool { - return ty == itemString || ty == itemMultilineString || - ty == itemRawString || ty == itemRawMultilineString -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/README.md containerd-1.5.9/vendor/github.com/BurntSushi/toml/README.md --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,218 +0,0 @@ -## TOML parser and encoder for Go with reflection - -TOML stands for Tom's Obvious, Minimal Language. This Go package provides a -reflection interface similar to Go's standard library `json` and `xml` -packages. This package also supports the `encoding.TextUnmarshaler` and -`encoding.TextMarshaler` interfaces so that you can define custom data -representations. (There is an example of this below.) - -Spec: https://github.com/toml-lang/toml - -Compatible with TOML version -[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) - -Documentation: https://godoc.org/github.com/BurntSushi/toml - -Installation: - -```bash -go get github.com/BurntSushi/toml -``` - -Try the toml validator: - -```bash -go get github.com/BurntSushi/toml/cmd/tomlv -tomlv some-toml-file.toml -``` - -[![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml) - -### Testing - -This package passes all tests in -[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder -and the encoder. - -### Examples - -This package works similarly to how the Go standard library handles `XML` -and `JSON`. Namely, data is loaded into Go values via reflection. - -For the simplest example, consider some TOML file as just a list of keys -and values: - -```toml -Age = 25 -Cats = [ "Cauchy", "Plato" ] -Pi = 3.14 -Perfection = [ 6, 28, 496, 8128 ] -DOB = 1987-07-05T05:45:00Z -``` - -Which could be defined in Go as: - -```go -type Config struct { - Age int - Cats []string - Pi float64 - Perfection []int - DOB time.Time // requires `import time` -} -``` - -And then decoded with: - -```go -var conf Config -if _, err := toml.Decode(tomlData, &conf); err != nil { - // handle error -} -``` - -You can also use struct tags if your struct field name doesn't map to a TOML -key value directly: - -```toml -some_key_NAME = "wat" -``` - -```go -type TOML struct { - ObscureKey string `toml:"some_key_NAME"` -} -``` - -### Using the `encoding.TextUnmarshaler` interface - -Here's an example that automatically parses duration strings into -`time.Duration` values: - -```toml -[[song]] -name = "Thunder Road" -duration = "4m49s" - -[[song]] -name = "Stairway to Heaven" -duration = "8m03s" -``` - -Which can be decoded with: - -```go -type song struct { - Name string - Duration duration -} -type songs struct { - Song []song -} -var favorites songs -if _, err := toml.Decode(blob, &favorites); err != nil { - log.Fatal(err) -} - -for _, s := range favorites.Song { - fmt.Printf("%s (%s)\n", s.Name, s.Duration) -} -``` - -And you'll also need a `duration` type that satisfies the -`encoding.TextUnmarshaler` interface: - -```go -type duration struct { - time.Duration -} - -func (d *duration) UnmarshalText(text []byte) error { - var err error - d.Duration, err = time.ParseDuration(string(text)) - return err -} -``` - -### More complex usage - -Here's an example of how to load the example from the official spec page: - -```toml -# This is a TOML document. Boom. - -title = "TOML Example" - -[owner] -name = "Tom Preston-Werner" -organization = "GitHub" -bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." -dob = 1979-05-27T07:32:00Z # First class dates? Why not? - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # You can indent as you please. Tabs or spaces. TOML don't care. - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] -``` - -And the corresponding Go types are: - -```go -type tomlConfig struct { - Title string - Owner ownerInfo - DB database `toml:"database"` - Servers map[string]server - Clients clients -} - -type ownerInfo struct { - Name string - Org string `toml:"organization"` - Bio string - DOB time.Time -} - -type database struct { - Server string - Ports []int - ConnMax int `toml:"connection_max"` - Enabled bool -} - -type server struct { - IP string - DC string -} - -type clients struct { - Data [][]interface{} - Hosts []string -} -``` - -Note that a case insensitive match will be tried if an exact match can't be -found. - -A working example of the above can be found in `_examples/example.{go,toml}`. diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/type_check.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/type_check.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/type_check.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/type_check.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -package toml - -// tomlType represents any Go type that corresponds to a TOML type. -// While the first draft of the TOML spec has a simplistic type system that -// probably doesn't need this level of sophistication, we seem to be militating -// toward adding real composite types. -type tomlType interface { - typeString() string -} - -// typeEqual accepts any two types and returns true if they are equal. -func typeEqual(t1, t2 tomlType) bool { - if t1 == nil || t2 == nil { - return false - } - return t1.typeString() == t2.typeString() -} - -func typeIsHash(t tomlType) bool { - return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) -} - -type tomlBaseType string - -func (btype tomlBaseType) typeString() string { - return string(btype) -} - -func (btype tomlBaseType) String() string { - return btype.typeString() -} - -var ( - tomlInteger tomlBaseType = "Integer" - tomlFloat tomlBaseType = "Float" - tomlDatetime tomlBaseType = "Datetime" - tomlString tomlBaseType = "String" - tomlBool tomlBaseType = "Bool" - tomlArray tomlBaseType = "Array" - tomlHash tomlBaseType = "Hash" - tomlArrayHash tomlBaseType = "ArrayHash" -) - -// typeOfPrimitive returns a tomlType of any primitive value in TOML. -// Primitive values are: Integer, Float, Datetime, String and Bool. -// -// Passing a lexer item other than the following will cause a BUG message -// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. -func (p *parser) typeOfPrimitive(lexItem item) tomlType { - switch lexItem.typ { - case itemInteger: - return tomlInteger - case itemFloat: - return tomlFloat - case itemDatetime: - return tomlDatetime - case itemString: - return tomlString - case itemMultilineString: - return tomlString - case itemRawString: - return tomlString - case itemRawMultilineString: - return tomlString - case itemBool: - return tomlBool - } - p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) - panic("unreachable") -} - -// typeOfArray returns a tomlType for an array given a list of types of its -// values. -// -// In the current spec, if an array is homogeneous, then its type is always -// "Array". If the array is not homogeneous, an error is generated. -func (p *parser) typeOfArray(types []tomlType) tomlType { - // Empty arrays are cool. - if len(types) == 0 { - return tomlArray - } - - theType := types[0] - for _, t := range types[1:] { - if !typeEqual(theType, t) { - p.panicf("Array contains values of type '%s' and '%s', but "+ - "arrays must be homogeneous.", theType, t) - } - } - return tomlArray -} diff -Nru containerd-1.2.6/vendor/github.com/BurntSushi/toml/type_fields.go containerd-1.5.9/vendor/github.com/BurntSushi/toml/type_fields.go --- containerd-1.2.6/vendor/github.com/BurntSushi/toml/type_fields.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/BurntSushi/toml/type_fields.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,242 +0,0 @@ -package toml - -// Struct field handling is adapted from code in encoding/json: -// -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the Go distribution. - -import ( - "reflect" - "sort" - "sync" -) - -// A field represents a single field found in a struct. -type field struct { - name string // the name of the field (`toml` tag included) - tag bool // whether field has a `toml` tag - index []int // represents the depth of an anonymous field - typ reflect.Type // the type of the field -} - -// byName sorts field by name, breaking ties with depth, -// then breaking ties with "name came from toml tag", then -// breaking ties with index sequence. -type byName []field - -func (x byName) Len() int { return len(x) } - -func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byName) Less(i, j int) bool { - if x[i].name != x[j].name { - return x[i].name < x[j].name - } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) - } - if x[i].tag != x[j].tag { - return x[i].tag - } - return byIndex(x).Less(i, j) -} - -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { - for k, xik := range x[i].index { - if k >= len(x[j].index) { - return false - } - if xik != x[j].index[k] { - return xik < x[j].index[k] - } - } - return len(x[i].index) < len(x[j].index) -} - -// typeFields returns a list of fields that TOML should recognize for the given -// type. The algorithm is breadth-first search over the set of structs to -// include - the top struct and then any reachable anonymous structs. -func typeFields(t reflect.Type) []field { - // Anonymous fields to explore at the current level and the next. - current := []field{} - next := []field{{typ: t}} - - // Count of queued names for current level and the next. - count := map[reflect.Type]int{} - nextCount := map[reflect.Type]int{} - - // Types already visited at an earlier level. - visited := map[reflect.Type]bool{} - - // Fields found. - var fields []field - - for len(next) > 0 { - current, next = next, current[:0] - count, nextCount = nextCount, map[reflect.Type]int{} - - for _, f := range current { - if visited[f.typ] { - continue - } - visited[f.typ] = true - - // Scan f.typ for fields to include. - for i := 0; i < f.typ.NumField(); i++ { - sf := f.typ.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported - continue - } - opts := getOptions(sf.Tag) - if opts.skip { - continue - } - index := make([]int, len(f.index)+1) - copy(index, f.index) - index[len(f.index)] = i - - ft := sf.Type - if ft.Name() == "" && ft.Kind() == reflect.Ptr { - // Follow pointer. - ft = ft.Elem() - } - - // Record found field and index sequence. - if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { - tagged := opts.name != "" - name := opts.name - if name == "" { - name = sf.Name - } - fields = append(fields, field{name, tagged, index, ft}) - if count[f.typ] > 1 { - // If there were multiple instances, add a second, - // so that the annihilation code will see a duplicate. - // It only cares about the distinction between 1 or 2, - // so don't bother generating any more copies. - fields = append(fields, fields[len(fields)-1]) - } - continue - } - - // Record new anonymous struct to explore in next round. - nextCount[ft]++ - if nextCount[ft] == 1 { - f := field{name: ft.Name(), index: index, typ: ft} - next = append(next, f) - } - } - } - } - - sort.Sort(byName(fields)) - - // Delete all fields that are hidden by the Go rules for embedded fields, - // except that fields with TOML tags are promoted. - - // The fields are sorted in primary order of name, secondary order - // of field index length. Loop over names; for each name, delete - // hidden fields by choosing the one dominant field that survives. - out := fields[:0] - for advance, i := 0, 0; i < len(fields); i += advance { - // One iteration per name. - // Find the sequence of fields with the name of this first field. - fi := fields[i] - name := fi.name - for advance = 1; i+advance < len(fields); advance++ { - fj := fields[i+advance] - if fj.name != name { - break - } - } - if advance == 1 { // Only one field with this name - out = append(out, fi) - continue - } - dominant, ok := dominantField(fields[i : i+advance]) - if ok { - out = append(out, dominant) - } - } - - fields = out - sort.Sort(byIndex(fields)) - - return fields -} - -// dominantField looks through the fields, all of which are known to -// have the same name, to find the single field that dominates the -// others using Go's embedding rules, modified by the presence of -// TOML tags. If there are multiple top-level fields, the boolean -// will be false: This condition is an error in Go and we skip all -// the fields. -func dominantField(fields []field) (field, bool) { - // The fields are sorted in increasing index-length order. The winner - // must therefore be one with the shortest index length. Drop all - // longer entries, which is easy: just truncate the slice. - length := len(fields[0].index) - tagged := -1 // Index of first tagged field. - for i, f := range fields { - if len(f.index) > length { - fields = fields[:i] - break - } - if f.tag { - if tagged >= 0 { - // Multiple tagged fields at the same level: conflict. - // Return no field. - return field{}, false - } - tagged = i - } - } - if tagged >= 0 { - return fields[tagged], true - } - // All remaining fields have the same length. If there's more than one, - // we have a conflict (two fields named "X" at the same level) and we - // return no field. - if len(fields) > 1 { - return field{}, false - } - return fields[0], true -} - -var fieldCache struct { - sync.RWMutex - m map[reflect.Type][]field -} - -// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) []field { - fieldCache.RLock() - f := fieldCache.m[t] - fieldCache.RUnlock() - if f != nil { - return f - } - - // Compute fields without lock. - // Might duplicate effort but won't hold other computations back. - f = typeFields(t) - if f == nil { - f = []field{} - } - - fieldCache.Lock() - if fieldCache.m == nil { - fieldCache.m = map[reflect.Type][]field{} - } - fieldCache.m[t] = f - fieldCache.Unlock() - return f -} diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/go.mod containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/go.mod --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,3 @@ +module github.com/cespare/xxhash/v2 + +go 1.11 diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/LICENSE.txt containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/LICENSE.txt --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/LICENSE.txt 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,22 @@ +Copyright (c) 2016 Caleb Spare + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/README.md containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/README.md --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,67 @@ +# xxhash + +[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash) +[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](https://travis-ci.org/cespare/xxhash) + +xxhash is a Go implementation of the 64-bit +[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a +high-quality hashing algorithm that is much faster than anything in the Go +standard library. + +This package provides a straightforward API: + +``` +func Sum64(b []byte) uint64 +func Sum64String(s string) uint64 +type Digest struct{ ... } + func New() *Digest +``` + +The `Digest` type implements hash.Hash64. Its key methods are: + +``` +func (*Digest) Write([]byte) (int, error) +func (*Digest) WriteString(string) (int, error) +func (*Digest) Sum64() uint64 +``` + +This implementation provides a fast pure-Go implementation and an even faster +assembly implementation for amd64. + +## Compatibility + +This package is in a module and the latest code is in version 2 of the module. +You need a version of Go with at least "minimal module compatibility" to use +github.com/cespare/xxhash/v2: + +* 1.9.7+ for Go 1.9 +* 1.10.3+ for Go 1.10 +* Go 1.11 or later + +I recommend using the latest release of Go. + +## Benchmarks + +Here are some quick benchmarks comparing the pure-Go and assembly +implementations of Sum64. + +| input size | purego | asm | +| --- | --- | --- | +| 5 B | 979.66 MB/s | 1291.17 MB/s | +| 100 B | 7475.26 MB/s | 7973.40 MB/s | +| 4 KB | 17573.46 MB/s | 17602.65 MB/s | +| 10 MB | 17131.46 MB/s | 17142.16 MB/s | + +These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using +the following commands under Go 1.11.2: + +``` +$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes' +$ go test -benchtime 10s -bench '/xxhash,direct,bytes' +``` + +## Projects using this package + +- [InfluxDB](https://github.com/influxdata/influxdb) +- [Prometheus](https://github.com/prometheus/prometheus) +- [FreeCache](https://github.com/coocood/freecache) diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/.travis.yml containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/.travis.yml --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,8 @@ +language: go +go: + - "1.x" + - master +env: + - TAGS="" + - TAGS="-tags purego" +script: go test $TAGS -v ./... diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,13 @@ +// +build !appengine +// +build gc +// +build !purego + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b. +// +//go:noescape +func Sum64(b []byte) uint64 + +//go:noescape +func writeBlocks(d *Digest, b []byte) int diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,215 @@ +// +build !appengine +// +build gc +// +build !purego + +#include "textflag.h" + +// Register allocation: +// AX h +// CX pointer to advance through b +// DX n +// BX loop end +// R8 v1, k1 +// R9 v2 +// R10 v3 +// R11 v4 +// R12 tmp +// R13 prime1v +// R14 prime2v +// R15 prime4v + +// round reads from and advances the buffer pointer in CX. +// It assumes that R13 has prime1v and R14 has prime2v. +#define round(r) \ + MOVQ (CX), R12 \ + ADDQ $8, CX \ + IMULQ R14, R12 \ + ADDQ R12, r \ + ROLQ $31, r \ + IMULQ R13, r + +// mergeRound applies a merge round on the two registers acc and val. +// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v. +#define mergeRound(acc, val) \ + IMULQ R14, val \ + ROLQ $31, val \ + IMULQ R13, val \ + XORQ val, acc \ + IMULQ R13, acc \ + ADDQ R15, acc + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT, $0-32 + // Load fixed primes. + MOVQ ·prime1v(SB), R13 + MOVQ ·prime2v(SB), R14 + MOVQ ·prime4v(SB), R15 + + // Load slice. + MOVQ b_base+0(FP), CX + MOVQ b_len+8(FP), DX + LEAQ (CX)(DX*1), BX + + // The first loop limit will be len(b)-32. + SUBQ $32, BX + + // Check whether we have at least one block. + CMPQ DX, $32 + JLT noBlocks + + // Set up initial state (v1, v2, v3, v4). + MOVQ R13, R8 + ADDQ R14, R8 + MOVQ R14, R9 + XORQ R10, R10 + XORQ R11, R11 + SUBQ R13, R11 + + // Loop until CX > BX. +blockLoop: + round(R8) + round(R9) + round(R10) + round(R11) + + CMPQ CX, BX + JLE blockLoop + + MOVQ R8, AX + ROLQ $1, AX + MOVQ R9, R12 + ROLQ $7, R12 + ADDQ R12, AX + MOVQ R10, R12 + ROLQ $12, R12 + ADDQ R12, AX + MOVQ R11, R12 + ROLQ $18, R12 + ADDQ R12, AX + + mergeRound(AX, R8) + mergeRound(AX, R9) + mergeRound(AX, R10) + mergeRound(AX, R11) + + JMP afterBlocks + +noBlocks: + MOVQ ·prime5v(SB), AX + +afterBlocks: + ADDQ DX, AX + + // Right now BX has len(b)-32, and we want to loop until CX > len(b)-8. + ADDQ $24, BX + + CMPQ CX, BX + JG fourByte + +wordLoop: + // Calculate k1. + MOVQ (CX), R8 + ADDQ $8, CX + IMULQ R14, R8 + ROLQ $31, R8 + IMULQ R13, R8 + + XORQ R8, AX + ROLQ $27, AX + IMULQ R13, AX + ADDQ R15, AX + + CMPQ CX, BX + JLE wordLoop + +fourByte: + ADDQ $4, BX + CMPQ CX, BX + JG singles + + MOVL (CX), R8 + ADDQ $4, CX + IMULQ R13, R8 + XORQ R8, AX + + ROLQ $23, AX + IMULQ R14, AX + ADDQ ·prime3v(SB), AX + +singles: + ADDQ $4, BX + CMPQ CX, BX + JGE finalize + +singlesLoop: + MOVBQZX (CX), R12 + ADDQ $1, CX + IMULQ ·prime5v(SB), R12 + XORQ R12, AX + + ROLQ $11, AX + IMULQ R13, AX + + CMPQ CX, BX + JL singlesLoop + +finalize: + MOVQ AX, R12 + SHRQ $33, R12 + XORQ R12, AX + IMULQ R14, AX + MOVQ AX, R12 + SHRQ $29, R12 + XORQ R12, AX + IMULQ ·prime3v(SB), AX + MOVQ AX, R12 + SHRQ $32, R12 + XORQ R12, AX + + MOVQ AX, ret+24(FP) + RET + +// writeBlocks uses the same registers as above except that it uses AX to store +// the d pointer. + +// func writeBlocks(d *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT, $0-40 + // Load fixed primes needed for round. + MOVQ ·prime1v(SB), R13 + MOVQ ·prime2v(SB), R14 + + // Load slice. + MOVQ b_base+8(FP), CX + MOVQ b_len+16(FP), DX + LEAQ (CX)(DX*1), BX + SUBQ $32, BX + + // Load vN from d. + MOVQ d+0(FP), AX + MOVQ 0(AX), R8 // v1 + MOVQ 8(AX), R9 // v2 + MOVQ 16(AX), R10 // v3 + MOVQ 24(AX), R11 // v4 + + // We don't need to check the loop condition here; this function is + // always called with at least one block of data to process. +blockLoop: + round(R8) + round(R9) + round(R10) + round(R11) + + CMPQ CX, BX + JLE blockLoop + + // Copy vN back to d. + MOVQ R8, 0(AX) + MOVQ R9, 8(AX) + MOVQ R10, 16(AX) + MOVQ R11, 24(AX) + + // The number of bytes written is CX minus the old base pointer. + SUBQ b_base+8(FP), CX + MOVQ CX, ret+32(FP) + + RET diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash.go containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash.go --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,236 @@ +// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described +// at http://cyan4973.github.io/xxHash/. +package xxhash + +import ( + "encoding/binary" + "errors" + "math/bits" +) + +const ( + prime1 uint64 = 11400714785074694791 + prime2 uint64 = 14029467366897019727 + prime3 uint64 = 1609587929392839161 + prime4 uint64 = 9650029242287828579 + prime5 uint64 = 2870177450012600261 +) + +// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where +// possible in the Go code is worth a small (but measurable) performance boost +// by avoiding some MOVQs. Vars are needed for the asm and also are useful for +// convenience in the Go code in a few places where we need to intentionally +// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the +// result overflows a uint64). +var ( + prime1v = prime1 + prime2v = prime2 + prime3v = prime3 + prime4v = prime4 + prime5v = prime5 +) + +// Digest implements hash.Hash64. +type Digest struct { + v1 uint64 + v2 uint64 + v3 uint64 + v4 uint64 + total uint64 + mem [32]byte + n int // how much of mem is used +} + +// New creates a new Digest that computes the 64-bit xxHash algorithm. +func New() *Digest { + var d Digest + d.Reset() + return &d +} + +// Reset clears the Digest's state so that it can be reused. +func (d *Digest) Reset() { + d.v1 = prime1v + prime2 + d.v2 = prime2 + d.v3 = 0 + d.v4 = -prime1v + d.total = 0 + d.n = 0 +} + +// Size always returns 8 bytes. +func (d *Digest) Size() int { return 8 } + +// BlockSize always returns 32 bytes. +func (d *Digest) BlockSize() int { return 32 } + +// Write adds more data to d. It always returns len(b), nil. +func (d *Digest) Write(b []byte) (n int, err error) { + n = len(b) + d.total += uint64(n) + + if d.n+n < 32 { + // This new data doesn't even fill the current block. + copy(d.mem[d.n:], b) + d.n += n + return + } + + if d.n > 0 { + // Finish off the partial block. + copy(d.mem[d.n:], b) + d.v1 = round(d.v1, u64(d.mem[0:8])) + d.v2 = round(d.v2, u64(d.mem[8:16])) + d.v3 = round(d.v3, u64(d.mem[16:24])) + d.v4 = round(d.v4, u64(d.mem[24:32])) + b = b[32-d.n:] + d.n = 0 + } + + if len(b) >= 32 { + // One or more full blocks left. + nw := writeBlocks(d, b) + b = b[nw:] + } + + // Store any remaining partial block. + copy(d.mem[:], b) + d.n = len(b) + + return +} + +// Sum appends the current hash to b and returns the resulting slice. +func (d *Digest) Sum(b []byte) []byte { + s := d.Sum64() + return append( + b, + byte(s>>56), + byte(s>>48), + byte(s>>40), + byte(s>>32), + byte(s>>24), + byte(s>>16), + byte(s>>8), + byte(s), + ) +} + +// Sum64 returns the current hash. +func (d *Digest) Sum64() uint64 { + var h uint64 + + if d.total >= 32 { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = d.v3 + prime5 + } + + h += d.total + + i, end := 0, d.n + for ; i+8 <= end; i += 8 { + k1 := round(0, u64(d.mem[i:i+8])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if i+4 <= end { + h ^= uint64(u32(d.mem[i:i+4])) * prime1 + h = rol23(h)*prime2 + prime3 + i += 4 + } + for i < end { + h ^= uint64(d.mem[i]) * prime5 + h = rol11(h) * prime1 + i++ + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +const ( + magic = "xxh\x06" + marshaledSize = len(magic) + 8*5 + 32 +) + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (d *Digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint64(b, d.v1) + b = appendUint64(b, d.v2) + b = appendUint64(b, d.v3) + b = appendUint64(b, d.v4) + b = appendUint64(b, d.total) + b = append(b, d.mem[:d.n]...) + b = b[:len(b)+len(d.mem)-d.n] + return b, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (d *Digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("xxhash: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("xxhash: invalid hash state size") + } + b = b[len(magic):] + b, d.v1 = consumeUint64(b) + b, d.v2 = consumeUint64(b) + b, d.v3 = consumeUint64(b) + b, d.v4 = consumeUint64(b) + b, d.total = consumeUint64(b) + copy(d.mem[:], b) + b = b[len(d.mem):] + d.n = int(d.total % uint64(len(d.mem))) + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.LittleEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := u64(b) + return b[8:], x +} + +func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } +func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func round(acc, input uint64) uint64 { + acc += input * prime2 + acc = rol31(acc) + acc *= prime1 + return acc +} + +func mergeRound(acc, val uint64) uint64 { + val = round(0, val) + acc ^= val + acc = acc*prime1 + prime4 + return acc +} + +func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } +func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } +func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } +func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } +func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } +func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } +func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } +func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_other.go containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_other.go --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,76 @@ +// +build !amd64 appengine !gc purego + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b. +func Sum64(b []byte) uint64 { + // A simpler version would be + // d := New() + // d.Write(b) + // return d.Sum64() + // but this is faster, particularly for small inputs. + + n := len(b) + var h uint64 + + if n >= 32 { + v1 := prime1v + prime2 + v2 := prime2 + v3 := uint64(0) + v4 := -prime1v + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = prime5 + } + + h += uint64(n) + + i, end := 0, len(b) + for ; i+8 <= end; i += 8 { + k1 := round(0, u64(b[i:i+8:len(b)])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if i+4 <= end { + h ^= uint64(u32(b[i:i+4:len(b)])) * prime1 + h = rol23(h)*prime2 + prime3 + i += 4 + } + for ; i < end; i++ { + h ^= uint64(b[i]) * prime5 + h = rol11(h) * prime1 + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +func writeBlocks(d *Digest, b []byte) int { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + n := len(b) + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4 + return n - len(b) +} diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,15 @@ +// +build appengine + +// This file contains the safe implementations of otherwise unsafe-using code. + +package xxhash + +// Sum64String computes the 64-bit xxHash digest of s. +func Sum64String(s string) uint64 { + return Sum64([]byte(s)) +} + +// WriteString adds more data to d. It always returns len(s), nil. +func (d *Digest) WriteString(s string) (n int, err error) { + return d.Write([]byte(s)) +} diff -Nru containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go --- containerd-1.2.6/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +// +build !appengine + +// This file encapsulates usage of unsafe. +// xxhash_safe.go contains the safe implementations. + +package xxhash + +import ( + "reflect" + "unsafe" +) + +// Notes: +// +// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ +// for some discussion about these unsafe conversions. +// +// In the future it's possible that compiler optimizations will make these +// unsafe operations unnecessary: https://golang.org/issue/2205. +// +// Both of these wrapper functions still incur function call overhead since they +// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write +// for strings to squeeze out a bit more speed. Mid-stack inlining should +// eventually fix this. + +// Sum64String computes the 64-bit xxHash digest of s. +// It may be faster than Sum64([]byte(s)) by avoiding a copy. +func Sum64String(s string) uint64 { + var b []byte + bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data + bh.Len = len(s) + bh.Cap = len(s) + return Sum64(b) +} + +// WriteString adds more data to d. It always returns len(s), nil. +// It may be faster than Write([]byte(s)) by avoiding a copy. +func (d *Digest) WriteString(s string) (n int, err error) { + var b []byte + bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data + bh.Len = len(s) + bh.Cap = len(s) + return d.Write(b) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/ARCHITECTURE.md containerd-1.5.9/vendor/github.com/cilium/ebpf/ARCHITECTURE.md --- containerd-1.2.6/vendor/github.com/cilium/ebpf/ARCHITECTURE.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/ARCHITECTURE.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,80 @@ +Architecture of the library +=== + + ELF -> Specifications -> Objects -> Links + +ELF +--- + +BPF is usually produced by using Clang to compile a subset of C. Clang outputs +an ELF file which contains program byte code (aka BPF), but also metadata for +maps used by the program. The metadata follows the conventions set by libbpf +shipped with the kernel. Certain ELF sections have special meaning +and contain structures defined by libbpf. Newer versions of clang emit +additional metadata in BPF Type Format (aka BTF). + +The library aims to be compatible with libbpf so that moving from a C toolchain +to a Go one creates little friction. To that end, the [ELF reader](elf_reader.go) +is tested against the Linux selftests and avoids introducing custom behaviour +if possible. + +The output of the ELF reader is a `CollectionSpec` which encodes +all of the information contained in the ELF in a form that is easy to work with +in Go. + +### BTF + +The BPF Type Format describes more than just the types used by a BPF program. It +includes debug aids like which source line corresponds to which instructions and +what global variables are used. + +[BTF parsing](internal/btf/) lives in a separate internal package since exposing +it would mean an additional maintenance burden, and because the API still +has sharp corners. The most important concept is the `btf.Type` interface, which +also describes things that aren't really types like `.rodata` or `.bss` sections. +`btf.Type`s can form cyclical graphs, which can easily lead to infinite loops if +one is not careful. Hopefully a safe pattern to work with `btf.Type` emerges as +we write more code that deals with it. + +Specifications +--- + +`CollectionSpec`, `ProgramSpec` and `MapSpec` are blueprints for in-kernel +objects and contain everything necessary to execute the relevant `bpf(2)` +syscalls. Since the ELF reader outputs a `CollectionSpec` it's possible to +modify clang-compiled BPF code, for example to rewrite constants. At the same +time the [asm](asm/) package provides an assembler that can be used to generate +`ProgramSpec` on the fly. + +Creating a spec should never require any privileges or be restricted in any way, +for example by only allowing programs in native endianness. This ensures that +the library stays flexible. + +Objects +--- + +`Program` and `Map` are the result of loading specs into the kernel. Sometimes +loading a spec will fail because the kernel is too old, or a feature is not +enabled. There are multiple ways the library deals with that: + +* Fallback: older kernels don't allowing naming programs and maps. The library + automatically detects support for names, and omits them during load if + necessary. This works since name is primarily a debug aid. + +* Sentinel error: sometimes it's possible to detect that a feature isn't available. + In that case the library will return an error wrapping `ErrNotSupported`. + This is also useful to skip tests that can't run on the current kernel. + +Once program and map objects are loaded they expose the kernel's low-level API, +e.g. `NextKey`. Often this API is awkward to use in Go, so there are safer +wrappers on top of the low-level API, like `MapIterator`. The low-level API is +useful as an out when our higher-level API doesn't support a particular use case. + +Links +--- + +BPF can be attached to many different points in the kernel and newer BPF hooks +tend to use bpf_link to do so. Older hooks unfortunately use a combination of +syscalls, netlink messages, etc. Adding support for a new link type should not +pull in large dependencies like netlink, so XDP programs or tracepoints are +out of scope. diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/alu.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/alu.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/alu.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/alu.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,149 @@ +package asm + +//go:generate stringer -output alu_string.go -type=Source,Endianness,ALUOp + +// Source of ALU / ALU64 / Branch operations +// +// msb lsb +// +----+-+---+ +// |op |S|cls| +// +----+-+---+ +type Source uint8 + +const sourceMask OpCode = 0x08 + +// Source bitmask +const ( + // InvalidSource is returned by getters when invoked + // on non ALU / branch OpCodes. + InvalidSource Source = 0xff + // ImmSource src is from constant + ImmSource Source = 0x00 + // RegSource src is from register + RegSource Source = 0x08 +) + +// The Endianness of a byte swap instruction. +type Endianness uint8 + +const endianMask = sourceMask + +// Endian flags +const ( + InvalidEndian Endianness = 0xff + // Convert to little endian + LE Endianness = 0x00 + // Convert to big endian + BE Endianness = 0x08 +) + +// ALUOp are ALU / ALU64 operations +// +// msb lsb +// +----+-+---+ +// |OP |s|cls| +// +----+-+---+ +type ALUOp uint8 + +const aluMask OpCode = 0xf0 + +const ( + // InvalidALUOp is returned by getters when invoked + // on non ALU OpCodes + InvalidALUOp ALUOp = 0xff + // Add - addition + Add ALUOp = 0x00 + // Sub - subtraction + Sub ALUOp = 0x10 + // Mul - multiplication + Mul ALUOp = 0x20 + // Div - division + Div ALUOp = 0x30 + // Or - bitwise or + Or ALUOp = 0x40 + // And - bitwise and + And ALUOp = 0x50 + // LSh - bitwise shift left + LSh ALUOp = 0x60 + // RSh - bitwise shift right + RSh ALUOp = 0x70 + // Neg - sign/unsign signing bit + Neg ALUOp = 0x80 + // Mod - modulo + Mod ALUOp = 0x90 + // Xor - bitwise xor + Xor ALUOp = 0xa0 + // Mov - move value from one place to another + Mov ALUOp = 0xb0 + // ArSh - arithmatic shift + ArSh ALUOp = 0xc0 + // Swap - endian conversions + Swap ALUOp = 0xd0 +) + +// HostTo converts from host to another endianness. +func HostTo(endian Endianness, dst Register, size Size) Instruction { + var imm int64 + switch size { + case Half: + imm = 16 + case Word: + imm = 32 + case DWord: + imm = 64 + default: + return Instruction{OpCode: InvalidOpCode} + } + + return Instruction{ + OpCode: OpCode(ALUClass).SetALUOp(Swap).SetSource(Source(endian)), + Dst: dst, + Constant: imm, + } +} + +// Op returns the OpCode for an ALU operation with a given source. +func (op ALUOp) Op(source Source) OpCode { + return OpCode(ALU64Class).SetALUOp(op).SetSource(source) +} + +// Reg emits `dst (op) src`. +func (op ALUOp) Reg(dst, src Register) Instruction { + return Instruction{ + OpCode: op.Op(RegSource), + Dst: dst, + Src: src, + } +} + +// Imm emits `dst (op) value`. +func (op ALUOp) Imm(dst Register, value int32) Instruction { + return Instruction{ + OpCode: op.Op(ImmSource), + Dst: dst, + Constant: int64(value), + } +} + +// Op32 returns the OpCode for a 32-bit ALU operation with a given source. +func (op ALUOp) Op32(source Source) OpCode { + return OpCode(ALUClass).SetALUOp(op).SetSource(source) +} + +// Reg32 emits `dst (op) src`, zeroing the upper 32 bit of dst. +func (op ALUOp) Reg32(dst, src Register) Instruction { + return Instruction{ + OpCode: op.Op32(RegSource), + Dst: dst, + Src: src, + } +} + +// Imm32 emits `dst (op) value`, zeroing the upper 32 bit of dst. +func (op ALUOp) Imm32(dst Register, value int32) Instruction { + return Instruction{ + OpCode: op.Op32(ImmSource), + Dst: dst, + Constant: int64(value), + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/alu_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/alu_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/alu_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/alu_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +// Code generated by "stringer -output alu_string.go -type=Source,Endianness,ALUOp"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidSource-255] + _ = x[ImmSource-0] + _ = x[RegSource-8] +} + +const ( + _Source_name_0 = "ImmSource" + _Source_name_1 = "RegSource" + _Source_name_2 = "InvalidSource" +) + +func (i Source) String() string { + switch { + case i == 0: + return _Source_name_0 + case i == 8: + return _Source_name_1 + case i == 255: + return _Source_name_2 + default: + return "Source(" + strconv.FormatInt(int64(i), 10) + ")" + } +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidEndian-255] + _ = x[LE-0] + _ = x[BE-8] +} + +const ( + _Endianness_name_0 = "LE" + _Endianness_name_1 = "BE" + _Endianness_name_2 = "InvalidEndian" +) + +func (i Endianness) String() string { + switch { + case i == 0: + return _Endianness_name_0 + case i == 8: + return _Endianness_name_1 + case i == 255: + return _Endianness_name_2 + default: + return "Endianness(" + strconv.FormatInt(int64(i), 10) + ")" + } +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidALUOp-255] + _ = x[Add-0] + _ = x[Sub-16] + _ = x[Mul-32] + _ = x[Div-48] + _ = x[Or-64] + _ = x[And-80] + _ = x[LSh-96] + _ = x[RSh-112] + _ = x[Neg-128] + _ = x[Mod-144] + _ = x[Xor-160] + _ = x[Mov-176] + _ = x[ArSh-192] + _ = x[Swap-208] +} + +const _ALUOp_name = "AddSubMulDivOrAndLShRShNegModXorMovArShSwapInvalidALUOp" + +var _ALUOp_map = map[ALUOp]string{ + 0: _ALUOp_name[0:3], + 16: _ALUOp_name[3:6], + 32: _ALUOp_name[6:9], + 48: _ALUOp_name[9:12], + 64: _ALUOp_name[12:14], + 80: _ALUOp_name[14:17], + 96: _ALUOp_name[17:20], + 112: _ALUOp_name[20:23], + 128: _ALUOp_name[23:26], + 144: _ALUOp_name[26:29], + 160: _ALUOp_name[29:32], + 176: _ALUOp_name[32:35], + 192: _ALUOp_name[35:39], + 208: _ALUOp_name[39:43], + 255: _ALUOp_name[43:55], +} + +func (i ALUOp) String() string { + if str, ok := _ALUOp_map[i]; ok { + return str + } + return "ALUOp(" + strconv.FormatInt(int64(i), 10) + ")" +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/doc.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/doc.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +// Package asm is an assembler for eBPF bytecode. +package asm diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/func.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/func.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/func.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/func.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,195 @@ +package asm + +//go:generate stringer -output func_string.go -type=BuiltinFunc + +// BuiltinFunc is a built-in eBPF function. +type BuiltinFunc int32 + +// eBPF built-in functions +// +// You can regenerate this list using the following gawk script: +// +// /FN\(.+\),/ { +// match($1, /\((.+)\)/, r) +// split(r[1], p, "_") +// printf "Fn" +// for (i in p) { +// printf "%s%s", toupper(substr(p[i], 1, 1)), substr(p[i], 2) +// } +// print "" +// } +// +// The script expects include/uapi/linux/bpf.h as it's input. +const ( + FnUnspec BuiltinFunc = iota + FnMapLookupElem + FnMapUpdateElem + FnMapDeleteElem + FnProbeRead + FnKtimeGetNs + FnTracePrintk + FnGetPrandomU32 + FnGetSmpProcessorId + FnSkbStoreBytes + FnL3CsumReplace + FnL4CsumReplace + FnTailCall + FnCloneRedirect + FnGetCurrentPidTgid + FnGetCurrentUidGid + FnGetCurrentComm + FnGetCgroupClassid + FnSkbVlanPush + FnSkbVlanPop + FnSkbGetTunnelKey + FnSkbSetTunnelKey + FnPerfEventRead + FnRedirect + FnGetRouteRealm + FnPerfEventOutput + FnSkbLoadBytes + FnGetStackid + FnCsumDiff + FnSkbGetTunnelOpt + FnSkbSetTunnelOpt + FnSkbChangeProto + FnSkbChangeType + FnSkbUnderCgroup + FnGetHashRecalc + FnGetCurrentTask + FnProbeWriteUser + FnCurrentTaskUnderCgroup + FnSkbChangeTail + FnSkbPullData + FnCsumUpdate + FnSetHashInvalid + FnGetNumaNodeId + FnSkbChangeHead + FnXdpAdjustHead + FnProbeReadStr + FnGetSocketCookie + FnGetSocketUid + FnSetHash + FnSetsockopt + FnSkbAdjustRoom + FnRedirectMap + FnSkRedirectMap + FnSockMapUpdate + FnXdpAdjustMeta + FnPerfEventReadValue + FnPerfProgReadValue + FnGetsockopt + FnOverrideReturn + FnSockOpsCbFlagsSet + FnMsgRedirectMap + FnMsgApplyBytes + FnMsgCorkBytes + FnMsgPullData + FnBind + FnXdpAdjustTail + FnSkbGetXfrmState + FnGetStack + FnSkbLoadBytesRelative + FnFibLookup + FnSockHashUpdate + FnMsgRedirectHash + FnSkRedirectHash + FnLwtPushEncap + FnLwtSeg6StoreBytes + FnLwtSeg6AdjustSrh + FnLwtSeg6Action + FnRcRepeat + FnRcKeydown + FnSkbCgroupId + FnGetCurrentCgroupId + FnGetLocalStorage + FnSkSelectReuseport + FnSkbAncestorCgroupId + FnSkLookupTcp + FnSkLookupUdp + FnSkRelease + FnMapPushElem + FnMapPopElem + FnMapPeekElem + FnMsgPushData + FnMsgPopData + FnRcPointerRel + FnSpinLock + FnSpinUnlock + FnSkFullsock + FnTcpSock + FnSkbEcnSetCe + FnGetListenerSock + FnSkcLookupTcp + FnTcpCheckSyncookie + FnSysctlGetName + FnSysctlGetCurrentValue + FnSysctlGetNewValue + FnSysctlSetNewValue + FnStrtol + FnStrtoul + FnSkStorageGet + FnSkStorageDelete + FnSendSignal + FnTcpGenSyncookie + FnSkbOutput + FnProbeReadUser + FnProbeReadKernel + FnProbeReadUserStr + FnProbeReadKernelStr + FnTcpSendAck + FnSendSignalThread + FnJiffies64 + FnReadBranchRecords + FnGetNsCurrentPidTgid + FnXdpOutput + FnGetNetnsCookie + FnGetCurrentAncestorCgroupId + FnSkAssign + FnKtimeGetBootNs + FnSeqPrintf + FnSeqWrite + FnSkCgroupId + FnSkAncestorCgroupId + FnRingbufOutput + FnRingbufReserve + FnRingbufSubmit + FnRingbufDiscard + FnRingbufQuery + FnCsumLevel + FnSkcToTcp6Sock + FnSkcToTcpSock + FnSkcToTcpTimewaitSock + FnSkcToTcpRequestSock + FnSkcToUdp6Sock + FnGetTaskStack + FnLoadHdrOpt + FnStoreHdrOpt + FnReserveHdrOpt + FnInodeStorageGet + FnInodeStorageDelete + FnDPath + FnCopyFromUser + FnSnprintfBtf + FnSeqPrintfBtf + FnSkbCgroupClassid + FnRedirectNeigh + FnPerCpuPtr + FnThisCpuPtr + FnRedirectPeer + FnTaskStorageGet + FnTaskStorageDelete + FnGetCurrentTaskBtf + FnBprmOptsSet + FnKtimeGetCoarseNs + FnImaInodeHash + FnSockFromFile +) + +// Call emits a function call. +func (fn BuiltinFunc) Call() Instruction { + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(Call), + Constant: int64(fn), + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/func_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/func_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/func_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/func_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,185 @@ +// Code generated by "stringer -output func_string.go -type=BuiltinFunc"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[FnUnspec-0] + _ = x[FnMapLookupElem-1] + _ = x[FnMapUpdateElem-2] + _ = x[FnMapDeleteElem-3] + _ = x[FnProbeRead-4] + _ = x[FnKtimeGetNs-5] + _ = x[FnTracePrintk-6] + _ = x[FnGetPrandomU32-7] + _ = x[FnGetSmpProcessorId-8] + _ = x[FnSkbStoreBytes-9] + _ = x[FnL3CsumReplace-10] + _ = x[FnL4CsumReplace-11] + _ = x[FnTailCall-12] + _ = x[FnCloneRedirect-13] + _ = x[FnGetCurrentPidTgid-14] + _ = x[FnGetCurrentUidGid-15] + _ = x[FnGetCurrentComm-16] + _ = x[FnGetCgroupClassid-17] + _ = x[FnSkbVlanPush-18] + _ = x[FnSkbVlanPop-19] + _ = x[FnSkbGetTunnelKey-20] + _ = x[FnSkbSetTunnelKey-21] + _ = x[FnPerfEventRead-22] + _ = x[FnRedirect-23] + _ = x[FnGetRouteRealm-24] + _ = x[FnPerfEventOutput-25] + _ = x[FnSkbLoadBytes-26] + _ = x[FnGetStackid-27] + _ = x[FnCsumDiff-28] + _ = x[FnSkbGetTunnelOpt-29] + _ = x[FnSkbSetTunnelOpt-30] + _ = x[FnSkbChangeProto-31] + _ = x[FnSkbChangeType-32] + _ = x[FnSkbUnderCgroup-33] + _ = x[FnGetHashRecalc-34] + _ = x[FnGetCurrentTask-35] + _ = x[FnProbeWriteUser-36] + _ = x[FnCurrentTaskUnderCgroup-37] + _ = x[FnSkbChangeTail-38] + _ = x[FnSkbPullData-39] + _ = x[FnCsumUpdate-40] + _ = x[FnSetHashInvalid-41] + _ = x[FnGetNumaNodeId-42] + _ = x[FnSkbChangeHead-43] + _ = x[FnXdpAdjustHead-44] + _ = x[FnProbeReadStr-45] + _ = x[FnGetSocketCookie-46] + _ = x[FnGetSocketUid-47] + _ = x[FnSetHash-48] + _ = x[FnSetsockopt-49] + _ = x[FnSkbAdjustRoom-50] + _ = x[FnRedirectMap-51] + _ = x[FnSkRedirectMap-52] + _ = x[FnSockMapUpdate-53] + _ = x[FnXdpAdjustMeta-54] + _ = x[FnPerfEventReadValue-55] + _ = x[FnPerfProgReadValue-56] + _ = x[FnGetsockopt-57] + _ = x[FnOverrideReturn-58] + _ = x[FnSockOpsCbFlagsSet-59] + _ = x[FnMsgRedirectMap-60] + _ = x[FnMsgApplyBytes-61] + _ = x[FnMsgCorkBytes-62] + _ = x[FnMsgPullData-63] + _ = x[FnBind-64] + _ = x[FnXdpAdjustTail-65] + _ = x[FnSkbGetXfrmState-66] + _ = x[FnGetStack-67] + _ = x[FnSkbLoadBytesRelative-68] + _ = x[FnFibLookup-69] + _ = x[FnSockHashUpdate-70] + _ = x[FnMsgRedirectHash-71] + _ = x[FnSkRedirectHash-72] + _ = x[FnLwtPushEncap-73] + _ = x[FnLwtSeg6StoreBytes-74] + _ = x[FnLwtSeg6AdjustSrh-75] + _ = x[FnLwtSeg6Action-76] + _ = x[FnRcRepeat-77] + _ = x[FnRcKeydown-78] + _ = x[FnSkbCgroupId-79] + _ = x[FnGetCurrentCgroupId-80] + _ = x[FnGetLocalStorage-81] + _ = x[FnSkSelectReuseport-82] + _ = x[FnSkbAncestorCgroupId-83] + _ = x[FnSkLookupTcp-84] + _ = x[FnSkLookupUdp-85] + _ = x[FnSkRelease-86] + _ = x[FnMapPushElem-87] + _ = x[FnMapPopElem-88] + _ = x[FnMapPeekElem-89] + _ = x[FnMsgPushData-90] + _ = x[FnMsgPopData-91] + _ = x[FnRcPointerRel-92] + _ = x[FnSpinLock-93] + _ = x[FnSpinUnlock-94] + _ = x[FnSkFullsock-95] + _ = x[FnTcpSock-96] + _ = x[FnSkbEcnSetCe-97] + _ = x[FnGetListenerSock-98] + _ = x[FnSkcLookupTcp-99] + _ = x[FnTcpCheckSyncookie-100] + _ = x[FnSysctlGetName-101] + _ = x[FnSysctlGetCurrentValue-102] + _ = x[FnSysctlGetNewValue-103] + _ = x[FnSysctlSetNewValue-104] + _ = x[FnStrtol-105] + _ = x[FnStrtoul-106] + _ = x[FnSkStorageGet-107] + _ = x[FnSkStorageDelete-108] + _ = x[FnSendSignal-109] + _ = x[FnTcpGenSyncookie-110] + _ = x[FnSkbOutput-111] + _ = x[FnProbeReadUser-112] + _ = x[FnProbeReadKernel-113] + _ = x[FnProbeReadUserStr-114] + _ = x[FnProbeReadKernelStr-115] + _ = x[FnTcpSendAck-116] + _ = x[FnSendSignalThread-117] + _ = x[FnJiffies64-118] + _ = x[FnReadBranchRecords-119] + _ = x[FnGetNsCurrentPidTgid-120] + _ = x[FnXdpOutput-121] + _ = x[FnGetNetnsCookie-122] + _ = x[FnGetCurrentAncestorCgroupId-123] + _ = x[FnSkAssign-124] + _ = x[FnKtimeGetBootNs-125] + _ = x[FnSeqPrintf-126] + _ = x[FnSeqWrite-127] + _ = x[FnSkCgroupId-128] + _ = x[FnSkAncestorCgroupId-129] + _ = x[FnRingbufOutput-130] + _ = x[FnRingbufReserve-131] + _ = x[FnRingbufSubmit-132] + _ = x[FnRingbufDiscard-133] + _ = x[FnRingbufQuery-134] + _ = x[FnCsumLevel-135] + _ = x[FnSkcToTcp6Sock-136] + _ = x[FnSkcToTcpSock-137] + _ = x[FnSkcToTcpTimewaitSock-138] + _ = x[FnSkcToTcpRequestSock-139] + _ = x[FnSkcToUdp6Sock-140] + _ = x[FnGetTaskStack-141] + _ = x[FnLoadHdrOpt-142] + _ = x[FnStoreHdrOpt-143] + _ = x[FnReserveHdrOpt-144] + _ = x[FnInodeStorageGet-145] + _ = x[FnInodeStorageDelete-146] + _ = x[FnDPath-147] + _ = x[FnCopyFromUser-148] + _ = x[FnSnprintfBtf-149] + _ = x[FnSeqPrintfBtf-150] + _ = x[FnSkbCgroupClassid-151] + _ = x[FnRedirectNeigh-152] + _ = x[FnPerCpuPtr-153] + _ = x[FnThisCpuPtr-154] + _ = x[FnRedirectPeer-155] + _ = x[FnTaskStorageGet-156] + _ = x[FnTaskStorageDelete-157] + _ = x[FnGetCurrentTaskBtf-158] + _ = x[FnBprmOptsSet-159] + _ = x[FnKtimeGetCoarseNs-160] + _ = x[FnImaInodeHash-161] + _ = x[FnSockFromFile-162] +} + +const _BuiltinFunc_name = "FnUnspecFnMapLookupElemFnMapUpdateElemFnMapDeleteElemFnProbeReadFnKtimeGetNsFnTracePrintkFnGetPrandomU32FnGetSmpProcessorIdFnSkbStoreBytesFnL3CsumReplaceFnL4CsumReplaceFnTailCallFnCloneRedirectFnGetCurrentPidTgidFnGetCurrentUidGidFnGetCurrentCommFnGetCgroupClassidFnSkbVlanPushFnSkbVlanPopFnSkbGetTunnelKeyFnSkbSetTunnelKeyFnPerfEventReadFnRedirectFnGetRouteRealmFnPerfEventOutputFnSkbLoadBytesFnGetStackidFnCsumDiffFnSkbGetTunnelOptFnSkbSetTunnelOptFnSkbChangeProtoFnSkbChangeTypeFnSkbUnderCgroupFnGetHashRecalcFnGetCurrentTaskFnProbeWriteUserFnCurrentTaskUnderCgroupFnSkbChangeTailFnSkbPullDataFnCsumUpdateFnSetHashInvalidFnGetNumaNodeIdFnSkbChangeHeadFnXdpAdjustHeadFnProbeReadStrFnGetSocketCookieFnGetSocketUidFnSetHashFnSetsockoptFnSkbAdjustRoomFnRedirectMapFnSkRedirectMapFnSockMapUpdateFnXdpAdjustMetaFnPerfEventReadValueFnPerfProgReadValueFnGetsockoptFnOverrideReturnFnSockOpsCbFlagsSetFnMsgRedirectMapFnMsgApplyBytesFnMsgCorkBytesFnMsgPullDataFnBindFnXdpAdjustTailFnSkbGetXfrmStateFnGetStackFnSkbLoadBytesRelativeFnFibLookupFnSockHashUpdateFnMsgRedirectHashFnSkRedirectHashFnLwtPushEncapFnLwtSeg6StoreBytesFnLwtSeg6AdjustSrhFnLwtSeg6ActionFnRcRepeatFnRcKeydownFnSkbCgroupIdFnGetCurrentCgroupIdFnGetLocalStorageFnSkSelectReuseportFnSkbAncestorCgroupIdFnSkLookupTcpFnSkLookupUdpFnSkReleaseFnMapPushElemFnMapPopElemFnMapPeekElemFnMsgPushDataFnMsgPopDataFnRcPointerRelFnSpinLockFnSpinUnlockFnSkFullsockFnTcpSockFnSkbEcnSetCeFnGetListenerSockFnSkcLookupTcpFnTcpCheckSyncookieFnSysctlGetNameFnSysctlGetCurrentValueFnSysctlGetNewValueFnSysctlSetNewValueFnStrtolFnStrtoulFnSkStorageGetFnSkStorageDeleteFnSendSignalFnTcpGenSyncookieFnSkbOutputFnProbeReadUserFnProbeReadKernelFnProbeReadUserStrFnProbeReadKernelStrFnTcpSendAckFnSendSignalThreadFnJiffies64FnReadBranchRecordsFnGetNsCurrentPidTgidFnXdpOutputFnGetNetnsCookieFnGetCurrentAncestorCgroupIdFnSkAssignFnKtimeGetBootNsFnSeqPrintfFnSeqWriteFnSkCgroupIdFnSkAncestorCgroupIdFnRingbufOutputFnRingbufReserveFnRingbufSubmitFnRingbufDiscardFnRingbufQueryFnCsumLevelFnSkcToTcp6SockFnSkcToTcpSockFnSkcToTcpTimewaitSockFnSkcToTcpRequestSockFnSkcToUdp6SockFnGetTaskStackFnLoadHdrOptFnStoreHdrOptFnReserveHdrOptFnInodeStorageGetFnInodeStorageDeleteFnDPathFnCopyFromUserFnSnprintfBtfFnSeqPrintfBtfFnSkbCgroupClassidFnRedirectNeighFnPerCpuPtrFnThisCpuPtrFnRedirectPeerFnTaskStorageGetFnTaskStorageDeleteFnGetCurrentTaskBtfFnBprmOptsSetFnKtimeGetCoarseNsFnImaInodeHashFnSockFromFile" + +var _BuiltinFunc_index = [...]uint16{0, 8, 23, 38, 53, 64, 76, 89, 104, 123, 138, 153, 168, 178, 193, 212, 230, 246, 264, 277, 289, 306, 323, 338, 348, 363, 380, 394, 406, 416, 433, 450, 466, 481, 497, 512, 528, 544, 568, 583, 596, 608, 624, 639, 654, 669, 683, 700, 714, 723, 735, 750, 763, 778, 793, 808, 828, 847, 859, 875, 894, 910, 925, 939, 952, 958, 973, 990, 1000, 1022, 1033, 1049, 1066, 1082, 1096, 1115, 1133, 1148, 1158, 1169, 1182, 1202, 1219, 1238, 1259, 1272, 1285, 1296, 1309, 1321, 1334, 1347, 1359, 1373, 1383, 1395, 1407, 1416, 1429, 1446, 1460, 1479, 1494, 1517, 1536, 1555, 1563, 1572, 1586, 1603, 1615, 1632, 1643, 1658, 1675, 1693, 1713, 1725, 1743, 1754, 1773, 1794, 1805, 1821, 1849, 1859, 1875, 1886, 1896, 1908, 1928, 1943, 1959, 1974, 1990, 2004, 2015, 2030, 2044, 2066, 2087, 2102, 2116, 2128, 2141, 2156, 2173, 2193, 2200, 2214, 2227, 2241, 2259, 2274, 2285, 2297, 2311, 2327, 2346, 2365, 2378, 2396, 2410, 2424} + +func (i BuiltinFunc) String() string { + if i < 0 || i >= BuiltinFunc(len(_BuiltinFunc_index)-1) { + return "BuiltinFunc(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BuiltinFunc_name[_BuiltinFunc_index[i]:_BuiltinFunc_index[i+1]] +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/instruction.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/instruction.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/instruction.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/instruction.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,506 @@ +package asm + +import ( + "crypto/sha1" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "math" + "strings" + + "github.com/cilium/ebpf/internal/unix" +) + +// InstructionSize is the size of a BPF instruction in bytes +const InstructionSize = 8 + +// RawInstructionOffset is an offset in units of raw BPF instructions. +type RawInstructionOffset uint64 + +// Bytes returns the offset of an instruction in bytes. +func (rio RawInstructionOffset) Bytes() uint64 { + return uint64(rio) * InstructionSize +} + +// Instruction is a single eBPF instruction. +type Instruction struct { + OpCode OpCode + Dst Register + Src Register + Offset int16 + Constant int64 + Reference string + Symbol string +} + +// Sym creates a symbol. +func (ins Instruction) Sym(name string) Instruction { + ins.Symbol = name + return ins +} + +// Unmarshal decodes a BPF instruction. +func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, error) { + var bi bpfInstruction + err := binary.Read(r, bo, &bi) + if err != nil { + return 0, err + } + + ins.OpCode = bi.OpCode + ins.Offset = bi.Offset + ins.Constant = int64(bi.Constant) + ins.Dst, ins.Src, err = bi.Registers.Unmarshal(bo) + if err != nil { + return 0, fmt.Errorf("can't unmarshal registers: %s", err) + } + + if !bi.OpCode.IsDWordLoad() { + return InstructionSize, nil + } + + var bi2 bpfInstruction + if err := binary.Read(r, bo, &bi2); err != nil { + // No Wrap, to avoid io.EOF clash + return 0, errors.New("64bit immediate is missing second half") + } + if bi2.OpCode != 0 || bi2.Offset != 0 || bi2.Registers != 0 { + return 0, errors.New("64bit immediate has non-zero fields") + } + ins.Constant = int64(uint64(uint32(bi2.Constant))<<32 | uint64(uint32(bi.Constant))) + + return 2 * InstructionSize, nil +} + +// Marshal encodes a BPF instruction. +func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) { + if ins.OpCode == InvalidOpCode { + return 0, errors.New("invalid opcode") + } + + isDWordLoad := ins.OpCode.IsDWordLoad() + + cons := int32(ins.Constant) + if isDWordLoad { + // Encode least significant 32bit first for 64bit operations. + cons = int32(uint32(ins.Constant)) + } + + regs, err := newBPFRegisters(ins.Dst, ins.Src, bo) + if err != nil { + return 0, fmt.Errorf("can't marshal registers: %s", err) + } + + bpfi := bpfInstruction{ + ins.OpCode, + regs, + ins.Offset, + cons, + } + + if err := binary.Write(w, bo, &bpfi); err != nil { + return 0, err + } + + if !isDWordLoad { + return InstructionSize, nil + } + + bpfi = bpfInstruction{ + Constant: int32(ins.Constant >> 32), + } + + if err := binary.Write(w, bo, &bpfi); err != nil { + return 0, err + } + + return 2 * InstructionSize, nil +} + +// RewriteMapPtr changes an instruction to use a new map fd. +// +// Returns an error if the instruction doesn't load a map. +func (ins *Instruction) RewriteMapPtr(fd int) error { + if !ins.OpCode.IsDWordLoad() { + return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) + } + + if ins.Src != PseudoMapFD && ins.Src != PseudoMapValue { + return errors.New("not a load from a map") + } + + // Preserve the offset value for direct map loads. + offset := uint64(ins.Constant) & (math.MaxUint32 << 32) + rawFd := uint64(uint32(fd)) + ins.Constant = int64(offset | rawFd) + return nil +} + +// MapPtr returns the map fd for this instruction. +// +// The result is undefined if the instruction is not a load from a map, +// see IsLoadFromMap. +func (ins *Instruction) MapPtr() int { + return int(int32(uint64(ins.Constant) & math.MaxUint32)) +} + +// RewriteMapOffset changes the offset of a direct load from a map. +// +// Returns an error if the instruction is not a direct load. +func (ins *Instruction) RewriteMapOffset(offset uint32) error { + if !ins.OpCode.IsDWordLoad() { + return fmt.Errorf("%s is not a 64 bit load", ins.OpCode) + } + + if ins.Src != PseudoMapValue { + return errors.New("not a direct load from a map") + } + + fd := uint64(ins.Constant) & math.MaxUint32 + ins.Constant = int64(uint64(offset)<<32 | fd) + return nil +} + +func (ins *Instruction) mapOffset() uint32 { + return uint32(uint64(ins.Constant) >> 32) +} + +// IsLoadFromMap returns true if the instruction loads from a map. +// +// This covers both loading the map pointer and direct map value loads. +func (ins *Instruction) IsLoadFromMap() bool { + return ins.OpCode == LoadImmOp(DWord) && (ins.Src == PseudoMapFD || ins.Src == PseudoMapValue) +} + +// IsFunctionCall returns true if the instruction calls another BPF function. +// +// This is not the same thing as a BPF helper call. +func (ins *Instruction) IsFunctionCall() bool { + return ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall +} + +// IsConstantLoad returns true if the instruction loads a constant of the +// given size. +func (ins *Instruction) IsConstantLoad(size Size) bool { + return ins.OpCode == LoadImmOp(size) && ins.Src == R0 && ins.Offset == 0 +} + +// Format implements fmt.Formatter. +func (ins Instruction) Format(f fmt.State, c rune) { + if c != 'v' { + fmt.Fprintf(f, "{UNRECOGNIZED: %c}", c) + return + } + + op := ins.OpCode + + if op == InvalidOpCode { + fmt.Fprint(f, "INVALID") + return + } + + // Omit trailing space for Exit + if op.JumpOp() == Exit { + fmt.Fprint(f, op) + return + } + + if ins.IsLoadFromMap() { + fd := ins.MapPtr() + switch ins.Src { + case PseudoMapFD: + fmt.Fprintf(f, "LoadMapPtr dst: %s fd: %d", ins.Dst, fd) + + case PseudoMapValue: + fmt.Fprintf(f, "LoadMapValue dst: %s, fd: %d off: %d", ins.Dst, fd, ins.mapOffset()) + } + + goto ref + } + + fmt.Fprintf(f, "%v ", op) + switch cls := op.Class(); cls { + case LdClass, LdXClass, StClass, StXClass: + switch op.Mode() { + case ImmMode: + fmt.Fprintf(f, "dst: %s imm: %d", ins.Dst, ins.Constant) + case AbsMode: + fmt.Fprintf(f, "imm: %d", ins.Constant) + case IndMode: + fmt.Fprintf(f, "dst: %s src: %s imm: %d", ins.Dst, ins.Src, ins.Constant) + case MemMode: + fmt.Fprintf(f, "dst: %s src: %s off: %d imm: %d", ins.Dst, ins.Src, ins.Offset, ins.Constant) + case XAddMode: + fmt.Fprintf(f, "dst: %s src: %s", ins.Dst, ins.Src) + } + + case ALU64Class, ALUClass: + fmt.Fprintf(f, "dst: %s ", ins.Dst) + if op.ALUOp() == Swap || op.Source() == ImmSource { + fmt.Fprintf(f, "imm: %d", ins.Constant) + } else { + fmt.Fprintf(f, "src: %s", ins.Src) + } + + case JumpClass: + switch jop := op.JumpOp(); jop { + case Call: + if ins.Src == PseudoCall { + // bpf-to-bpf call + fmt.Fprint(f, ins.Constant) + } else { + fmt.Fprint(f, BuiltinFunc(ins.Constant)) + } + + default: + fmt.Fprintf(f, "dst: %s off: %d ", ins.Dst, ins.Offset) + if op.Source() == ImmSource { + fmt.Fprintf(f, "imm: %d", ins.Constant) + } else { + fmt.Fprintf(f, "src: %s", ins.Src) + } + } + } + +ref: + if ins.Reference != "" { + fmt.Fprintf(f, " <%s>", ins.Reference) + } +} + +// Instructions is an eBPF program. +type Instructions []Instruction + +func (insns Instructions) String() string { + return fmt.Sprint(insns) +} + +// RewriteMapPtr rewrites all loads of a specific map pointer to a new fd. +// +// Returns an error if the symbol isn't used, see IsUnreferencedSymbol. +func (insns Instructions) RewriteMapPtr(symbol string, fd int) error { + if symbol == "" { + return errors.New("empty symbol") + } + + found := false + for i := range insns { + ins := &insns[i] + if ins.Reference != symbol { + continue + } + + if err := ins.RewriteMapPtr(fd); err != nil { + return err + } + + found = true + } + + if !found { + return &unreferencedSymbolError{symbol} + } + + return nil +} + +// SymbolOffsets returns the set of symbols and their offset in +// the instructions. +func (insns Instructions) SymbolOffsets() (map[string]int, error) { + offsets := make(map[string]int) + + for i, ins := range insns { + if ins.Symbol == "" { + continue + } + + if _, ok := offsets[ins.Symbol]; ok { + return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol) + } + + offsets[ins.Symbol] = i + } + + return offsets, nil +} + +// ReferenceOffsets returns the set of references and their offset in +// the instructions. +func (insns Instructions) ReferenceOffsets() map[string][]int { + offsets := make(map[string][]int) + + for i, ins := range insns { + if ins.Reference == "" { + continue + } + + offsets[ins.Reference] = append(offsets[ins.Reference], i) + } + + return offsets +} + +// Format implements fmt.Formatter. +// +// You can control indentation of symbols by +// specifying a width. Setting a precision controls the indentation of +// instructions. +// The default character is a tab, which can be overridden by specifying +// the ' ' space flag. +func (insns Instructions) Format(f fmt.State, c rune) { + if c != 's' && c != 'v' { + fmt.Fprintf(f, "{UNKNOWN FORMAT '%c'}", c) + return + } + + // Precision is better in this case, because it allows + // specifying 0 padding easily. + padding, ok := f.Precision() + if !ok { + padding = 1 + } + + indent := strings.Repeat("\t", padding) + if f.Flag(' ') { + indent = strings.Repeat(" ", padding) + } + + symPadding, ok := f.Width() + if !ok { + symPadding = padding - 1 + } + if symPadding < 0 { + symPadding = 0 + } + + symIndent := strings.Repeat("\t", symPadding) + if f.Flag(' ') { + symIndent = strings.Repeat(" ", symPadding) + } + + // Guess how many digits we need at most, by assuming that all instructions + // are double wide. + highestOffset := len(insns) * 2 + offsetWidth := int(math.Ceil(math.Log10(float64(highestOffset)))) + + iter := insns.Iterate() + for iter.Next() { + if iter.Ins.Symbol != "" { + fmt.Fprintf(f, "%s%s:\n", symIndent, iter.Ins.Symbol) + } + fmt.Fprintf(f, "%s%*d: %v\n", indent, offsetWidth, iter.Offset, iter.Ins) + } +} + +// Marshal encodes a BPF program into the kernel format. +func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error { + for i, ins := range insns { + _, err := ins.Marshal(w, bo) + if err != nil { + return fmt.Errorf("instruction %d: %w", i, err) + } + } + return nil +} + +// Tag calculates the kernel tag for a series of instructions. +// +// It mirrors bpf_prog_calc_tag in the kernel and so can be compared +// to ProgramInfo.Tag to figure out whether a loaded program matches +// certain instructions. +func (insns Instructions) Tag(bo binary.ByteOrder) (string, error) { + h := sha1.New() + for i, ins := range insns { + if ins.IsLoadFromMap() { + ins.Constant = 0 + } + _, err := ins.Marshal(h, bo) + if err != nil { + return "", fmt.Errorf("instruction %d: %w", i, err) + } + } + return hex.EncodeToString(h.Sum(nil)[:unix.BPF_TAG_SIZE]), nil +} + +// Iterate allows iterating a BPF program while keeping track of +// various offsets. +// +// Modifying the instruction slice will lead to undefined behaviour. +func (insns Instructions) Iterate() *InstructionIterator { + return &InstructionIterator{insns: insns} +} + +// InstructionIterator iterates over a BPF program. +type InstructionIterator struct { + insns Instructions + // The instruction in question. + Ins *Instruction + // The index of the instruction in the original instruction slice. + Index int + // The offset of the instruction in raw BPF instructions. This accounts + // for double-wide instructions. + Offset RawInstructionOffset +} + +// Next returns true as long as there are any instructions remaining. +func (iter *InstructionIterator) Next() bool { + if len(iter.insns) == 0 { + return false + } + + if iter.Ins != nil { + iter.Index++ + iter.Offset += RawInstructionOffset(iter.Ins.OpCode.rawInstructions()) + } + iter.Ins = &iter.insns[0] + iter.insns = iter.insns[1:] + return true +} + +type bpfInstruction struct { + OpCode OpCode + Registers bpfRegisters + Offset int16 + Constant int32 +} + +type bpfRegisters uint8 + +func newBPFRegisters(dst, src Register, bo binary.ByteOrder) (bpfRegisters, error) { + switch bo { + case binary.LittleEndian: + return bpfRegisters((src << 4) | (dst & 0xF)), nil + case binary.BigEndian: + return bpfRegisters((dst << 4) | (src & 0xF)), nil + default: + return 0, fmt.Errorf("unrecognized ByteOrder %T", bo) + } +} + +func (r bpfRegisters) Unmarshal(bo binary.ByteOrder) (dst, src Register, err error) { + switch bo { + case binary.LittleEndian: + return Register(r & 0xF), Register(r >> 4), nil + case binary.BigEndian: + return Register(r >> 4), Register(r & 0xf), nil + default: + return 0, 0, fmt.Errorf("unrecognized ByteOrder %T", bo) + } +} + +type unreferencedSymbolError struct { + symbol string +} + +func (use *unreferencedSymbolError) Error() string { + return fmt.Sprintf("unreferenced symbol %s", use.symbol) +} + +// IsUnreferencedSymbol returns true if err was caused by +// an unreferenced symbol. +func IsUnreferencedSymbol(err error) bool { + _, ok := err.(*unreferencedSymbolError) + return ok +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/jump.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/jump.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/jump.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/jump.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,109 @@ +package asm + +//go:generate stringer -output jump_string.go -type=JumpOp + +// JumpOp affect control flow. +// +// msb lsb +// +----+-+---+ +// |OP |s|cls| +// +----+-+---+ +type JumpOp uint8 + +const jumpMask OpCode = aluMask + +const ( + // InvalidJumpOp is returned by getters when invoked + // on non branch OpCodes + InvalidJumpOp JumpOp = 0xff + // Ja jumps by offset unconditionally + Ja JumpOp = 0x00 + // JEq jumps by offset if r == imm + JEq JumpOp = 0x10 + // JGT jumps by offset if r > imm + JGT JumpOp = 0x20 + // JGE jumps by offset if r >= imm + JGE JumpOp = 0x30 + // JSet jumps by offset if r & imm + JSet JumpOp = 0x40 + // JNE jumps by offset if r != imm + JNE JumpOp = 0x50 + // JSGT jumps by offset if signed r > signed imm + JSGT JumpOp = 0x60 + // JSGE jumps by offset if signed r >= signed imm + JSGE JumpOp = 0x70 + // Call builtin or user defined function from imm + Call JumpOp = 0x80 + // Exit ends execution, with value in r0 + Exit JumpOp = 0x90 + // JLT jumps by offset if r < imm + JLT JumpOp = 0xa0 + // JLE jumps by offset if r <= imm + JLE JumpOp = 0xb0 + // JSLT jumps by offset if signed r < signed imm + JSLT JumpOp = 0xc0 + // JSLE jumps by offset if signed r <= signed imm + JSLE JumpOp = 0xd0 +) + +// Return emits an exit instruction. +// +// Requires a return value in R0. +func Return() Instruction { + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(Exit), + } +} + +// Op returns the OpCode for a given jump source. +func (op JumpOp) Op(source Source) OpCode { + return OpCode(JumpClass).SetJumpOp(op).SetSource(source) +} + +// Imm compares dst to value, and adjusts PC by offset if the condition is fulfilled. +func (op JumpOp) Imm(dst Register, value int32, label string) Instruction { + if op == Exit || op == Call || op == Ja { + return Instruction{OpCode: InvalidOpCode} + } + + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(op).SetSource(ImmSource), + Dst: dst, + Offset: -1, + Constant: int64(value), + Reference: label, + } +} + +// Reg compares dst to src, and adjusts PC by offset if the condition is fulfilled. +func (op JumpOp) Reg(dst, src Register, label string) Instruction { + if op == Exit || op == Call || op == Ja { + return Instruction{OpCode: InvalidOpCode} + } + + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(op).SetSource(RegSource), + Dst: dst, + Src: src, + Offset: -1, + Reference: label, + } +} + +// Label adjusts PC to the address of the label. +func (op JumpOp) Label(label string) Instruction { + if op == Call { + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(Call), + Src: PseudoCall, + Constant: -1, + Reference: label, + } + } + + return Instruction{ + OpCode: OpCode(JumpClass).SetJumpOp(op), + Offset: -1, + Reference: label, + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/jump_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/jump_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/jump_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/jump_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,53 @@ +// Code generated by "stringer -output jump_string.go -type=JumpOp"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidJumpOp-255] + _ = x[Ja-0] + _ = x[JEq-16] + _ = x[JGT-32] + _ = x[JGE-48] + _ = x[JSet-64] + _ = x[JNE-80] + _ = x[JSGT-96] + _ = x[JSGE-112] + _ = x[Call-128] + _ = x[Exit-144] + _ = x[JLT-160] + _ = x[JLE-176] + _ = x[JSLT-192] + _ = x[JSLE-208] +} + +const _JumpOp_name = "JaJEqJGTJGEJSetJNEJSGTJSGECallExitJLTJLEJSLTJSLEInvalidJumpOp" + +var _JumpOp_map = map[JumpOp]string{ + 0: _JumpOp_name[0:2], + 16: _JumpOp_name[2:5], + 32: _JumpOp_name[5:8], + 48: _JumpOp_name[8:11], + 64: _JumpOp_name[11:15], + 80: _JumpOp_name[15:18], + 96: _JumpOp_name[18:22], + 112: _JumpOp_name[22:26], + 128: _JumpOp_name[26:30], + 144: _JumpOp_name[30:34], + 160: _JumpOp_name[34:37], + 176: _JumpOp_name[37:40], + 192: _JumpOp_name[40:44], + 208: _JumpOp_name[44:48], + 255: _JumpOp_name[48:61], +} + +func (i JumpOp) String() string { + if str, ok := _JumpOp_map[i]; ok { + return str + } + return "JumpOp(" + strconv.FormatInt(int64(i), 10) + ")" +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/load_store.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/load_store.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/load_store.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/load_store.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,204 @@ +package asm + +//go:generate stringer -output load_store_string.go -type=Mode,Size + +// Mode for load and store operations +// +// msb lsb +// +---+--+---+ +// |MDE|sz|cls| +// +---+--+---+ +type Mode uint8 + +const modeMask OpCode = 0xe0 + +const ( + // InvalidMode is returned by getters when invoked + // on non load / store OpCodes + InvalidMode Mode = 0xff + // ImmMode - immediate value + ImmMode Mode = 0x00 + // AbsMode - immediate value + offset + AbsMode Mode = 0x20 + // IndMode - indirect (imm+src) + IndMode Mode = 0x40 + // MemMode - load from memory + MemMode Mode = 0x60 + // XAddMode - add atomically across processors. + XAddMode Mode = 0xc0 +) + +// Size of load and store operations +// +// msb lsb +// +---+--+---+ +// |mde|SZ|cls| +// +---+--+---+ +type Size uint8 + +const sizeMask OpCode = 0x18 + +const ( + // InvalidSize is returned by getters when invoked + // on non load / store OpCodes + InvalidSize Size = 0xff + // DWord - double word; 64 bits + DWord Size = 0x18 + // Word - word; 32 bits + Word Size = 0x00 + // Half - half-word; 16 bits + Half Size = 0x08 + // Byte - byte; 8 bits + Byte Size = 0x10 +) + +// Sizeof returns the size in bytes. +func (s Size) Sizeof() int { + switch s { + case DWord: + return 8 + case Word: + return 4 + case Half: + return 2 + case Byte: + return 1 + default: + return -1 + } +} + +// LoadMemOp returns the OpCode to load a value of given size from memory. +func LoadMemOp(size Size) OpCode { + return OpCode(LdXClass).SetMode(MemMode).SetSize(size) +} + +// LoadMem emits `dst = *(size *)(src + offset)`. +func LoadMem(dst, src Register, offset int16, size Size) Instruction { + return Instruction{ + OpCode: LoadMemOp(size), + Dst: dst, + Src: src, + Offset: offset, + } +} + +// LoadImmOp returns the OpCode to load an immediate of given size. +// +// As of kernel 4.20, only DWord size is accepted. +func LoadImmOp(size Size) OpCode { + return OpCode(LdClass).SetMode(ImmMode).SetSize(size) +} + +// LoadImm emits `dst = (size)value`. +// +// As of kernel 4.20, only DWord size is accepted. +func LoadImm(dst Register, value int64, size Size) Instruction { + return Instruction{ + OpCode: LoadImmOp(size), + Dst: dst, + Constant: value, + } +} + +// LoadMapPtr stores a pointer to a map in dst. +func LoadMapPtr(dst Register, fd int) Instruction { + if fd < 0 { + return Instruction{OpCode: InvalidOpCode} + } + + return Instruction{ + OpCode: LoadImmOp(DWord), + Dst: dst, + Src: PseudoMapFD, + Constant: int64(uint32(fd)), + } +} + +// LoadMapValue stores a pointer to the value at a certain offset of a map. +func LoadMapValue(dst Register, fd int, offset uint32) Instruction { + if fd < 0 { + return Instruction{OpCode: InvalidOpCode} + } + + fdAndOffset := (uint64(offset) << 32) | uint64(uint32(fd)) + return Instruction{ + OpCode: LoadImmOp(DWord), + Dst: dst, + Src: PseudoMapValue, + Constant: int64(fdAndOffset), + } +} + +// LoadIndOp returns the OpCode for loading a value of given size from an sk_buff. +func LoadIndOp(size Size) OpCode { + return OpCode(LdClass).SetMode(IndMode).SetSize(size) +} + +// LoadInd emits `dst = ntoh(*(size *)(((sk_buff *)R6)->data + src + offset))`. +func LoadInd(dst, src Register, offset int32, size Size) Instruction { + return Instruction{ + OpCode: LoadIndOp(size), + Dst: dst, + Src: src, + Constant: int64(offset), + } +} + +// LoadAbsOp returns the OpCode for loading a value of given size from an sk_buff. +func LoadAbsOp(size Size) OpCode { + return OpCode(LdClass).SetMode(AbsMode).SetSize(size) +} + +// LoadAbs emits `r0 = ntoh(*(size *)(((sk_buff *)R6)->data + offset))`. +func LoadAbs(offset int32, size Size) Instruction { + return Instruction{ + OpCode: LoadAbsOp(size), + Dst: R0, + Constant: int64(offset), + } +} + +// StoreMemOp returns the OpCode for storing a register of given size in memory. +func StoreMemOp(size Size) OpCode { + return OpCode(StXClass).SetMode(MemMode).SetSize(size) +} + +// StoreMem emits `*(size *)(dst + offset) = src` +func StoreMem(dst Register, offset int16, src Register, size Size) Instruction { + return Instruction{ + OpCode: StoreMemOp(size), + Dst: dst, + Src: src, + Offset: offset, + } +} + +// StoreImmOp returns the OpCode for storing an immediate of given size in memory. +func StoreImmOp(size Size) OpCode { + return OpCode(StClass).SetMode(MemMode).SetSize(size) +} + +// StoreImm emits `*(size *)(dst + offset) = value`. +func StoreImm(dst Register, offset int16, value int64, size Size) Instruction { + return Instruction{ + OpCode: StoreImmOp(size), + Dst: dst, + Offset: offset, + Constant: value, + } +} + +// StoreXAddOp returns the OpCode to atomically add a register to a value in memory. +func StoreXAddOp(size Size) OpCode { + return OpCode(StXClass).SetMode(XAddMode).SetSize(size) +} + +// StoreXAdd atomically adds src to *dst. +func StoreXAdd(dst, src Register, size Size) Instruction { + return Instruction{ + OpCode: StoreXAddOp(size), + Dst: dst, + Src: src, + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/load_store_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/load_store_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/load_store_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/load_store_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,80 @@ +// Code generated by "stringer -output load_store_string.go -type=Mode,Size"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidMode-255] + _ = x[ImmMode-0] + _ = x[AbsMode-32] + _ = x[IndMode-64] + _ = x[MemMode-96] + _ = x[XAddMode-192] +} + +const ( + _Mode_name_0 = "ImmMode" + _Mode_name_1 = "AbsMode" + _Mode_name_2 = "IndMode" + _Mode_name_3 = "MemMode" + _Mode_name_4 = "XAddMode" + _Mode_name_5 = "InvalidMode" +) + +func (i Mode) String() string { + switch { + case i == 0: + return _Mode_name_0 + case i == 32: + return _Mode_name_1 + case i == 64: + return _Mode_name_2 + case i == 96: + return _Mode_name_3 + case i == 192: + return _Mode_name_4 + case i == 255: + return _Mode_name_5 + default: + return "Mode(" + strconv.FormatInt(int64(i), 10) + ")" + } +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidSize-255] + _ = x[DWord-24] + _ = x[Word-0] + _ = x[Half-8] + _ = x[Byte-16] +} + +const ( + _Size_name_0 = "Word" + _Size_name_1 = "Half" + _Size_name_2 = "Byte" + _Size_name_3 = "DWord" + _Size_name_4 = "InvalidSize" +) + +func (i Size) String() string { + switch { + case i == 0: + return _Size_name_0 + case i == 8: + return _Size_name_1 + case i == 16: + return _Size_name_2 + case i == 24: + return _Size_name_3 + case i == 255: + return _Size_name_4 + default: + return "Size(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/opcode.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/opcode.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/opcode.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/opcode.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,237 @@ +package asm + +import ( + "fmt" + "strings" +) + +//go:generate stringer -output opcode_string.go -type=Class + +type encoding int + +const ( + unknownEncoding encoding = iota + loadOrStore + jumpOrALU +) + +// Class of operations +// +// msb lsb +// +---+--+---+ +// | ?? |CLS| +// +---+--+---+ +type Class uint8 + +const classMask OpCode = 0x07 + +const ( + // LdClass load memory + LdClass Class = 0x00 + // LdXClass load memory from constant + LdXClass Class = 0x01 + // StClass load register from memory + StClass Class = 0x02 + // StXClass load register from constant + StXClass Class = 0x03 + // ALUClass arithmetic operators + ALUClass Class = 0x04 + // JumpClass jump operators + JumpClass Class = 0x05 + // ALU64Class arithmetic in 64 bit mode + ALU64Class Class = 0x07 +) + +func (cls Class) encoding() encoding { + switch cls { + case LdClass, LdXClass, StClass, StXClass: + return loadOrStore + case ALU64Class, ALUClass, JumpClass: + return jumpOrALU + default: + return unknownEncoding + } +} + +// OpCode is a packed eBPF opcode. +// +// Its encoding is defined by a Class value: +// +// msb lsb +// +----+-+---+ +// | ???? |CLS| +// +----+-+---+ +type OpCode uint8 + +// InvalidOpCode is returned by setters on OpCode +const InvalidOpCode OpCode = 0xff + +// rawInstructions returns the number of BPF instructions required +// to encode this opcode. +func (op OpCode) rawInstructions() int { + if op.IsDWordLoad() { + return 2 + } + return 1 +} + +func (op OpCode) IsDWordLoad() bool { + return op == LoadImmOp(DWord) +} + +// Class returns the class of operation. +func (op OpCode) Class() Class { + return Class(op & classMask) +} + +// Mode returns the mode for load and store operations. +func (op OpCode) Mode() Mode { + if op.Class().encoding() != loadOrStore { + return InvalidMode + } + return Mode(op & modeMask) +} + +// Size returns the size for load and store operations. +func (op OpCode) Size() Size { + if op.Class().encoding() != loadOrStore { + return InvalidSize + } + return Size(op & sizeMask) +} + +// Source returns the source for branch and ALU operations. +func (op OpCode) Source() Source { + if op.Class().encoding() != jumpOrALU || op.ALUOp() == Swap { + return InvalidSource + } + return Source(op & sourceMask) +} + +// ALUOp returns the ALUOp. +func (op OpCode) ALUOp() ALUOp { + if op.Class().encoding() != jumpOrALU { + return InvalidALUOp + } + return ALUOp(op & aluMask) +} + +// Endianness returns the Endianness for a byte swap instruction. +func (op OpCode) Endianness() Endianness { + if op.ALUOp() != Swap { + return InvalidEndian + } + return Endianness(op & endianMask) +} + +// JumpOp returns the JumpOp. +func (op OpCode) JumpOp() JumpOp { + if op.Class().encoding() != jumpOrALU { + return InvalidJumpOp + } + return JumpOp(op & jumpMask) +} + +// SetMode sets the mode on load and store operations. +// +// Returns InvalidOpCode if op is of the wrong class. +func (op OpCode) SetMode(mode Mode) OpCode { + if op.Class().encoding() != loadOrStore || !valid(OpCode(mode), modeMask) { + return InvalidOpCode + } + return (op & ^modeMask) | OpCode(mode) +} + +// SetSize sets the size on load and store operations. +// +// Returns InvalidOpCode if op is of the wrong class. +func (op OpCode) SetSize(size Size) OpCode { + if op.Class().encoding() != loadOrStore || !valid(OpCode(size), sizeMask) { + return InvalidOpCode + } + return (op & ^sizeMask) | OpCode(size) +} + +// SetSource sets the source on jump and ALU operations. +// +// Returns InvalidOpCode if op is of the wrong class. +func (op OpCode) SetSource(source Source) OpCode { + if op.Class().encoding() != jumpOrALU || !valid(OpCode(source), sourceMask) { + return InvalidOpCode + } + return (op & ^sourceMask) | OpCode(source) +} + +// SetALUOp sets the ALUOp on ALU operations. +// +// Returns InvalidOpCode if op is of the wrong class. +func (op OpCode) SetALUOp(alu ALUOp) OpCode { + class := op.Class() + if (class != ALUClass && class != ALU64Class) || !valid(OpCode(alu), aluMask) { + return InvalidOpCode + } + return (op & ^aluMask) | OpCode(alu) +} + +// SetJumpOp sets the JumpOp on jump operations. +// +// Returns InvalidOpCode if op is of the wrong class. +func (op OpCode) SetJumpOp(jump JumpOp) OpCode { + if op.Class() != JumpClass || !valid(OpCode(jump), jumpMask) { + return InvalidOpCode + } + return (op & ^jumpMask) | OpCode(jump) +} + +func (op OpCode) String() string { + var f strings.Builder + + switch class := op.Class(); class { + case LdClass, LdXClass, StClass, StXClass: + f.WriteString(strings.TrimSuffix(class.String(), "Class")) + + mode := op.Mode() + f.WriteString(strings.TrimSuffix(mode.String(), "Mode")) + + switch op.Size() { + case DWord: + f.WriteString("DW") + case Word: + f.WriteString("W") + case Half: + f.WriteString("H") + case Byte: + f.WriteString("B") + } + + case ALU64Class, ALUClass: + f.WriteString(op.ALUOp().String()) + + if op.ALUOp() == Swap { + // Width for Endian is controlled by Constant + f.WriteString(op.Endianness().String()) + } else { + if class == ALUClass { + f.WriteString("32") + } + + f.WriteString(strings.TrimSuffix(op.Source().String(), "Source")) + } + + case JumpClass: + f.WriteString(op.JumpOp().String()) + if jop := op.JumpOp(); jop != Exit && jop != Call { + f.WriteString(strings.TrimSuffix(op.Source().String(), "Source")) + } + + default: + fmt.Fprintf(&f, "OpCode(%#x)", uint8(op)) + } + + return f.String() +} + +// valid returns true if all bits in value are covered by mask. +func valid(value, mask OpCode) bool { + return value & ^mask == 0 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/opcode_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/opcode_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/opcode_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/opcode_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +// Code generated by "stringer -output opcode_string.go -type=Class"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[LdClass-0] + _ = x[LdXClass-1] + _ = x[StClass-2] + _ = x[StXClass-3] + _ = x[ALUClass-4] + _ = x[JumpClass-5] + _ = x[ALU64Class-7] +} + +const ( + _Class_name_0 = "LdClassLdXClassStClassStXClassALUClassJumpClass" + _Class_name_1 = "ALU64Class" +) + +var ( + _Class_index_0 = [...]uint8{0, 7, 15, 22, 30, 38, 47} +) + +func (i Class) String() string { + switch { + case 0 <= i && i <= 5: + return _Class_name_0[_Class_index_0[i]:_Class_index_0[i+1]] + case i == 7: + return _Class_name_1 + default: + return "Class(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/register.go containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/register.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/asm/register.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/asm/register.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,49 @@ +package asm + +import ( + "fmt" +) + +// Register is the source or destination of most operations. +type Register uint8 + +// R0 contains return values. +const R0 Register = 0 + +// Registers for function arguments. +const ( + R1 Register = R0 + 1 + iota + R2 + R3 + R4 + R5 +) + +// Callee saved registers preserved by function calls. +const ( + R6 Register = R5 + 1 + iota + R7 + R8 + R9 +) + +// Read-only frame pointer to access stack. +const ( + R10 Register = R9 + 1 + RFP = R10 +) + +// Pseudo registers used by 64bit loads and jumps +const ( + PseudoMapFD = R1 // BPF_PSEUDO_MAP_FD + PseudoMapValue = R2 // BPF_PSEUDO_MAP_VALUE + PseudoCall = R1 // BPF_PSEUDO_CALL +) + +func (r Register) String() string { + v := uint8(r) + if v == 10 { + return "rfp" + } + return fmt.Sprintf("r%d", v) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/.clang-format containerd-1.5.9/vendor/github.com/cilium/ebpf/.clang-format --- containerd-1.2.6/vendor/github.com/cilium/ebpf/.clang-format 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/.clang-format 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: true +AlignEscapedNewlines: DontAlign +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortFunctionsOnASingleLine: false +BreakBeforeBraces: Attach +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +TabWidth: 4 +UseTab: ForContinuationAndIndentation +ColumnLimit: 1000 +... diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/CODE_OF_CONDUCT.md containerd-1.5.9/vendor/github.com/cilium/ebpf/CODE_OF_CONDUCT.md --- containerd-1.2.6/vendor/github.com/cilium/ebpf/CODE_OF_CONDUCT.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/CODE_OF_CONDUCT.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at nathanjsweet at gmail dot com or i at lmb dot io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/collection.go containerd-1.5.9/vendor/github.com/cilium/ebpf/collection.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/collection.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/collection.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,616 @@ +package ebpf + +import ( + "errors" + "fmt" + "io" + "math" + "reflect" + "strings" + + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" +) + +// CollectionOptions control loading a collection into the kernel. +// +// Maps and Programs are passed to NewMapWithOptions and NewProgramsWithOptions. +type CollectionOptions struct { + Maps MapOptions + Programs ProgramOptions +} + +// CollectionSpec describes a collection. +type CollectionSpec struct { + Maps map[string]*MapSpec + Programs map[string]*ProgramSpec +} + +// Copy returns a recursive copy of the spec. +func (cs *CollectionSpec) Copy() *CollectionSpec { + if cs == nil { + return nil + } + + cpy := CollectionSpec{ + Maps: make(map[string]*MapSpec, len(cs.Maps)), + Programs: make(map[string]*ProgramSpec, len(cs.Programs)), + } + + for name, spec := range cs.Maps { + cpy.Maps[name] = spec.Copy() + } + + for name, spec := range cs.Programs { + cpy.Programs[name] = spec.Copy() + } + + return &cpy +} + +// RewriteMaps replaces all references to specific maps. +// +// Use this function to use pre-existing maps instead of creating new ones +// when calling NewCollection. Any named maps are removed from CollectionSpec.Maps. +// +// Returns an error if a named map isn't used in at least one program. +func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error { + for symbol, m := range maps { + // have we seen a program that uses this symbol / map + seen := false + fd := m.FD() + for progName, progSpec := range cs.Programs { + err := progSpec.Instructions.RewriteMapPtr(symbol, fd) + + switch { + case err == nil: + seen = true + + case asm.IsUnreferencedSymbol(err): + // Not all programs need to use the map + + default: + return fmt.Errorf("program %s: %w", progName, err) + } + } + + if !seen { + return fmt.Errorf("map %s not referenced by any programs", symbol) + } + + // Prevent NewCollection from creating rewritten maps + delete(cs.Maps, symbol) + } + + return nil +} + +// RewriteConstants replaces the value of multiple constants. +// +// The constant must be defined like so in the C program: +// +// volatile const type foobar; +// volatile const type foobar = default; +// +// Replacement values must be of the same length as the C sizeof(type). +// If necessary, they are marshalled according to the same rules as +// map values. +// +// From Linux 5.5 the verifier will use constants to eliminate dead code. +// +// Returns an error if a constant doesn't exist. +func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error { + rodata := cs.Maps[".rodata"] + if rodata == nil { + return errors.New("missing .rodata section") + } + + if rodata.BTF == nil { + return errors.New(".rodata section has no BTF") + } + + if n := len(rodata.Contents); n != 1 { + return fmt.Errorf("expected one key in .rodata, found %d", n) + } + + kv := rodata.Contents[0] + value, ok := kv.Value.([]byte) + if !ok { + return fmt.Errorf("first value in .rodata is %T not []byte", kv.Value) + } + + buf := make([]byte, len(value)) + copy(buf, value) + + err := patchValue(buf, btf.MapValue(rodata.BTF), consts) + if err != nil { + return err + } + + rodata.Contents[0] = MapKV{kv.Key, buf} + return nil +} + +// Assign the contents of a CollectionSpec to a struct. +// +// This function is a short-cut to manually checking the presence +// of maps and programs in a collection spec. Consider using bpf2go if this +// sounds useful. +// +// The argument to must be a pointer to a struct. A field of the +// struct is updated with values from Programs or Maps if it +// has an `ebpf` tag and its type is *ProgramSpec or *MapSpec. +// The tag gives the name of the program or map as found in +// the CollectionSpec. +// +// struct { +// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"` +// Bar *ebpf.MapSpec `ebpf:"bar_map"` +// Ignored int +// } +// +// Returns an error if any of the fields can't be found, or +// if the same map or program is assigned multiple times. +func (cs *CollectionSpec) Assign(to interface{}) error { + valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { + switch typ { + case reflect.TypeOf((*ProgramSpec)(nil)): + p := cs.Programs[name] + if p == nil { + return reflect.Value{}, fmt.Errorf("missing program %q", name) + } + return reflect.ValueOf(p), nil + case reflect.TypeOf((*MapSpec)(nil)): + m := cs.Maps[name] + if m == nil { + return reflect.Value{}, fmt.Errorf("missing map %q", name) + } + return reflect.ValueOf(m), nil + default: + return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) + } + } + + return assignValues(to, valueOf) +} + +// LoadAndAssign maps and programs into the kernel and assign them to a struct. +// +// This function is a short-cut to manually checking the presence +// of maps and programs in a collection spec. Consider using bpf2go if this +// sounds useful. +// +// The argument to must be a pointer to a struct. A field of the +// struct is updated with values from Programs or Maps if it +// has an `ebpf` tag and its type is *Program or *Map. +// The tag gives the name of the program or map as found in +// the CollectionSpec. +// +// struct { +// Foo *ebpf.Program `ebpf:"xdp_foo"` +// Bar *ebpf.Map `ebpf:"bar_map"` +// Ignored int +// } +// +// opts may be nil. +// +// Returns an error if any of the fields can't be found, or +// if the same map or program is assigned multiple times. +func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions) error { + if opts == nil { + opts = &CollectionOptions{} + } + + loadMap, loadProgram, done, cleanup := lazyLoadCollection(cs, opts) + defer cleanup() + + valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { + switch typ { + case reflect.TypeOf((*Program)(nil)): + p, err := loadProgram(name) + if err != nil { + return reflect.Value{}, err + } + return reflect.ValueOf(p), nil + case reflect.TypeOf((*Map)(nil)): + m, err := loadMap(name) + if err != nil { + return reflect.Value{}, err + } + return reflect.ValueOf(m), nil + default: + return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) + } + } + + if err := assignValues(to, valueOf); err != nil { + return err + } + + done() + return nil +} + +// Collection is a collection of Programs and Maps associated +// with their symbols +type Collection struct { + Programs map[string]*Program + Maps map[string]*Map +} + +// NewCollection creates a Collection from a specification. +func NewCollection(spec *CollectionSpec) (*Collection, error) { + return NewCollectionWithOptions(spec, CollectionOptions{}) +} + +// NewCollectionWithOptions creates a Collection from a specification. +func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) { + loadMap, loadProgram, done, cleanup := lazyLoadCollection(spec, &opts) + defer cleanup() + + for mapName := range spec.Maps { + _, err := loadMap(mapName) + if err != nil { + return nil, err + } + } + + for progName := range spec.Programs { + _, err := loadProgram(progName) + if err != nil { + return nil, err + } + } + + maps, progs := done() + return &Collection{ + progs, + maps, + }, nil +} + +type handleCache struct { + btfHandles map[*btf.Spec]*btf.Handle + btfSpecs map[io.ReaderAt]*btf.Spec +} + +func newHandleCache() *handleCache { + return &handleCache{ + btfHandles: make(map[*btf.Spec]*btf.Handle), + btfSpecs: make(map[io.ReaderAt]*btf.Spec), + } +} + +func (hc handleCache) btfHandle(spec *btf.Spec) (*btf.Handle, error) { + if hc.btfHandles[spec] != nil { + return hc.btfHandles[spec], nil + } + + handle, err := btf.NewHandle(spec) + if err != nil { + return nil, err + } + + hc.btfHandles[spec] = handle + return handle, nil +} + +func (hc handleCache) btfSpec(rd io.ReaderAt) (*btf.Spec, error) { + if hc.btfSpecs[rd] != nil { + return hc.btfSpecs[rd], nil + } + + spec, err := btf.LoadSpecFromReader(rd) + if err != nil { + return nil, err + } + + hc.btfSpecs[rd] = spec + return spec, nil +} + +func (hc handleCache) close() { + for _, handle := range hc.btfHandles { + handle.Close() + } + hc.btfHandles = nil + hc.btfSpecs = nil +} + +func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) ( + loadMap func(string) (*Map, error), + loadProgram func(string) (*Program, error), + done func() (map[string]*Map, map[string]*Program), + cleanup func(), +) { + var ( + maps = make(map[string]*Map) + progs = make(map[string]*Program) + handles = newHandleCache() + skipMapsAndProgs = false + ) + + cleanup = func() { + handles.close() + + if skipMapsAndProgs { + return + } + + for _, m := range maps { + m.Close() + } + + for _, p := range progs { + p.Close() + } + } + + done = func() (map[string]*Map, map[string]*Program) { + skipMapsAndProgs = true + return maps, progs + } + + loadMap = func(mapName string) (*Map, error) { + if m := maps[mapName]; m != nil { + return m, nil + } + + mapSpec := coll.Maps[mapName] + if mapSpec == nil { + return nil, fmt.Errorf("missing map %s", mapName) + } + + m, err := newMapWithOptions(mapSpec, opts.Maps, handles) + if err != nil { + return nil, fmt.Errorf("map %s: %w", mapName, err) + } + + maps[mapName] = m + return m, nil + } + + loadProgram = func(progName string) (*Program, error) { + if prog := progs[progName]; prog != nil { + return prog, nil + } + + progSpec := coll.Programs[progName] + if progSpec == nil { + return nil, fmt.Errorf("unknown program %s", progName) + } + + progSpec = progSpec.Copy() + + // Rewrite any reference to a valid map. + for i := range progSpec.Instructions { + ins := &progSpec.Instructions[i] + + if !ins.IsLoadFromMap() || ins.Reference == "" { + continue + } + + if uint32(ins.Constant) != math.MaxUint32 { + // Don't overwrite maps already rewritten, users can + // rewrite programs in the spec themselves + continue + } + + m, err := loadMap(ins.Reference) + if err != nil { + return nil, fmt.Errorf("program %s: %w", progName, err) + } + + fd := m.FD() + if fd < 0 { + return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd) + } + if err := ins.RewriteMapPtr(m.FD()); err != nil { + return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err) + } + } + + prog, err := newProgramWithOptions(progSpec, opts.Programs, handles) + if err != nil { + return nil, fmt.Errorf("program %s: %w", progName, err) + } + + progs[progName] = prog + return prog, nil + } + + return +} + +// LoadCollection parses an object file and converts it to a collection. +func LoadCollection(file string) (*Collection, error) { + spec, err := LoadCollectionSpec(file) + if err != nil { + return nil, err + } + return NewCollection(spec) +} + +// Close frees all maps and programs associated with the collection. +// +// The collection mustn't be used afterwards. +func (coll *Collection) Close() { + for _, prog := range coll.Programs { + prog.Close() + } + for _, m := range coll.Maps { + m.Close() + } +} + +// DetachMap removes the named map from the Collection. +// +// This means that a later call to Close() will not affect this map. +// +// Returns nil if no map of that name exists. +func (coll *Collection) DetachMap(name string) *Map { + m := coll.Maps[name] + delete(coll.Maps, name) + return m +} + +// DetachProgram removes the named program from the Collection. +// +// This means that a later call to Close() will not affect this program. +// +// Returns nil if no program of that name exists. +func (coll *Collection) DetachProgram(name string) *Program { + p := coll.Programs[name] + delete(coll.Programs, name) + return p +} + +// Assign the contents of a collection to a struct. +// +// Deprecated: use CollectionSpec.Assign instead. It provides the same +// functionality but creates only the maps and programs requested. +func (coll *Collection) Assign(to interface{}) error { + assignedMaps := make(map[string]struct{}) + assignedPrograms := make(map[string]struct{}) + valueOf := func(typ reflect.Type, name string) (reflect.Value, error) { + switch typ { + case reflect.TypeOf((*Program)(nil)): + p := coll.Programs[name] + if p == nil { + return reflect.Value{}, fmt.Errorf("missing program %q", name) + } + assignedPrograms[name] = struct{}{} + return reflect.ValueOf(p), nil + case reflect.TypeOf((*Map)(nil)): + m := coll.Maps[name] + if m == nil { + return reflect.Value{}, fmt.Errorf("missing map %q", name) + } + assignedMaps[name] = struct{}{} + return reflect.ValueOf(m), nil + default: + return reflect.Value{}, fmt.Errorf("unsupported type %s", typ) + } + } + + if err := assignValues(to, valueOf); err != nil { + return err + } + + for name := range assignedPrograms { + coll.DetachProgram(name) + } + + for name := range assignedMaps { + coll.DetachMap(name) + } + + return nil +} + +func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Value, error)) error { + type structField struct { + reflect.StructField + value reflect.Value + } + + var ( + fields []structField + visitedTypes = make(map[reflect.Type]bool) + flattenStruct func(reflect.Value) error + ) + + flattenStruct = func(structVal reflect.Value) error { + structType := structVal.Type() + if structType.Kind() != reflect.Struct { + return fmt.Errorf("%s is not a struct", structType) + } + + if visitedTypes[structType] { + return fmt.Errorf("recursion on type %s", structType) + } + + for i := 0; i < structType.NumField(); i++ { + field := structField{structType.Field(i), structVal.Field(i)} + + name := field.Tag.Get("ebpf") + if name != "" { + fields = append(fields, field) + continue + } + + var err error + switch field.Type.Kind() { + case reflect.Ptr: + if field.Type.Elem().Kind() != reflect.Struct { + continue + } + + if field.value.IsNil() { + return fmt.Errorf("nil pointer to %s", structType) + } + + err = flattenStruct(field.value.Elem()) + + case reflect.Struct: + err = flattenStruct(field.value) + + default: + continue + } + + if err != nil { + return fmt.Errorf("field %s: %w", field.Name, err) + } + } + + return nil + } + + toValue := reflect.ValueOf(to) + if toValue.Type().Kind() != reflect.Ptr { + return fmt.Errorf("%T is not a pointer to struct", to) + } + + if toValue.IsNil() { + return fmt.Errorf("nil pointer to %T", to) + } + + if err := flattenStruct(toValue.Elem()); err != nil { + return err + } + + type elem struct { + // Either *Map or *Program + typ reflect.Type + name string + } + + assignedTo := make(map[elem]string) + for _, field := range fields { + name := field.Tag.Get("ebpf") + if strings.Contains(name, ",") { + return fmt.Errorf("field %s: ebpf tag contains a comma", field.Name) + } + + e := elem{field.Type, name} + if assignedField := assignedTo[e]; assignedField != "" { + return fmt.Errorf("field %s: %q was already assigned to %s", field.Name, name, assignedField) + } + + value, err := valueOf(field.Type, name) + if err != nil { + return fmt.Errorf("field %s: %w", field.Name, err) + } + + if !field.value.CanSet() { + return fmt.Errorf("field %s: can't set value", field.Name) + } + + field.value.Set(value) + assignedTo[e] = field.Name + } + + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/cilium/ebpf/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/cilium/ebpf/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +# How to contribute + +Development is on [GitHub](https://github.com/cilium/ebpf) and contributions in +the form of pull requests and issues reporting bugs or suggesting new features +are welcome. Please take a look at [the architecture](ARCHITECTURE.md) to get +a better understanding for the high-level goals. + +New features must be accompanied by tests. Before starting work on any large +feature, please [join](https://cilium.herokuapp.com/) the +[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack to +discuss the design first. + +When submitting pull requests, consider writing details about what problem you +are solving and why the proposed approach solves that problem in commit messages +and/or pull request description to help future library users and maintainers to +reason about the proposed changes. + +## Running the tests + +Many of the tests require privileges to set resource limits and load eBPF code. +The easiest way to obtain these is to run the tests with `sudo`. + +To test the current package with your local kernel you can simply run: +``` +go test -exec sudo ./... +``` + +To test the current package with a different kernel version you can use the [run-tests.sh](run-tests.sh) script. +It requires [virtme](https://github.com/amluto/virtme) and qemu to be installed. + +Examples: + +```bash +# Run all tests on a 5.4 kernel +./run-tests.sh 5.4 + +# Run a subset of tests: +./run-tests.sh 5.4 go test ./link +``` + diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/doc.go containerd-1.5.9/vendor/github.com/cilium/ebpf/doc.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +// Package ebpf is a toolkit for working with eBPF programs. +// +// eBPF programs are small snippets of code which are executed directly +// in a VM in the Linux kernel, which makes them very fast and flexible. +// Many Linux subsystems now accept eBPF programs. This makes it possible +// to implement highly application specific logic inside the kernel, +// without having to modify the actual kernel itself. +// +// This package is designed for long-running processes which +// want to use eBPF to implement part of their application logic. It has no +// run-time dependencies outside of the library and the Linux kernel itself. +// eBPF code should be compiled ahead of time using clang, and shipped with +// your application as any other resource. +// +// Use the link subpackage to attach a loaded program to a hook in the kernel. +package ebpf diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go containerd-1.5.9/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +// +build gofuzz + +// Use with https://github.com/dvyukov/go-fuzz + +package ebpf + +import "bytes" + +func FuzzLoadCollectionSpec(data []byte) int { + spec, err := LoadCollectionSpecFromReader(bytes.NewReader(data)) + if err != nil { + if spec != nil { + panic("spec is not nil") + } + return 0 + } + if spec == nil { + panic("spec is nil") + } + return 1 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/elf_reader.go containerd-1.5.9/vendor/github.com/cilium/ebpf/elf_reader.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/elf_reader.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/elf_reader.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,953 @@ +package ebpf + +import ( + "bufio" + "bytes" + "debug/elf" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "os" + "strings" + + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" + "github.com/cilium/ebpf/internal/unix" +) + +// elfCode is a convenience to reduce the amount of arguments that have to +// be passed around explicitly. You should treat it's contents as immutable. +type elfCode struct { + *internal.SafeELFFile + sections map[elf.SectionIndex]*elfSection + license string + version uint32 + btf *btf.Spec +} + +// LoadCollectionSpec parses an ELF file into a CollectionSpec. +func LoadCollectionSpec(file string) (*CollectionSpec, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + defer f.Close() + + spec, err := LoadCollectionSpecFromReader(f) + if err != nil { + return nil, fmt.Errorf("file %s: %w", file, err) + } + return spec, nil +} + +// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec. +func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { + f, err := internal.NewSafeELFFile(rd) + if err != nil { + return nil, err + } + defer f.Close() + + var ( + licenseSection *elf.Section + versionSection *elf.Section + sections = make(map[elf.SectionIndex]*elfSection) + relSections = make(map[elf.SectionIndex]*elf.Section) + ) + + // This is the target of relocations generated by inline assembly. + sections[elf.SHN_UNDEF] = newElfSection(new(elf.Section), undefSection) + + // Collect all the sections we're interested in. This includes relocations + // which we parse later. + for i, sec := range f.Sections { + idx := elf.SectionIndex(i) + + switch { + case strings.HasPrefix(sec.Name, "license"): + licenseSection = sec + case strings.HasPrefix(sec.Name, "version"): + versionSection = sec + case strings.HasPrefix(sec.Name, "maps"): + sections[idx] = newElfSection(sec, mapSection) + case sec.Name == ".maps": + sections[idx] = newElfSection(sec, btfMapSection) + case sec.Name == ".bss" || sec.Name == ".data" || strings.HasPrefix(sec.Name, ".rodata"): + sections[idx] = newElfSection(sec, dataSection) + case sec.Type == elf.SHT_REL: + // Store relocations under the section index of the target + relSections[elf.SectionIndex(sec.Info)] = sec + case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0: + sections[idx] = newElfSection(sec, programSection) + } + } + + license, err := loadLicense(licenseSection) + if err != nil { + return nil, fmt.Errorf("load license: %w", err) + } + + version, err := loadVersion(versionSection, f.ByteOrder) + if err != nil { + return nil, fmt.Errorf("load version: %w", err) + } + + btfSpec, err := btf.LoadSpecFromReader(rd) + if err != nil && !errors.Is(err, btf.ErrNotFound) { + return nil, fmt.Errorf("load BTF: %w", err) + } + + // Assign symbols to all the sections we're interested in. + symbols, err := f.Symbols() + if err != nil { + return nil, fmt.Errorf("load symbols: %v", err) + } + + for _, symbol := range symbols { + idx := symbol.Section + symType := elf.ST_TYPE(symbol.Info) + + section := sections[idx] + if section == nil { + continue + } + + // Older versions of LLVM don't tag symbols correctly, so keep + // all NOTYPE ones. + keep := symType == elf.STT_NOTYPE + switch section.kind { + case mapSection, btfMapSection, dataSection: + keep = keep || symType == elf.STT_OBJECT + case programSection: + keep = keep || symType == elf.STT_FUNC + } + if !keep || symbol.Name == "" { + continue + } + + section.symbols[symbol.Value] = symbol + } + + ec := &elfCode{ + SafeELFFile: f, + sections: sections, + license: license, + version: version, + btf: btfSpec, + } + + // Go through relocation sections, and parse the ones for sections we're + // interested in. Make sure that relocations point at valid sections. + for idx, relSection := range relSections { + section := sections[idx] + if section == nil { + continue + } + + rels, err := ec.loadRelocations(relSection, symbols) + if err != nil { + return nil, fmt.Errorf("relocation for section %q: %w", section.Name, err) + } + + for _, rel := range rels { + target := sections[rel.Section] + if target == nil { + return nil, fmt.Errorf("section %q: reference to %q in section %s: %w", section.Name, rel.Name, rel.Section, ErrNotSupported) + } + + if target.Flags&elf.SHF_STRINGS > 0 { + return nil, fmt.Errorf("section %q: string is not stack allocated: %w", section.Name, ErrNotSupported) + } + + target.references++ + } + + section.relocations = rels + } + + // Collect all the various ways to define maps. + maps := make(map[string]*MapSpec) + if err := ec.loadMaps(maps); err != nil { + return nil, fmt.Errorf("load maps: %w", err) + } + + if err := ec.loadBTFMaps(maps); err != nil { + return nil, fmt.Errorf("load BTF maps: %w", err) + } + + if err := ec.loadDataSections(maps); err != nil { + return nil, fmt.Errorf("load data sections: %w", err) + } + + // Finally, collect programs and link them. + progs, err := ec.loadPrograms() + if err != nil { + return nil, fmt.Errorf("load programs: %w", err) + } + + return &CollectionSpec{maps, progs}, nil +} + +func loadLicense(sec *elf.Section) (string, error) { + if sec == nil { + return "", nil + } + + data, err := sec.Data() + if err != nil { + return "", fmt.Errorf("section %s: %v", sec.Name, err) + } + return string(bytes.TrimRight(data, "\000")), nil +} + +func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) { + if sec == nil { + return 0, nil + } + + var version uint32 + if err := binary.Read(sec.Open(), bo, &version); err != nil { + return 0, fmt.Errorf("section %s: %v", sec.Name, err) + } + return version, nil +} + +type elfSectionKind int + +const ( + undefSection elfSectionKind = iota + mapSection + btfMapSection + programSection + dataSection +) + +type elfSection struct { + *elf.Section + kind elfSectionKind + // Offset from the start of the section to a symbol + symbols map[uint64]elf.Symbol + // Offset from the start of the section to a relocation, which points at + // a symbol in another section. + relocations map[uint64]elf.Symbol + // The number of relocations pointing at this section. + references int +} + +func newElfSection(section *elf.Section, kind elfSectionKind) *elfSection { + return &elfSection{ + section, + kind, + make(map[uint64]elf.Symbol), + make(map[uint64]elf.Symbol), + 0, + } +} + +func (ec *elfCode) loadPrograms() (map[string]*ProgramSpec, error) { + var ( + progs []*ProgramSpec + libs []*ProgramSpec + ) + + for _, sec := range ec.sections { + if sec.kind != programSection { + continue + } + + if len(sec.symbols) == 0 { + return nil, fmt.Errorf("section %v: missing symbols", sec.Name) + } + + funcSym, ok := sec.symbols[0] + if !ok { + return nil, fmt.Errorf("section %v: no label at start", sec.Name) + } + + insns, length, err := ec.loadInstructions(sec) + if err != nil { + return nil, fmt.Errorf("program %s: %w", funcSym.Name, err) + } + + progType, attachType, progFlags, attachTo := getProgType(sec.Name) + + spec := &ProgramSpec{ + Name: funcSym.Name, + Type: progType, + Flags: progFlags, + AttachType: attachType, + AttachTo: attachTo, + License: ec.license, + KernelVersion: ec.version, + Instructions: insns, + ByteOrder: ec.ByteOrder, + } + + if ec.btf != nil { + spec.BTF, err = ec.btf.Program(sec.Name, length) + if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) { + return nil, fmt.Errorf("program %s: %w", funcSym.Name, err) + } + } + + if spec.Type == UnspecifiedProgram { + // There is no single name we can use for "library" sections, + // since they may contain multiple functions. We'll decode the + // labels they contain later on, and then link sections that way. + libs = append(libs, spec) + } else { + progs = append(progs, spec) + } + } + + res := make(map[string]*ProgramSpec, len(progs)) + for _, prog := range progs { + err := link(prog, libs) + if err != nil { + return nil, fmt.Errorf("program %s: %w", prog.Name, err) + } + res[prog.Name] = prog + } + + return res, nil +} + +func (ec *elfCode) loadInstructions(section *elfSection) (asm.Instructions, uint64, error) { + var ( + r = bufio.NewReader(section.Open()) + insns asm.Instructions + offset uint64 + ) + for { + var ins asm.Instruction + n, err := ins.Unmarshal(r, ec.ByteOrder) + if err == io.EOF { + return insns, offset, nil + } + if err != nil { + return nil, 0, fmt.Errorf("offset %d: %w", offset, err) + } + + ins.Symbol = section.symbols[offset].Name + + if rel, ok := section.relocations[offset]; ok { + if err = ec.relocateInstruction(&ins, rel); err != nil { + return nil, 0, fmt.Errorf("offset %d: relocate instruction: %w", offset, err) + } + } + + insns = append(insns, ins) + offset += n + } +} + +func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) error { + var ( + typ = elf.ST_TYPE(rel.Info) + bind = elf.ST_BIND(rel.Info) + name = rel.Name + ) + + target := ec.sections[rel.Section] + + switch target.kind { + case mapSection, btfMapSection: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("possible erroneous static qualifier on map definition: found reference to %q", name) + } + + if typ != elf.STT_OBJECT && typ != elf.STT_NOTYPE { + // STT_NOTYPE is generated on clang < 8 which doesn't tag + // relocations appropriately. + return fmt.Errorf("map load: incorrect relocation type %v", typ) + } + + ins.Src = asm.PseudoMapFD + + // Mark the instruction as needing an update when creating the + // collection. + if err := ins.RewriteMapPtr(-1); err != nil { + return err + } + + case dataSection: + var offset uint32 + switch typ { + case elf.STT_SECTION: + if bind != elf.STB_LOCAL { + return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind) + } + + // This is really a reference to a static symbol, which clang doesn't + // emit a symbol table entry for. Instead it encodes the offset in + // the instruction itself. + offset = uint32(uint64(ins.Constant)) + + case elf.STT_OBJECT: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind) + } + + offset = uint32(rel.Value) + + default: + return fmt.Errorf("incorrect relocation type %v for direct map load", typ) + } + + // We rely on using the name of the data section as the reference. It + // would be nicer to keep the real name in case of an STT_OBJECT, but + // it's not clear how to encode that into Instruction. + name = target.Name + + // The kernel expects the offset in the second basic BPF instruction. + ins.Constant = int64(uint64(offset) << 32) + ins.Src = asm.PseudoMapValue + + // Mark the instruction as needing an update when creating the + // collection. + if err := ins.RewriteMapPtr(-1); err != nil { + return err + } + + case programSection: + if ins.OpCode.JumpOp() != asm.Call { + return fmt.Errorf("not a call instruction: %s", ins) + } + + if ins.Src != asm.PseudoCall { + return fmt.Errorf("call: %s: incorrect source register", name) + } + + switch typ { + case elf.STT_NOTYPE, elf.STT_FUNC: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + } + + case elf.STT_SECTION: + if bind != elf.STB_LOCAL { + return fmt.Errorf("call: %s: unsupported binding: %s", name, bind) + } + + // The function we want to call is in the indicated section, + // at the offset encoded in the instruction itself. Reverse + // the calculation to find the real function we're looking for. + // A value of -1 references the first instruction in the section. + offset := int64(int32(ins.Constant)+1) * asm.InstructionSize + if offset < 0 { + return fmt.Errorf("call: %s: invalid offset %d", name, offset) + } + + sym, ok := target.symbols[uint64(offset)] + if !ok { + return fmt.Errorf("call: %s: no symbol at offset %d", name, offset) + } + + ins.Constant = -1 + name = sym.Name + + default: + return fmt.Errorf("call: %s: invalid symbol type %s", name, typ) + } + + case undefSection: + if bind != elf.STB_GLOBAL { + return fmt.Errorf("asm relocation: %s: unsupported binding: %s", name, bind) + } + + if typ != elf.STT_NOTYPE { + return fmt.Errorf("asm relocation: %s: unsupported type %s", name, typ) + } + + // There is nothing to do here but set ins.Reference. + + default: + return fmt.Errorf("relocation to %q: %w", target.Name, ErrNotSupported) + } + + ins.Reference = name + return nil +} + +func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error { + for _, sec := range ec.sections { + if sec.kind != mapSection { + continue + } + + nSym := len(sec.symbols) + if nSym == 0 { + return fmt.Errorf("section %v: no symbols", sec.Name) + } + + if sec.Size%uint64(nSym) != 0 { + return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name) + } + + var ( + r = bufio.NewReader(sec.Open()) + size = sec.Size / uint64(nSym) + ) + for i, offset := 0, uint64(0); i < nSym; i, offset = i+1, offset+size { + mapSym, ok := sec.symbols[offset] + if !ok { + return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset) + } + + mapName := mapSym.Name + if maps[mapName] != nil { + return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym) + } + + lr := io.LimitReader(r, int64(size)) + + spec := MapSpec{ + Name: SanitizeName(mapName, -1), + } + switch { + case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil: + return fmt.Errorf("map %s: missing type", mapName) + case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil: + return fmt.Errorf("map %s: missing key size", mapName) + case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil: + return fmt.Errorf("map %s: missing value size", mapName) + case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil: + return fmt.Errorf("map %s: missing max entries", mapName) + case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil: + return fmt.Errorf("map %s: missing flags", mapName) + } + + if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil { + return fmt.Errorf("map %s: unknown and non-zero fields in definition", mapName) + } + + if err := spec.clampPerfEventArraySize(); err != nil { + return fmt.Errorf("map %s: %w", mapName, err) + } + + maps[mapName] = &spec + } + } + + return nil +} + +func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error { + for _, sec := range ec.sections { + if sec.kind != btfMapSection { + continue + } + + if ec.btf == nil { + return fmt.Errorf("missing BTF") + } + + _, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open())) + if err != nil { + return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported) + } + + var ds btf.Datasec + if err := ec.btf.FindType(sec.Name, &ds); err != nil { + return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err) + } + + for _, vs := range ds.Vars { + v, ok := vs.Type.(*btf.Var) + if !ok { + return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type) + } + name := string(v.Name) + + if maps[name] != nil { + return fmt.Errorf("section %v: map %s already exists", sec.Name, name) + } + + mapStruct, ok := v.Type.(*btf.Struct) + if !ok { + return fmt.Errorf("expected struct, got %s", v.Type) + } + + mapSpec, err := mapSpecFromBTF(name, mapStruct, false, ec.btf) + if err != nil { + return fmt.Errorf("map %v: %w", name, err) + } + + if err := mapSpec.clampPerfEventArraySize(); err != nil { + return fmt.Errorf("map %v: %w", name, err) + } + + maps[name] = mapSpec + } + } + + return nil +} + +// mapSpecFromBTF produces a MapSpec based on a btf.Struct def representing +// a BTF map definition. The name and spec arguments will be copied to the +// resulting MapSpec, and inner must be true on any resursive invocations. +func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*MapSpec, error) { + + var ( + key, value btf.Type + keySize, valueSize uint32 + mapType, flags, maxEntries uint32 + pinType PinType + innerMapSpec *MapSpec + err error + ) + + for i, member := range def.Members { + switch member.Name { + case "type": + mapType, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get type: %w", err) + } + + case "map_flags": + flags, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF map flags: %w", err) + } + + case "max_entries": + maxEntries, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF map max entries: %w", err) + } + + case "key": + if keySize != 0 { + return nil, errors.New("both key and key_size given") + } + + pk, ok := member.Type.(*btf.Pointer) + if !ok { + return nil, fmt.Errorf("key type is not a pointer: %T", member.Type) + } + + key = pk.Target + + size, err := btf.Sizeof(pk.Target) + if err != nil { + return nil, fmt.Errorf("can't get size of BTF key: %w", err) + } + + keySize = uint32(size) + + case "value": + if valueSize != 0 { + return nil, errors.New("both value and value_size given") + } + + vk, ok := member.Type.(*btf.Pointer) + if !ok { + return nil, fmt.Errorf("value type is not a pointer: %T", member.Type) + } + + value = vk.Target + + size, err := btf.Sizeof(vk.Target) + if err != nil { + return nil, fmt.Errorf("can't get size of BTF value: %w", err) + } + + valueSize = uint32(size) + + case "key_size": + // Key needs to be nil and keySize needs to be 0 for key_size to be + // considered a valid member. + if key != nil || keySize != 0 { + return nil, errors.New("both key and key_size given") + } + + keySize, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF key size: %w", err) + } + + case "value_size": + // Value needs to be nil and valueSize needs to be 0 for value_size to be + // considered a valid member. + if value != nil || valueSize != 0 { + return nil, errors.New("both value and value_size given") + } + + valueSize, err = uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get BTF value size: %w", err) + } + + case "pinning": + if inner { + return nil, errors.New("inner maps can't be pinned") + } + + pinning, err := uintFromBTF(member.Type) + if err != nil { + return nil, fmt.Errorf("can't get pinning: %w", err) + } + + pinType = PinType(pinning) + + case "values": + // The 'values' field in BTF map definitions is used for declaring map + // value types that are references to other BPF objects, like other maps + // or programs. It is always expected to be an array of pointers. + if i != len(def.Members)-1 { + return nil, errors.New("'values' must be the last member in a BTF map definition") + } + + if valueSize != 0 && valueSize != 4 { + return nil, errors.New("value_size must be 0 or 4") + } + valueSize = 4 + + valueType, err := resolveBTFArrayMacro(member.Type) + if err != nil { + return nil, fmt.Errorf("can't resolve type of member 'values': %w", err) + } + + switch t := valueType.(type) { + case *btf.Struct: + // The values member pointing to an array of structs means we're expecting + // a map-in-map declaration. + if MapType(mapType) != ArrayOfMaps && MapType(mapType) != HashOfMaps { + return nil, errors.New("outer map needs to be an array or a hash of maps") + } + if inner { + return nil, fmt.Errorf("nested inner maps are not supported") + } + + // This inner map spec is used as a map template, but it needs to be + // created as a traditional map before it can be used to do so. + // libbpf names the inner map template '.inner', but we + // opted for _inner to simplify validation logic. (dots only supported + // on kernels 5.2 and up) + // Pass the BTF spec from the parent object, since both parent and + // child must be created from the same BTF blob (on kernels that support BTF). + innerMapSpec, err = mapSpecFromBTF(name+"_inner", t, true, spec) + if err != nil { + return nil, fmt.Errorf("can't parse BTF map definition of inner map: %w", err) + } + + default: + return nil, fmt.Errorf("unsupported value type %q in 'values' field", t) + } + + default: + return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name) + } + } + + bm := btf.NewMap(spec, key, value) + + return &MapSpec{ + Name: SanitizeName(name, -1), + Type: MapType(mapType), + KeySize: keySize, + ValueSize: valueSize, + MaxEntries: maxEntries, + Flags: flags, + BTF: &bm, + Pinning: pinType, + InnerMap: innerMapSpec, + }, nil +} + +// uintFromBTF resolves the __uint macro, which is a pointer to a sized +// array, e.g. for int (*foo)[10], this function will return 10. +func uintFromBTF(typ btf.Type) (uint32, error) { + ptr, ok := typ.(*btf.Pointer) + if !ok { + return 0, fmt.Errorf("not a pointer: %v", typ) + } + + arr, ok := ptr.Target.(*btf.Array) + if !ok { + return 0, fmt.Errorf("not a pointer to array: %v", typ) + } + + return arr.Nelems, nil +} + +// resolveBTFArrayMacro resolves the __array macro, which declares an array +// of pointers to a given type. This function returns the target Type of +// the pointers in the array. +func resolveBTFArrayMacro(typ btf.Type) (btf.Type, error) { + arr, ok := typ.(*btf.Array) + if !ok { + return nil, fmt.Errorf("not an array: %v", typ) + } + + ptr, ok := arr.Type.(*btf.Pointer) + if !ok { + return nil, fmt.Errorf("not an array of pointers: %v", typ) + } + + return ptr.Target, nil +} + +func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error { + for _, sec := range ec.sections { + if sec.kind != dataSection { + continue + } + + if sec.references == 0 { + // Prune data sections which are not referenced by any + // instructions. + continue + } + + if ec.btf == nil { + return errors.New("data sections require BTF, make sure all consts are marked as static") + } + + btfMap, err := ec.btf.Datasec(sec.Name) + if err != nil { + return err + } + + data, err := sec.Data() + if err != nil { + return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err) + } + + if uint64(len(data)) > math.MaxUint32 { + return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name) + } + + mapSpec := &MapSpec{ + Name: SanitizeName(sec.Name, -1), + Type: Array, + KeySize: 4, + ValueSize: uint32(len(data)), + MaxEntries: 1, + Contents: []MapKV{{uint32(0), data}}, + BTF: btfMap, + } + + switch sec.Name { + case ".rodata": + mapSpec.Flags = unix.BPF_F_RDONLY_PROG + mapSpec.Freeze = true + case ".bss": + // The kernel already zero-initializes the map + mapSpec.Contents = nil + } + + maps[sec.Name] = mapSpec + } + return nil +} + +func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) { + types := map[string]struct { + progType ProgramType + attachType AttachType + progFlags uint32 + }{ + // From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c + "socket": {SocketFilter, AttachNone, 0}, + "seccomp": {SocketFilter, AttachNone, 0}, + "kprobe/": {Kprobe, AttachNone, 0}, + "uprobe/": {Kprobe, AttachNone, 0}, + "kretprobe/": {Kprobe, AttachNone, 0}, + "uretprobe/": {Kprobe, AttachNone, 0}, + "tracepoint/": {TracePoint, AttachNone, 0}, + "raw_tracepoint/": {RawTracepoint, AttachNone, 0}, + "raw_tp/": {RawTracepoint, AttachNone, 0}, + "tp_btf/": {Tracing, AttachTraceRawTp, 0}, + "xdp": {XDP, AttachNone, 0}, + "perf_event": {PerfEvent, AttachNone, 0}, + "lwt_in": {LWTIn, AttachNone, 0}, + "lwt_out": {LWTOut, AttachNone, 0}, + "lwt_xmit": {LWTXmit, AttachNone, 0}, + "lwt_seg6local": {LWTSeg6Local, AttachNone, 0}, + "sockops": {SockOps, AttachCGroupSockOps, 0}, + "sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser, 0}, + "sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser, 0}, + "sk_msg": {SkMsg, AttachSkSKBStreamVerdict, 0}, + "lirc_mode2": {LircMode2, AttachLircMode2, 0}, + "flow_dissector": {FlowDissector, AttachFlowDissector, 0}, + "iter/": {Tracing, AttachTraceIter, 0}, + "fentry/": {Tracing, AttachTraceFEntry, 0}, + "fmod_ret/": {Tracing, AttachModifyReturn, 0}, + "fexit/": {Tracing, AttachTraceFExit, 0}, + "fentry.s/": {Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE}, + "fmod_ret.s/": {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE}, + "fexit.s/": {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE}, + "sk_lookup/": {SkLookup, AttachSkLookup, 0}, + "lsm/": {LSM, AttachLSMMac, 0}, + "lsm.s/": {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE}, + + "cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress, 0}, + "cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress, 0}, + "cgroup/dev": {CGroupDevice, AttachCGroupDevice, 0}, + "cgroup/skb": {CGroupSKB, AttachNone, 0}, + "cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate, 0}, + "cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind, 0}, + "cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind, 0}, + "cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind, 0}, + "cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind, 0}, + "cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect, 0}, + "cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect, 0}, + "cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0}, + "cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0}, + "cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0}, + "cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0}, + "cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl, 0}, + "cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt, 0}, + "cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt, 0}, + "classifier": {SchedCLS, AttachNone, 0}, + "action": {SchedACT, AttachNone, 0}, + } + + for prefix, t := range types { + if !strings.HasPrefix(sectionName, prefix) { + continue + } + + if !strings.HasSuffix(prefix, "/") { + return t.progType, t.attachType, t.progFlags, "" + } + + return t.progType, t.attachType, t.progFlags, sectionName[len(prefix):] + } + + return UnspecifiedProgram, AttachNone, 0, "" +} + +func (ec *elfCode) loadRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) { + rels := make(map[uint64]elf.Symbol) + + if sec.Entsize < 16 { + return nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name) + } + + r := bufio.NewReader(sec.Open()) + for off := uint64(0); off < sec.Size; off += sec.Entsize { + ent := io.LimitReader(r, int64(sec.Entsize)) + + var rel elf.Rel64 + if binary.Read(ent, ec.ByteOrder, &rel) != nil { + return nil, fmt.Errorf("can't parse relocation at offset %v", off) + } + + symNo := int(elf.R_SYM64(rel.Info) - 1) + if symNo >= len(symbols) { + return nil, fmt.Errorf("offset %d: symbol %d doesn't exist", off, symNo) + } + + symbol := symbols[symNo] + rels[rel.Off] = symbol + } + + return rels, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/.gitignore containerd-1.5.9/vendor/github.com/cilium/ebpf/.gitignore --- containerd-1.2.6/vendor/github.com/cilium/ebpf/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,13 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.o + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/.golangci.yaml containerd-1.5.9/vendor/github.com/cilium/ebpf/.golangci.yaml --- containerd-1.2.6/vendor/github.com/cilium/ebpf/.golangci.yaml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/.golangci.yaml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +--- +issues: + exclude-rules: + # syscall param structs will have unused fields in Go code. + - path: syscall.*.go + linters: + - structcheck + +linters: + disable-all: true + enable: + - deadcode + - errcheck + - goimports + - gosimple + - govet + - ineffassign + - misspell + - staticcheck + - structcheck + - typecheck + - unused + - varcheck + + # Could be enabled later: + # - gocyclo + # - prealloc + # - maligned + # - gosec diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/go.mod containerd-1.5.9/vendor/github.com/cilium/ebpf/go.mod --- containerd-1.2.6/vendor/github.com/cilium/ebpf/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,9 @@ +module github.com/cilium/ebpf + +go 1.15 + +require ( + github.com/frankban/quicktest v1.11.3 + github.com/google/go-cmp v0.5.4 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c +) diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/go.sum containerd-1.5.9/vendor/github.com/cilium/ebpf/go.sum --- containerd-1.2.6/vendor/github.com/cilium/ebpf/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,13 @@ +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/info.go containerd-1.5.9/vendor/github.com/cilium/ebpf/info.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/info.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/info.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,239 @@ +package ebpf + +import ( + "bufio" + "encoding/hex" + "errors" + "fmt" + "io" + "os" + "strings" + "syscall" + "time" + + "github.com/cilium/ebpf/internal" +) + +// MapInfo describes a map. +type MapInfo struct { + Type MapType + id MapID + KeySize uint32 + ValueSize uint32 + MaxEntries uint32 + Flags uint32 + // Name as supplied by user space at load time. + Name string +} + +func newMapInfoFromFd(fd *internal.FD) (*MapInfo, error) { + info, err := bpfGetMapInfoByFD(fd) + if errors.Is(err, syscall.EINVAL) { + return newMapInfoFromProc(fd) + } + if err != nil { + return nil, err + } + + return &MapInfo{ + MapType(info.map_type), + MapID(info.id), + info.key_size, + info.value_size, + info.max_entries, + info.map_flags, + // name is available from 4.15. + internal.CString(info.name[:]), + }, nil +} + +func newMapInfoFromProc(fd *internal.FD) (*MapInfo, error) { + var mi MapInfo + err := scanFdInfo(fd, map[string]interface{}{ + "map_type": &mi.Type, + "key_size": &mi.KeySize, + "value_size": &mi.ValueSize, + "max_entries": &mi.MaxEntries, + "map_flags": &mi.Flags, + }) + if err != nil { + return nil, err + } + return &mi, nil +} + +// ID returns the map ID. +// +// Available from 4.13. +// +// The bool return value indicates whether this optional field is available. +func (mi *MapInfo) ID() (MapID, bool) { + return mi.id, mi.id > 0 +} + +// programStats holds statistics of a program. +type programStats struct { + // Total accumulated runtime of the program ins ns. + runtime time.Duration + // Total number of times the program was called. + runCount uint64 +} + +// ProgramInfo describes a program. +type ProgramInfo struct { + Type ProgramType + id ProgramID + // Truncated hash of the BPF bytecode. + Tag string + // Name as supplied by user space at load time. + Name string + + stats *programStats +} + +func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) { + info, err := bpfGetProgInfoByFD(fd) + if errors.Is(err, syscall.EINVAL) { + return newProgramInfoFromProc(fd) + } + if err != nil { + return nil, err + } + + return &ProgramInfo{ + Type: ProgramType(info.prog_type), + id: ProgramID(info.id), + // tag is available if the kernel supports BPF_PROG_GET_INFO_BY_FD. + Tag: hex.EncodeToString(info.tag[:]), + // name is available from 4.15. + Name: internal.CString(info.name[:]), + stats: &programStats{ + runtime: time.Duration(info.run_time_ns), + runCount: info.run_cnt, + }, + }, nil +} + +func newProgramInfoFromProc(fd *internal.FD) (*ProgramInfo, error) { + var info ProgramInfo + err := scanFdInfo(fd, map[string]interface{}{ + "prog_type": &info.Type, + "prog_tag": &info.Tag, + }) + if errors.Is(err, errMissingFields) { + return nil, &internal.UnsupportedFeatureError{ + Name: "reading program info from /proc/self/fdinfo", + MinimumVersion: internal.Version{4, 10, 0}, + } + } + if err != nil { + return nil, err + } + + return &info, nil +} + +// ID returns the program ID. +// +// Available from 4.13. +// +// The bool return value indicates whether this optional field is available. +func (pi *ProgramInfo) ID() (ProgramID, bool) { + return pi.id, pi.id > 0 +} + +// RunCount returns the total number of times the program was called. +// +// Can return 0 if the collection of statistics is not enabled. See EnableStats(). +// The bool return value indicates whether this optional field is available. +func (pi *ProgramInfo) RunCount() (uint64, bool) { + if pi.stats != nil { + return pi.stats.runCount, true + } + return 0, false +} + +// Runtime returns the total accumulated runtime of the program. +// +// Can return 0 if the collection of statistics is not enabled. See EnableStats(). +// The bool return value indicates whether this optional field is available. +func (pi *ProgramInfo) Runtime() (time.Duration, bool) { + if pi.stats != nil { + return pi.stats.runtime, true + } + return time.Duration(0), false +} + +func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error { + raw, err := fd.Value() + if err != nil { + return err + } + + fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", raw)) + if err != nil { + return err + } + defer fh.Close() + + if err := scanFdInfoReader(fh, fields); err != nil { + return fmt.Errorf("%s: %w", fh.Name(), err) + } + return nil +} + +var errMissingFields = errors.New("missing fields") + +func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error { + var ( + scanner = bufio.NewScanner(r) + scanned int + ) + + for scanner.Scan() { + parts := strings.SplitN(scanner.Text(), "\t", 2) + if len(parts) != 2 { + continue + } + + name := strings.TrimSuffix(parts[0], ":") + field, ok := fields[string(name)] + if !ok { + continue + } + + if n, err := fmt.Sscanln(parts[1], field); err != nil || n != 1 { + return fmt.Errorf("can't parse field %s: %v", name, err) + } + + scanned++ + } + + if err := scanner.Err(); err != nil { + return err + } + + if scanned != len(fields) { + return errMissingFields + } + + return nil +} + +// EnableStats starts the measuring of the runtime +// and run counts of eBPF programs. +// +// Collecting statistics can have an impact on the performance. +// +// Requires at least 5.8. +func EnableStats(which uint32) (io.Closer, error) { + attr := internal.BPFEnableStatsAttr{ + StatsType: which, + } + + fd, err := internal.BPFEnableStats(&attr) + if err != nil { + return nil, err + } + return fd, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,799 @@ +package btf + +import ( + "bytes" + "debug/elf" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "math" + "os" + "reflect" + "sync" + "unsafe" + + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/unix" +) + +const btfMagic = 0xeB9F + +// Errors returned by BTF functions. +var ( + ErrNotSupported = internal.ErrNotSupported + ErrNotFound = errors.New("not found") + ErrNoExtendedInfo = errors.New("no extended info") +) + +// Spec represents decoded BTF. +type Spec struct { + rawTypes []rawType + strings stringTable + types []Type + namedTypes map[string][]namedType + funcInfos map[string]extInfo + lineInfos map[string]extInfo + coreRelos map[string]coreRelos + byteOrder binary.ByteOrder +} + +type btfHeader struct { + Magic uint16 + Version uint8 + Flags uint8 + HdrLen uint32 + + TypeOff uint32 + TypeLen uint32 + StringOff uint32 + StringLen uint32 +} + +// LoadSpecFromReader reads BTF sections from an ELF. +// +// Returns ErrNotFound if the reader contains no BTF. +func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { + file, err := internal.NewSafeELFFile(rd) + if err != nil { + return nil, err + } + defer file.Close() + + btfSection, btfExtSection, sectionSizes, err := findBtfSections(file) + if err != nil { + return nil, err + } + + if btfSection == nil { + return nil, fmt.Errorf("btf: %w", ErrNotFound) + } + + symbols, err := file.Symbols() + if err != nil { + return nil, fmt.Errorf("can't read symbols: %v", err) + } + + variableOffsets := make(map[variable]uint32) + for _, symbol := range symbols { + if idx := symbol.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE { + // Ignore things like SHN_ABS + continue + } + + if int(symbol.Section) >= len(file.Sections) { + return nil, fmt.Errorf("symbol %s: invalid section %d", symbol.Name, symbol.Section) + } + + secName := file.Sections[symbol.Section].Name + if _, ok := sectionSizes[secName]; !ok { + continue + } + + if symbol.Value > math.MaxUint32 { + return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name) + } + + variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value) + } + + spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets) + if err != nil { + return nil, err + } + + if btfExtSection == nil { + return spec, nil + } + + spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) + if err != nil { + return nil, fmt.Errorf("can't read ext info: %w", err) + } + + return spec, nil +} + +func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, map[string]uint32, error) { + var ( + btfSection *elf.Section + btfExtSection *elf.Section + sectionSizes = make(map[string]uint32) + ) + + for _, sec := range file.Sections { + switch sec.Name { + case ".BTF": + btfSection = sec + case ".BTF.ext": + btfExtSection = sec + default: + if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS { + break + } + + if sec.Size > math.MaxUint32 { + return nil, nil, nil, fmt.Errorf("section %s exceeds maximum size", sec.Name) + } + + sectionSizes[sec.Name] = uint32(sec.Size) + } + } + return btfSection, btfExtSection, sectionSizes, nil +} + +func loadSpecFromVmlinux(rd io.ReaderAt) (*Spec, error) { + file, err := internal.NewSafeELFFile(rd) + if err != nil { + return nil, err + } + defer file.Close() + + btfSection, _, _, err := findBtfSections(file) + if err != nil { + return nil, fmt.Errorf(".BTF ELF section: %s", err) + } + if btfSection == nil { + return nil, fmt.Errorf("unable to find .BTF ELF section") + } + return loadNakedSpec(btfSection.Open(), file.ByteOrder, nil, nil) +} + +func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) { + rawTypes, rawStrings, err := parseBTF(btf, bo) + if err != nil { + return nil, err + } + + err = fixupDatasec(rawTypes, rawStrings, sectionSizes, variableOffsets) + if err != nil { + return nil, err + } + + types, typesByName, err := inflateRawTypes(rawTypes, rawStrings) + if err != nil { + return nil, err + } + + return &Spec{ + rawTypes: rawTypes, + namedTypes: typesByName, + types: types, + strings: rawStrings, + byteOrder: bo, + }, nil +} + +var kernelBTF struct { + sync.Mutex + *Spec +} + +// LoadKernelSpec returns the current kernel's BTF information. +// +// Requires a >= 5.5 kernel with CONFIG_DEBUG_INFO_BTF enabled. Returns +// ErrNotSupported if BTF is not enabled. +func LoadKernelSpec() (*Spec, error) { + kernelBTF.Lock() + defer kernelBTF.Unlock() + + if kernelBTF.Spec != nil { + return kernelBTF.Spec, nil + } + + var err error + kernelBTF.Spec, err = loadKernelSpec() + return kernelBTF.Spec, err +} + +func loadKernelSpec() (*Spec, error) { + release, err := unix.KernelRelease() + if err != nil { + return nil, fmt.Errorf("can't read kernel release number: %w", err) + } + + fh, err := os.Open("/sys/kernel/btf/vmlinux") + if err == nil { + defer fh.Close() + + return loadNakedSpec(fh, internal.NativeEndian, nil, nil) + } + + // use same list of locations as libbpf + // https://github.com/libbpf/libbpf/blob/9a3a42608dbe3731256a5682a125ac1e23bced8f/src/btf.c#L3114-L3122 + locations := []string{ + "/boot/vmlinux-%s", + "/lib/modules/%s/vmlinux-%[1]s", + "/lib/modules/%s/build/vmlinux", + "/usr/lib/modules/%s/kernel/vmlinux", + "/usr/lib/debug/boot/vmlinux-%s", + "/usr/lib/debug/boot/vmlinux-%s.debug", + "/usr/lib/debug/lib/modules/%s/vmlinux", + } + + for _, loc := range locations { + path := fmt.Sprintf(loc, release) + + fh, err := os.Open(path) + if err != nil { + continue + } + defer fh.Close() + + return loadSpecFromVmlinux(fh) + } + + return nil, fmt.Errorf("no BTF for kernel version %s: %w", release, internal.ErrNotSupported) +} + +func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) { + rawBTF, err := ioutil.ReadAll(btf) + if err != nil { + return nil, nil, fmt.Errorf("can't read BTF: %v", err) + } + + rd := bytes.NewReader(rawBTF) + + var header btfHeader + if err := binary.Read(rd, bo, &header); err != nil { + return nil, nil, fmt.Errorf("can't read header: %v", err) + } + + if header.Magic != btfMagic { + return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic) + } + + if header.Version != 1 { + return nil, nil, fmt.Errorf("unexpected version %v", header.Version) + } + + if header.Flags != 0 { + return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags) + } + + remainder := int64(header.HdrLen) - int64(binary.Size(&header)) + if remainder < 0 { + return nil, nil, errors.New("header is too short") + } + + if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil { + return nil, nil, fmt.Errorf("header padding: %v", err) + } + + if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil { + return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err) + } + + rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen))) + if err != nil { + return nil, nil, fmt.Errorf("can't read type names: %w", err) + } + + if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil { + return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err) + } + + rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo) + if err != nil { + return nil, nil, fmt.Errorf("can't read types: %w", err) + } + + return rawTypes, rawStrings, nil +} + +type variable struct { + section string + name string +} + +func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) error { + for i, rawType := range rawTypes { + if rawType.Kind() != kindDatasec { + continue + } + + name, err := rawStrings.Lookup(rawType.NameOff) + if err != nil { + return err + } + + if name == ".kconfig" || name == ".ksyms" { + return fmt.Errorf("reference to %s: %w", name, ErrNotSupported) + } + + if rawTypes[i].SizeType != 0 { + continue + } + + size, ok := sectionSizes[name] + if !ok { + return fmt.Errorf("data section %s: missing size", name) + } + + rawTypes[i].SizeType = size + + secinfos := rawType.data.([]btfVarSecinfo) + for j, secInfo := range secinfos { + id := int(secInfo.Type - 1) + if id >= len(rawTypes) { + return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j) + } + + varName, err := rawStrings.Lookup(rawTypes[id].NameOff) + if err != nil { + return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err) + } + + offset, ok := variableOffsets[variable{name, varName}] + if !ok { + return fmt.Errorf("data section %s: missing offset for variable %s", name, varName) + } + + secinfos[j].Offset = offset + } + } + + return nil +} + +type marshalOpts struct { + ByteOrder binary.ByteOrder + StripFuncLinkage bool +} + +func (s *Spec) marshal(opts marshalOpts) ([]byte, error) { + var ( + buf bytes.Buffer + header = new(btfHeader) + headerLen = binary.Size(header) + ) + + // Reserve space for the header. We have to write it last since + // we don't know the size of the type section yet. + _, _ = buf.Write(make([]byte, headerLen)) + + // Write type section, just after the header. + for _, raw := range s.rawTypes { + switch { + case opts.StripFuncLinkage && raw.Kind() == kindFunc: + raw.SetLinkage(StaticFunc) + } + + if err := raw.Marshal(&buf, opts.ByteOrder); err != nil { + return nil, fmt.Errorf("can't marshal BTF: %w", err) + } + } + + typeLen := uint32(buf.Len() - headerLen) + + // Write string section after type section. + _, _ = buf.Write(s.strings) + + // Fill out the header, and write it out. + header = &btfHeader{ + Magic: btfMagic, + Version: 1, + Flags: 0, + HdrLen: uint32(headerLen), + TypeOff: 0, + TypeLen: typeLen, + StringOff: typeLen, + StringLen: uint32(len(s.strings)), + } + + raw := buf.Bytes() + err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header) + if err != nil { + return nil, fmt.Errorf("can't write header: %v", err) + } + + return raw, nil +} + +type sliceWriter []byte + +func (sw sliceWriter) Write(p []byte) (int, error) { + if len(p) != len(sw) { + return 0, errors.New("size doesn't match") + } + + return copy(sw, p), nil +} + +// Program finds the BTF for a specific section. +// +// Length is the number of bytes in the raw BPF instruction stream. +// +// Returns an error which may wrap ErrNoExtendedInfo if the Spec doesn't +// contain extended BTF info. +func (s *Spec) Program(name string, length uint64) (*Program, error) { + if length == 0 { + return nil, errors.New("length musn't be zero") + } + + if s.funcInfos == nil && s.lineInfos == nil && s.coreRelos == nil { + return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo) + } + + funcInfos, funcOK := s.funcInfos[name] + lineInfos, lineOK := s.lineInfos[name] + relos, coreOK := s.coreRelos[name] + + if !funcOK && !lineOK && !coreOK { + return nil, fmt.Errorf("no extended BTF info for section %s", name) + } + + return &Program{s, length, funcInfos, lineInfos, relos}, nil +} + +// Datasec returns the BTF required to create maps which represent data sections. +func (s *Spec) Datasec(name string) (*Map, error) { + var datasec Datasec + if err := s.FindType(name, &datasec); err != nil { + return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err) + } + + m := NewMap(s, &Void{}, &datasec) + return &m, nil +} + +// FindType searches for a type with a specific name. +// +// hint determines the type of the returned Type. +// +// Returns an error wrapping ErrNotFound if no matching +// type exists in spec. +func (s *Spec) FindType(name string, typ Type) error { + var ( + wanted = reflect.TypeOf(typ) + candidate Type + ) + + for _, typ := range s.namedTypes[essentialName(name)] { + if reflect.TypeOf(typ) != wanted { + continue + } + + // Match against the full name, not just the essential one. + if typ.name() != name { + continue + } + + if candidate != nil { + return fmt.Errorf("type %s: multiple candidates for %T", name, typ) + } + + candidate = typ + } + + if candidate == nil { + return fmt.Errorf("type %s: %w", name, ErrNotFound) + } + + cpy, _ := copyType(candidate, nil) + value := reflect.Indirect(reflect.ValueOf(cpy)) + reflect.Indirect(reflect.ValueOf(typ)).Set(value) + return nil +} + +// Handle is a reference to BTF loaded into the kernel. +type Handle struct { + fd *internal.FD +} + +// NewHandle loads BTF into the kernel. +// +// Returns ErrNotSupported if BTF is not supported. +func NewHandle(spec *Spec) (*Handle, error) { + if err := haveBTF(); err != nil { + return nil, err + } + + if spec.byteOrder != internal.NativeEndian { + return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian) + } + + btf, err := spec.marshal(marshalOpts{ + ByteOrder: internal.NativeEndian, + StripFuncLinkage: haveFuncLinkage() != nil, + }) + if err != nil { + return nil, fmt.Errorf("can't marshal BTF: %w", err) + } + + if uint64(len(btf)) > math.MaxUint32 { + return nil, errors.New("BTF exceeds the maximum size") + } + + attr := &bpfLoadBTFAttr{ + btf: internal.NewSlicePointer(btf), + btfSize: uint32(len(btf)), + } + + fd, err := bpfLoadBTF(attr) + if err != nil { + logBuf := make([]byte, 64*1024) + attr.logBuf = internal.NewSlicePointer(logBuf) + attr.btfLogSize = uint32(len(logBuf)) + attr.btfLogLevel = 1 + _, logErr := bpfLoadBTF(attr) + return nil, internal.ErrorWithLog(err, logBuf, logErr) + } + + return &Handle{fd}, nil +} + +// Close destroys the handle. +// +// Subsequent calls to FD will return an invalid value. +func (h *Handle) Close() error { + return h.fd.Close() +} + +// FD returns the file descriptor for the handle. +func (h *Handle) FD() int { + value, err := h.fd.Value() + if err != nil { + return -1 + } + + return int(value) +} + +// Map is the BTF for a map. +type Map struct { + spec *Spec + key, value Type +} + +// NewMap returns a new Map containing the given values. +// The key and value arguments are initialized to Void if nil values are given. +func NewMap(spec *Spec, key Type, value Type) Map { + if key == nil { + key = &Void{} + } + if value == nil { + value = &Void{} + } + + return Map{ + spec: spec, + key: key, + value: value, + } +} + +// MapSpec should be a method on Map, but is a free function +// to hide it from users of the ebpf package. +func MapSpec(m *Map) *Spec { + return m.spec +} + +// MapKey should be a method on Map, but is a free function +// to hide it from users of the ebpf package. +func MapKey(m *Map) Type { + return m.key +} + +// MapValue should be a method on Map, but is a free function +// to hide it from users of the ebpf package. +func MapValue(m *Map) Type { + return m.value +} + +// Program is the BTF information for a stream of instructions. +type Program struct { + spec *Spec + length uint64 + funcInfos, lineInfos extInfo + coreRelos coreRelos +} + +// ProgramSpec returns the Spec needed for loading function and line infos into the kernel. +// +// This is a free function instead of a method to hide it from users +// of package ebpf. +func ProgramSpec(s *Program) *Spec { + return s.spec +} + +// ProgramAppend the information from other to the Program. +// +// This is a free function instead of a method to hide it from users +// of package ebpf. +func ProgramAppend(s, other *Program) error { + funcInfos, err := s.funcInfos.append(other.funcInfos, s.length) + if err != nil { + return fmt.Errorf("func infos: %w", err) + } + + lineInfos, err := s.lineInfos.append(other.lineInfos, s.length) + if err != nil { + return fmt.Errorf("line infos: %w", err) + } + + s.funcInfos = funcInfos + s.lineInfos = lineInfos + s.coreRelos = s.coreRelos.append(other.coreRelos, s.length) + s.length += other.length + return nil +} + +// ProgramFuncInfos returns the binary form of BTF function infos. +// +// This is a free function instead of a method to hide it from users +// of package ebpf. +func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) { + bytes, err = s.funcInfos.MarshalBinary() + if err != nil { + return 0, nil, err + } + + return s.funcInfos.recordSize, bytes, nil +} + +// ProgramLineInfos returns the binary form of BTF line infos. +// +// This is a free function instead of a method to hide it from users +// of package ebpf. +func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) { + bytes, err = s.lineInfos.MarshalBinary() + if err != nil { + return 0, nil, err + } + + return s.lineInfos.recordSize, bytes, nil +} + +// ProgramFixups returns the changes required to adjust the program to the target. +// +// This is a free function instead of a method to hide it from users +// of package ebpf. +func ProgramFixups(s *Program, target *Spec) (COREFixups, error) { + if len(s.coreRelos) == 0 { + return nil, nil + } + + if target == nil { + var err error + target, err = LoadKernelSpec() + if err != nil { + return nil, err + } + } + + return coreRelocate(s.spec, target, s.coreRelos) +} + +type bpfLoadBTFAttr struct { + btf internal.Pointer + logBuf internal.Pointer + btfSize uint32 + btfLogSize uint32 + btfLogLevel uint32 +} + +func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) { + fd, err := internal.BPF(internal.BPF_BTF_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + + return internal.NewFD(uint32(fd)), nil +} + +func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte { + const minHeaderLength = 24 + + typesLen := uint32(binary.Size(types)) + header := btfHeader{ + Magic: btfMagic, + Version: 1, + HdrLen: minHeaderLength, + TypeOff: 0, + TypeLen: typesLen, + StringOff: typesLen, + StringLen: uint32(len(strings)), + } + + buf := new(bytes.Buffer) + _ = binary.Write(buf, bo, &header) + _ = binary.Write(buf, bo, types) + buf.Write(strings) + + return buf.Bytes() +} + +var haveBTF = internal.FeatureTest("BTF", "5.1", func() error { + var ( + types struct { + Integer btfType + Var btfType + btfVar struct{ Linkage uint32 } + } + strings = []byte{0, 'a', 0} + ) + + // We use a BTF_KIND_VAR here, to make sure that + // the kernel understands BTF at least as well as we + // do. BTF_KIND_VAR was introduced ~5.1. + types.Integer.SetKind(kindPointer) + types.Var.NameOff = 1 + types.Var.SetKind(kindVar) + types.Var.SizeType = 1 + + btf := marshalBTF(&types, strings, internal.NativeEndian) + + fd, err := bpfLoadBTF(&bpfLoadBTFAttr{ + btf: internal.NewSlicePointer(btf), + btfSize: uint32(len(btf)), + }) + if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) { + // Treat both EINVAL and EPERM as not supported: loading the program + // might still succeed without BTF. + return internal.ErrNotSupported + } + if err != nil { + return err + } + + fd.Close() + return nil +}) + +var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() error { + if err := haveBTF(); err != nil { + return err + } + + var ( + types struct { + FuncProto btfType + Func btfType + } + strings = []byte{0, 'a', 0} + ) + + types.FuncProto.SetKind(kindFuncProto) + types.Func.SetKind(kindFunc) + types.Func.SizeType = 1 // aka FuncProto + types.Func.NameOff = 1 + types.Func.SetLinkage(GlobalFunc) + + btf := marshalBTF(&types, strings, internal.NativeEndian) + + fd, err := bpfLoadBTF(&bpfLoadBTFAttr{ + btf: internal.NewSlicePointer(btf), + btfSize: uint32(len(btf)), + }) + if errors.Is(err, unix.EINVAL) { + return internal.ErrNotSupported + } + if err != nil { + return err + } + + fd.Close() + return nil +}) diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,282 @@ +package btf + +import ( + "encoding/binary" + "fmt" + "io" +) + +//go:generate stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage + +// btfKind describes a Type. +type btfKind uint8 + +// Equivalents of the BTF_KIND_* constants. +const ( + kindUnknown btfKind = iota + kindInt + kindPointer + kindArray + kindStruct + kindUnion + kindEnum + kindForward + kindTypedef + kindVolatile + kindConst + kindRestrict + // Added ~4.20 + kindFunc + kindFuncProto + // Added ~5.1 + kindVar + kindDatasec +) + +// FuncLinkage describes BTF function linkage metadata. +type FuncLinkage int + +// Equivalent of enum btf_func_linkage. +const ( + StaticFunc FuncLinkage = iota // static + GlobalFunc // global + ExternFunc // extern +) + +// VarLinkage describes BTF variable linkage metadata. +type VarLinkage int + +const ( + StaticVar VarLinkage = iota // static + GlobalVar // global + ExternVar // extern +) + +const ( + btfTypeKindShift = 24 + btfTypeKindLen = 4 + btfTypeVlenShift = 0 + btfTypeVlenMask = 16 + btfTypeKindFlagShift = 31 + btfTypeKindFlagMask = 1 +) + +// btfType is equivalent to struct btf_type in Documentation/bpf/btf.rst. +type btfType struct { + NameOff uint32 + /* "info" bits arrangement + * bits 0-15: vlen (e.g. # of struct's members), linkage + * bits 16-23: unused + * bits 24-27: kind (e.g. int, ptr, array...etc) + * bits 28-30: unused + * bit 31: kind_flag, currently used by + * struct, union and fwd + */ + Info uint32 + /* "size" is used by INT, ENUM, STRUCT and UNION. + * "size" tells the size of the type it is describing. + * + * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + * FUNC and FUNC_PROTO. + * "type" is a type_id referring to another type. + */ + SizeType uint32 +} + +func (k btfKind) String() string { + switch k { + case kindUnknown: + return "Unknown" + case kindInt: + return "Integer" + case kindPointer: + return "Pointer" + case kindArray: + return "Array" + case kindStruct: + return "Struct" + case kindUnion: + return "Union" + case kindEnum: + return "Enumeration" + case kindForward: + return "Forward" + case kindTypedef: + return "Typedef" + case kindVolatile: + return "Volatile" + case kindConst: + return "Const" + case kindRestrict: + return "Restrict" + case kindFunc: + return "Function" + case kindFuncProto: + return "Function Proto" + case kindVar: + return "Variable" + case kindDatasec: + return "Section" + default: + return fmt.Sprintf("Unknown (%d)", k) + } +} + +func mask(len uint32) uint32 { + return (1 << len) - 1 +} + +func (bt *btfType) info(len, shift uint32) uint32 { + return (bt.Info >> shift) & mask(len) +} + +func (bt *btfType) setInfo(value, len, shift uint32) { + bt.Info &^= mask(len) << shift + bt.Info |= (value & mask(len)) << shift +} + +func (bt *btfType) Kind() btfKind { + return btfKind(bt.info(btfTypeKindLen, btfTypeKindShift)) +} + +func (bt *btfType) SetKind(kind btfKind) { + bt.setInfo(uint32(kind), btfTypeKindLen, btfTypeKindShift) +} + +func (bt *btfType) Vlen() int { + return int(bt.info(btfTypeVlenMask, btfTypeVlenShift)) +} + +func (bt *btfType) SetVlen(vlen int) { + bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift) +} + +func (bt *btfType) KindFlag() bool { + return bt.info(btfTypeKindFlagMask, btfTypeKindFlagShift) == 1 +} + +func (bt *btfType) Linkage() FuncLinkage { + return FuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift)) +} + +func (bt *btfType) SetLinkage(linkage FuncLinkage) { + bt.setInfo(uint32(linkage), btfTypeVlenMask, btfTypeVlenShift) +} + +func (bt *btfType) Type() TypeID { + // TODO: Panic here if wrong kind? + return TypeID(bt.SizeType) +} + +func (bt *btfType) Size() uint32 { + // TODO: Panic here if wrong kind? + return bt.SizeType +} + +type rawType struct { + btfType + data interface{} +} + +func (rt *rawType) Marshal(w io.Writer, bo binary.ByteOrder) error { + if err := binary.Write(w, bo, &rt.btfType); err != nil { + return err + } + + if rt.data == nil { + return nil + } + + return binary.Write(w, bo, rt.data) +} + +type btfArray struct { + Type TypeID + IndexType TypeID + Nelems uint32 +} + +type btfMember struct { + NameOff uint32 + Type TypeID + Offset uint32 +} + +type btfVarSecinfo struct { + Type TypeID + Offset uint32 + Size uint32 +} + +type btfVariable struct { + Linkage uint32 +} + +type btfEnum struct { + NameOff uint32 + Val int32 +} + +type btfParam struct { + NameOff uint32 + Type TypeID +} + +func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { + var ( + header btfType + types []rawType + ) + + for id := TypeID(1); ; id++ { + if err := binary.Read(r, bo, &header); err == io.EOF { + return types, nil + } else if err != nil { + return nil, fmt.Errorf("can't read type info for id %v: %v", id, err) + } + + var data interface{} + switch header.Kind() { + case kindInt: + data = new(uint32) + case kindPointer: + case kindArray: + data = new(btfArray) + case kindStruct: + fallthrough + case kindUnion: + data = make([]btfMember, header.Vlen()) + case kindEnum: + data = make([]btfEnum, header.Vlen()) + case kindForward: + case kindTypedef: + case kindVolatile: + case kindConst: + case kindRestrict: + case kindFunc: + case kindFuncProto: + data = make([]btfParam, header.Vlen()) + case kindVar: + data = new(btfVariable) + case kindDatasec: + data = make([]btfVarSecinfo, header.Vlen()) + default: + return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind()) + } + + if data == nil { + types = append(types, rawType{header, nil}) + continue + } + + if err := binary.Read(r, bo, data); err != nil { + return nil, fmt.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err) + } + + types = append(types, rawType{header, data}) + } +} + +func intEncoding(raw uint32) (IntEncoding, uint32, byte) { + return IntEncoding((raw & 0x0f000000) >> 24), (raw & 0x00ff0000) >> 16, byte(raw & 0x000000ff) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf_types_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf_types_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/btf_types_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/btf_types_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +// Code generated by "stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage"; DO NOT EDIT. + +package btf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[StaticFunc-0] + _ = x[GlobalFunc-1] + _ = x[ExternFunc-2] +} + +const _FuncLinkage_name = "staticglobalextern" + +var _FuncLinkage_index = [...]uint8{0, 6, 12, 18} + +func (i FuncLinkage) String() string { + if i < 0 || i >= FuncLinkage(len(_FuncLinkage_index)-1) { + return "FuncLinkage(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _FuncLinkage_name[_FuncLinkage_index[i]:_FuncLinkage_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[StaticVar-0] + _ = x[GlobalVar-1] + _ = x[ExternVar-2] +} + +const _VarLinkage_name = "staticglobalextern" + +var _VarLinkage_index = [...]uint8{0, 6, 12, 18} + +func (i VarLinkage) String() string { + if i < 0 || i >= VarLinkage(len(_VarLinkage_index)-1) { + return "VarLinkage(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _VarLinkage_name[_VarLinkage_index[i]:_VarLinkage_index[i+1]] +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/core.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/core.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/core.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/core.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,887 @@ +package btf + +import ( + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + + "github.com/cilium/ebpf/asm" +) + +// Code in this file is derived from libbpf, which is available under a BSD +// 2-Clause license. + +// COREFixup is the result of computing a CO-RE relocation for a target. +type COREFixup struct { + Kind COREKind + Local uint32 + Target uint32 + Poison bool +} + +func (f COREFixup) equal(other COREFixup) bool { + return f.Local == other.Local && f.Target == other.Target +} + +func (f COREFixup) String() string { + if f.Poison { + return fmt.Sprintf("%s=poison", f.Kind) + } + return fmt.Sprintf("%s=%d->%d", f.Kind, f.Local, f.Target) +} + +func (f COREFixup) apply(ins *asm.Instruction) error { + if f.Poison { + return errors.New("can't poison individual instruction") + } + + switch class := ins.OpCode.Class(); class { + case asm.LdXClass, asm.StClass, asm.StXClass: + if want := int16(f.Local); want != ins.Offset { + return fmt.Errorf("invalid offset %d, expected %d", ins.Offset, want) + } + + if f.Target > math.MaxInt16 { + return fmt.Errorf("offset %d exceeds MaxInt16", f.Target) + } + + ins.Offset = int16(f.Target) + + case asm.LdClass: + if !ins.IsConstantLoad(asm.DWord) { + return fmt.Errorf("not a dword-sized immediate load") + } + + if want := int64(f.Local); want != ins.Constant { + return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) + } + + ins.Constant = int64(f.Target) + + case asm.ALUClass: + if ins.OpCode.ALUOp() == asm.Swap { + return fmt.Errorf("relocation against swap") + } + + fallthrough + + case asm.ALU64Class: + if src := ins.OpCode.Source(); src != asm.ImmSource { + return fmt.Errorf("invalid source %s", src) + } + + if want := int64(f.Local); want != ins.Constant { + return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) + } + + if f.Target > math.MaxInt32 { + return fmt.Errorf("immediate %d exceeds MaxInt32", f.Target) + } + + ins.Constant = int64(f.Target) + + default: + return fmt.Errorf("invalid class %s", class) + } + + return nil +} + +func (f COREFixup) isNonExistant() bool { + return f.Kind.checksForExistence() && f.Target == 0 +} + +type COREFixups map[uint64]COREFixup + +// Apply a set of CO-RE relocations to a BPF program. +func (fs COREFixups) Apply(insns asm.Instructions) (asm.Instructions, error) { + if len(fs) == 0 { + cpy := make(asm.Instructions, len(insns)) + copy(cpy, insns) + return insns, nil + } + + cpy := make(asm.Instructions, 0, len(insns)) + iter := insns.Iterate() + for iter.Next() { + fixup, ok := fs[iter.Offset.Bytes()] + if !ok { + cpy = append(cpy, *iter.Ins) + continue + } + + ins := *iter.Ins + if fixup.Poison { + const badRelo = asm.BuiltinFunc(0xbad2310) + + cpy = append(cpy, badRelo.Call()) + if ins.OpCode.IsDWordLoad() { + // 64 bit constant loads occupy two raw bpf instructions, so + // we need to add another instruction as padding. + cpy = append(cpy, badRelo.Call()) + } + + continue + } + + if err := fixup.apply(&ins); err != nil { + return nil, fmt.Errorf("instruction %d, offset %d: %s: %w", iter.Index, iter.Offset.Bytes(), fixup.Kind, err) + } + + cpy = append(cpy, ins) + } + + return cpy, nil +} + +// COREKind is the type of CO-RE relocation +type COREKind uint32 + +const ( + reloFieldByteOffset COREKind = iota /* field byte offset */ + reloFieldByteSize /* field size in bytes */ + reloFieldExists /* field existence in target kernel */ + reloFieldSigned /* field signedness (0 - unsigned, 1 - signed) */ + reloFieldLShiftU64 /* bitfield-specific left bitshift */ + reloFieldRShiftU64 /* bitfield-specific right bitshift */ + reloTypeIDLocal /* type ID in local BPF object */ + reloTypeIDTarget /* type ID in target kernel */ + reloTypeExists /* type existence in target kernel */ + reloTypeSize /* type size in bytes */ + reloEnumvalExists /* enum value existence in target kernel */ + reloEnumvalValue /* enum value integer value */ +) + +func (k COREKind) String() string { + switch k { + case reloFieldByteOffset: + return "byte_off" + case reloFieldByteSize: + return "byte_sz" + case reloFieldExists: + return "field_exists" + case reloFieldSigned: + return "signed" + case reloFieldLShiftU64: + return "lshift_u64" + case reloFieldRShiftU64: + return "rshift_u64" + case reloTypeIDLocal: + return "local_type_id" + case reloTypeIDTarget: + return "target_type_id" + case reloTypeExists: + return "type_exists" + case reloTypeSize: + return "type_size" + case reloEnumvalExists: + return "enumval_exists" + case reloEnumvalValue: + return "enumval_value" + default: + return "unknown" + } +} + +func (k COREKind) checksForExistence() bool { + return k == reloEnumvalExists || k == reloTypeExists || k == reloFieldExists +} + +func coreRelocate(local, target *Spec, relos coreRelos) (COREFixups, error) { + if local.byteOrder != target.byteOrder { + return nil, fmt.Errorf("can't relocate %s against %s", local.byteOrder, target.byteOrder) + } + + var ids []TypeID + relosByID := make(map[TypeID]coreRelos) + result := make(COREFixups, len(relos)) + for _, relo := range relos { + if relo.kind == reloTypeIDLocal { + // Filtering out reloTypeIDLocal here makes our lives a lot easier + // down the line, since it doesn't have a target at all. + if len(relo.accessor) > 1 || relo.accessor[0] != 0 { + return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor) + } + + result[uint64(relo.insnOff)] = COREFixup{ + relo.kind, + uint32(relo.typeID), + uint32(relo.typeID), + false, + } + continue + } + + relos, ok := relosByID[relo.typeID] + if !ok { + ids = append(ids, relo.typeID) + } + relosByID[relo.typeID] = append(relos, relo) + } + + // Ensure we work on relocations in a deterministic order. + sort.Slice(ids, func(i, j int) bool { + return ids[i] < ids[j] + }) + + for _, id := range ids { + if int(id) >= len(local.types) { + return nil, fmt.Errorf("invalid type id %d", id) + } + + localType := local.types[id] + named, ok := localType.(namedType) + if !ok || named.name() == "" { + return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported) + } + + relos := relosByID[id] + targets := target.namedTypes[named.essentialName()] + fixups, err := coreCalculateFixups(localType, targets, relos) + if err != nil { + return nil, fmt.Errorf("relocate %s: %w", localType, err) + } + + for i, relo := range relos { + result[uint64(relo.insnOff)] = fixups[i] + } + } + + return result, nil +} + +var errAmbiguousRelocation = errors.New("ambiguous relocation") +var errImpossibleRelocation = errors.New("impossible relocation") + +// coreCalculateFixups calculates the fixups for the given relocations using +// the "best" target. +// +// The best target is determined by scoring: the less poisoning we have to do +// the better the target is. +func coreCalculateFixups(local Type, targets []namedType, relos coreRelos) ([]COREFixup, error) { + localID := local.ID() + local, err := copyType(local, skipQualifierAndTypedef) + if err != nil { + return nil, err + } + + bestScore := len(relos) + var bestFixups []COREFixup + for i := range targets { + targetID := targets[i].ID() + target, err := copyType(targets[i], skipQualifierAndTypedef) + if err != nil { + return nil, err + } + + score := 0 // lower is better + fixups := make([]COREFixup, 0, len(relos)) + for _, relo := range relos { + fixup, err := coreCalculateFixup(local, localID, target, targetID, relo) + if err != nil { + return nil, fmt.Errorf("target %s: %w", target, err) + } + if fixup.Poison || fixup.isNonExistant() { + score++ + } + fixups = append(fixups, fixup) + } + + if score > bestScore { + // We have a better target already, ignore this one. + continue + } + + if score < bestScore { + // This is the best target yet, use it. + bestScore = score + bestFixups = fixups + continue + } + + // Some other target has the same score as the current one. Make sure + // the fixups agree with each other. + for i, fixup := range bestFixups { + if !fixup.equal(fixups[i]) { + return nil, fmt.Errorf("%s: multiple types match: %w", fixup.Kind, errAmbiguousRelocation) + } + } + } + + if bestFixups == nil { + // Nothing at all matched, probably because there are no suitable + // targets at all. Poison everything! + bestFixups = make([]COREFixup, len(relos)) + for i, relo := range relos { + bestFixups[i] = COREFixup{Kind: relo.kind, Poison: true} + } + } + + return bestFixups, nil +} + +// coreCalculateFixup calculates the fixup for a single local type, target type +// and relocation. +func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID, relo coreRelo) (COREFixup, error) { + fixup := func(local, target uint32) (COREFixup, error) { + return COREFixup{relo.kind, local, target, false}, nil + } + poison := func() (COREFixup, error) { + if relo.kind.checksForExistence() { + return fixup(1, 0) + } + return COREFixup{relo.kind, 0, 0, true}, nil + } + zero := COREFixup{} + + switch relo.kind { + case reloTypeIDTarget, reloTypeSize, reloTypeExists: + if len(relo.accessor) > 1 || relo.accessor[0] != 0 { + return zero, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor) + } + + err := coreAreTypesCompatible(local, target) + if errors.Is(err, errImpossibleRelocation) { + return poison() + } + if err != nil { + return zero, fmt.Errorf("relocation %s: %w", relo.kind, err) + } + + switch relo.kind { + case reloTypeExists: + return fixup(1, 1) + + case reloTypeIDTarget: + return fixup(uint32(localID), uint32(targetID)) + + case reloTypeSize: + localSize, err := Sizeof(local) + if err != nil { + return zero, err + } + + targetSize, err := Sizeof(target) + if err != nil { + return zero, err + } + + return fixup(uint32(localSize), uint32(targetSize)) + } + + case reloEnumvalValue, reloEnumvalExists: + localValue, targetValue, err := coreFindEnumValue(local, relo.accessor, target) + if errors.Is(err, errImpossibleRelocation) { + return poison() + } + if err != nil { + return zero, fmt.Errorf("relocation %s: %w", relo.kind, err) + } + + switch relo.kind { + case reloEnumvalExists: + return fixup(1, 1) + + case reloEnumvalValue: + return fixup(uint32(localValue.Value), uint32(targetValue.Value)) + } + + case reloFieldByteOffset, reloFieldByteSize, reloFieldExists: + if _, ok := target.(*Fwd); ok { + // We can't relocate fields using a forward declaration, so + // skip it. If a non-forward declaration is present in the BTF + // we'll find it in one of the other iterations. + return poison() + } + + localField, targetField, err := coreFindField(local, relo.accessor, target) + if errors.Is(err, errImpossibleRelocation) { + return poison() + } + if err != nil { + return zero, fmt.Errorf("target %s: %w", target, err) + } + + switch relo.kind { + case reloFieldExists: + return fixup(1, 1) + + case reloFieldByteOffset: + return fixup(localField.offset/8, targetField.offset/8) + + case reloFieldByteSize: + localSize, err := Sizeof(localField.Type) + if err != nil { + return zero, err + } + + targetSize, err := Sizeof(targetField.Type) + if err != nil { + return zero, err + } + + return fixup(uint32(localSize), uint32(targetSize)) + + } + } + + return zero, fmt.Errorf("relocation %s: %w", relo.kind, ErrNotSupported) +} + +/* coreAccessor contains a path through a struct. It contains at least one index. + * + * The interpretation depends on the kind of the relocation. The following is + * taken from struct bpf_core_relo in libbpf_internal.h: + * + * - for field-based relocations, string encodes an accessed field using + * a sequence of field and array indices, separated by colon (:). It's + * conceptually very close to LLVM's getelementptr ([0]) instruction's + * arguments for identifying offset to a field. + * - for type-based relocations, strings is expected to be just "0"; + * - for enum value-based relocations, string contains an index of enum + * value within its enum type; + * + * Example to provide a better feel. + * + * struct sample { + * int a; + * struct { + * int b[10]; + * }; + * }; + * + * struct sample s = ...; + * int x = &s->a; // encoded as "0:0" (a is field #0) + * int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1, + * // b is field #0 inside anon struct, accessing elem #5) + * int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array) + */ +type coreAccessor []int + +func parseCoreAccessor(accessor string) (coreAccessor, error) { + if accessor == "" { + return nil, fmt.Errorf("empty accessor") + } + + var result coreAccessor + parts := strings.Split(accessor, ":") + for _, part := range parts { + // 31 bits to avoid overflowing int on 32 bit platforms. + index, err := strconv.ParseUint(part, 10, 31) + if err != nil { + return nil, fmt.Errorf("accessor index %q: %s", part, err) + } + + result = append(result, int(index)) + } + + return result, nil +} + +func (ca coreAccessor) String() string { + strs := make([]string, 0, len(ca)) + for _, i := range ca { + strs = append(strs, strconv.Itoa(i)) + } + return strings.Join(strs, ":") +} + +func (ca coreAccessor) enumValue(t Type) (*EnumValue, error) { + e, ok := t.(*Enum) + if !ok { + return nil, fmt.Errorf("not an enum: %s", t) + } + + if len(ca) > 1 { + return nil, fmt.Errorf("invalid accessor %s for enum", ca) + } + + i := ca[0] + if i >= len(e.Values) { + return nil, fmt.Errorf("invalid index %d for %s", i, e) + } + + return &e.Values[i], nil +} + +type coreField struct { + Type Type + offset uint32 +} + +func adjustOffset(base uint32, t Type, n int) (uint32, error) { + size, err := Sizeof(t) + if err != nil { + return 0, err + } + + return base + (uint32(n) * uint32(size) * 8), nil +} + +// coreFindField descends into the local type using the accessor and tries to +// find an equivalent field in target at each step. +// +// Returns the field and the offset of the field from the start of +// target in bits. +func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreField, _ error) { + // The first index is used to offset a pointer of the base type like + // when accessing an array. + localOffset, err := adjustOffset(0, local, localAcc[0]) + if err != nil { + return coreField{}, coreField{}, err + } + + targetOffset, err := adjustOffset(0, target, localAcc[0]) + if err != nil { + return coreField{}, coreField{}, err + } + + if err := coreAreMembersCompatible(local, target); err != nil { + return coreField{}, coreField{}, fmt.Errorf("fields: %w", err) + } + + var localMaybeFlex, targetMaybeFlex bool + for _, acc := range localAcc[1:] { + switch localType := local.(type) { + case composite: + // For composite types acc is used to find the field in the local type, + // and then we try to find a field in target with the same name. + localMembers := localType.members() + if acc >= len(localMembers) { + return coreField{}, coreField{}, fmt.Errorf("invalid accessor %d for %s", acc, local) + } + + localMember := localMembers[acc] + if localMember.Name == "" { + _, ok := localMember.Type.(composite) + if !ok { + return coreField{}, coreField{}, fmt.Errorf("unnamed field with type %s: %s", localMember.Type, ErrNotSupported) + } + + // This is an anonymous struct or union, ignore it. + local = localMember.Type + localOffset += localMember.Offset + localMaybeFlex = false + continue + } + + targetType, ok := target.(composite) + if !ok { + return coreField{}, coreField{}, fmt.Errorf("target not composite: %w", errImpossibleRelocation) + } + + targetMember, last, err := coreFindMember(targetType, localMember.Name) + if err != nil { + return coreField{}, coreField{}, err + } + + if targetMember.BitfieldSize > 0 { + return coreField{}, coreField{}, fmt.Errorf("field %q is a bitfield: %w", targetMember.Name, ErrNotSupported) + } + + local = localMember.Type + localMaybeFlex = acc == len(localMembers)-1 + localOffset += localMember.Offset + target = targetMember.Type + targetMaybeFlex = last + targetOffset += targetMember.Offset + + case *Array: + // For arrays, acc is the index in the target. + targetType, ok := target.(*Array) + if !ok { + return coreField{}, coreField{}, fmt.Errorf("target not array: %w", errImpossibleRelocation) + } + + if localType.Nelems == 0 && !localMaybeFlex { + return coreField{}, coreField{}, fmt.Errorf("local type has invalid flexible array") + } + if targetType.Nelems == 0 && !targetMaybeFlex { + return coreField{}, coreField{}, fmt.Errorf("target type has invalid flexible array") + } + + if localType.Nelems > 0 && acc >= int(localType.Nelems) { + return coreField{}, coreField{}, fmt.Errorf("invalid access of %s at index %d", localType, acc) + } + if targetType.Nelems > 0 && acc >= int(targetType.Nelems) { + return coreField{}, coreField{}, fmt.Errorf("out of bounds access of target: %w", errImpossibleRelocation) + } + + local = localType.Type + localMaybeFlex = false + localOffset, err = adjustOffset(localOffset, local, acc) + if err != nil { + return coreField{}, coreField{}, err + } + + target = targetType.Type + targetMaybeFlex = false + targetOffset, err = adjustOffset(targetOffset, target, acc) + if err != nil { + return coreField{}, coreField{}, err + } + + default: + return coreField{}, coreField{}, fmt.Errorf("relocate field of %T: %w", localType, ErrNotSupported) + } + + if err := coreAreMembersCompatible(local, target); err != nil { + return coreField{}, coreField{}, err + } + } + + return coreField{local, localOffset}, coreField{target, targetOffset}, nil +} + +// coreFindMember finds a member in a composite type while handling anonymous +// structs and unions. +func coreFindMember(typ composite, name Name) (Member, bool, error) { + if name == "" { + return Member{}, false, errors.New("can't search for anonymous member") + } + + type offsetTarget struct { + composite + offset uint32 + } + + targets := []offsetTarget{{typ, 0}} + visited := make(map[composite]bool) + + for i := 0; i < len(targets); i++ { + target := targets[i] + + // Only visit targets once to prevent infinite recursion. + if visited[target] { + continue + } + if len(visited) >= maxTypeDepth { + // This check is different than libbpf, which restricts the entire + // path to BPF_CORE_SPEC_MAX_LEN items. + return Member{}, false, fmt.Errorf("type is nested too deep") + } + visited[target] = true + + members := target.members() + for j, member := range members { + if member.Name == name { + // NB: This is safe because member is a copy. + member.Offset += target.offset + return member, j == len(members)-1, nil + } + + // The names don't match, but this member could be an anonymous struct + // or union. + if member.Name != "" { + continue + } + + comp, ok := member.Type.(composite) + if !ok { + return Member{}, false, fmt.Errorf("anonymous non-composite type %T not allowed", member.Type) + } + + targets = append(targets, offsetTarget{comp, target.offset + member.Offset}) + } + } + + return Member{}, false, fmt.Errorf("no matching member: %w", errImpossibleRelocation) +} + +// coreFindEnumValue follows localAcc to find the equivalent enum value in target. +func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localValue, targetValue *EnumValue, _ error) { + localValue, err := localAcc.enumValue(local) + if err != nil { + return nil, nil, err + } + + targetEnum, ok := target.(*Enum) + if !ok { + return nil, nil, errImpossibleRelocation + } + + localName := localValue.Name.essentialName() + for i, targetValue := range targetEnum.Values { + if targetValue.Name.essentialName() != localName { + continue + } + + return localValue, &targetEnum.Values[i], nil + } + + return nil, nil, errImpossibleRelocation +} + +/* The comment below is from bpf_core_types_are_compat in libbpf.c: + * + * Check local and target types for compatibility. This check is used for + * type-based CO-RE relocations and follow slightly different rules than + * field-based relocations. This function assumes that root types were already + * checked for name match. Beyond that initial root-level name check, names + * are completely ignored. Compatibility rules are as follows: + * - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but + * kind should match for local and target types (i.e., STRUCT is not + * compatible with UNION); + * - for ENUMs, the size is ignored; + * - for INT, size and signedness are ignored; + * - for ARRAY, dimensionality is ignored, element types are checked for + * compatibility recursively; + * - CONST/VOLATILE/RESTRICT modifiers are ignored; + * - TYPEDEFs/PTRs are compatible if types they pointing to are compatible; + * - FUNC_PROTOs are compatible if they have compatible signature: same + * number of input args and compatible return and argument types. + * These rules are not set in stone and probably will be adjusted as we get + * more experience with using BPF CO-RE relocations. + * + * Returns errImpossibleRelocation if types are not compatible. + */ +func coreAreTypesCompatible(localType Type, targetType Type) error { + var ( + localTs, targetTs typeDeque + l, t = &localType, &targetType + depth = 0 + ) + + for ; l != nil && t != nil; l, t = localTs.shift(), targetTs.shift() { + if depth >= maxTypeDepth { + return errors.New("types are nested too deep") + } + + localType = *l + targetType = *t + + if reflect.TypeOf(localType) != reflect.TypeOf(targetType) { + return fmt.Errorf("type mismatch: %w", errImpossibleRelocation) + } + + switch lv := (localType).(type) { + case *Void, *Struct, *Union, *Enum, *Fwd: + // Nothing to do here + + case *Int: + tv := targetType.(*Int) + if lv.isBitfield() || tv.isBitfield() { + return fmt.Errorf("bitfield: %w", errImpossibleRelocation) + } + + case *Pointer, *Array: + depth++ + localType.walk(&localTs) + targetType.walk(&targetTs) + + case *FuncProto: + tv := targetType.(*FuncProto) + if len(lv.Params) != len(tv.Params) { + return fmt.Errorf("function param mismatch: %w", errImpossibleRelocation) + } + + depth++ + localType.walk(&localTs) + targetType.walk(&targetTs) + + default: + return fmt.Errorf("unsupported type %T", localType) + } + } + + if l != nil { + return fmt.Errorf("dangling local type %T", *l) + } + + if t != nil { + return fmt.Errorf("dangling target type %T", *t) + } + + return nil +} + +/* coreAreMembersCompatible checks two types for field-based relocation compatibility. + * + * The comment below is from bpf_core_fields_are_compat in libbpf.c: + * + * Check two types for compatibility for the purpose of field access + * relocation. const/volatile/restrict and typedefs are skipped to ensure we + * are relocating semantically compatible entities: + * - any two STRUCTs/UNIONs are compatible and can be mixed; + * - any two FWDs are compatible, if their names match (modulo flavor suffix); + * - any two PTRs are always compatible; + * - for ENUMs, names should be the same (ignoring flavor suffix) or at + * least one of enums should be anonymous; + * - for ENUMs, check sizes, names are ignored; + * - for INT, size and signedness are ignored; + * - for ARRAY, dimensionality is ignored, element types are checked for + * compatibility recursively; + * [ NB: coreAreMembersCompatible doesn't recurse, this check is done + * by coreFindField. ] + * - everything else shouldn't be ever a target of relocation. + * These rules are not set in stone and probably will be adjusted as we get + * more experience with using BPF CO-RE relocations. + * + * Returns errImpossibleRelocation if the members are not compatible. + */ +func coreAreMembersCompatible(localType Type, targetType Type) error { + doNamesMatch := func(a, b string) error { + if a == "" || b == "" { + // allow anonymous and named type to match + return nil + } + + if essentialName(a) == essentialName(b) { + return nil + } + + return fmt.Errorf("names don't match: %w", errImpossibleRelocation) + } + + _, lok := localType.(composite) + _, tok := targetType.(composite) + if lok && tok { + return nil + } + + if reflect.TypeOf(localType) != reflect.TypeOf(targetType) { + return fmt.Errorf("type mismatch: %w", errImpossibleRelocation) + } + + switch lv := localType.(type) { + case *Array, *Pointer: + return nil + + case *Enum: + tv := targetType.(*Enum) + return doNamesMatch(lv.name(), tv.name()) + + case *Fwd: + tv := targetType.(*Fwd) + return doNamesMatch(lv.name(), tv.name()) + + case *Int: + tv := targetType.(*Int) + if lv.isBitfield() || tv.isBitfield() { + return fmt.Errorf("bitfield: %w", errImpossibleRelocation) + } + return nil + + default: + return fmt.Errorf("type %s: %w", localType, ErrNotSupported) + } +} + +func skipQualifierAndTypedef(typ Type) (Type, error) { + result := typ + for depth := 0; depth <= maxTypeDepth; depth++ { + switch v := (result).(type) { + case qualifier: + result = v.qualify() + case *Typedef: + result = v.Type + default: + return result, nil + } + } + return nil, errors.New("exceeded type depth") +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/doc.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/doc.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,8 @@ +// Package btf handles data encoded according to the BPF Type Format. +// +// The canonical documentation lives in the Linux kernel repository and is +// available at https://www.kernel.org/doc/html/latest/bpf/btf.html +// +// The API is very much unstable. You should only use this via the main +// ebpf library. +package btf diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,303 @@ +package btf + +import ( + "bufio" + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" +) + +type btfExtHeader struct { + Magic uint16 + Version uint8 + Flags uint8 + HdrLen uint32 + + FuncInfoOff uint32 + FuncInfoLen uint32 + LineInfoOff uint32 + LineInfoLen uint32 +} + +type btfExtCoreHeader struct { + CoreReloOff uint32 + CoreReloLen uint32 +} + +func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, relos map[string]coreRelos, err error) { + var header btfExtHeader + var coreHeader btfExtCoreHeader + if err := binary.Read(r, bo, &header); err != nil { + return nil, nil, nil, fmt.Errorf("can't read header: %v", err) + } + + if header.Magic != btfMagic { + return nil, nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic) + } + + if header.Version != 1 { + return nil, nil, nil, fmt.Errorf("unexpected version %v", header.Version) + } + + if header.Flags != 0 { + return nil, nil, nil, fmt.Errorf("unsupported flags %v", header.Flags) + } + + remainder := int64(header.HdrLen) - int64(binary.Size(&header)) + if remainder < 0 { + return nil, nil, nil, errors.New("header is too short") + } + + coreHdrSize := int64(binary.Size(&coreHeader)) + if remainder >= coreHdrSize { + if err := binary.Read(r, bo, &coreHeader); err != nil { + return nil, nil, nil, fmt.Errorf("can't read CO-RE relocation header: %v", err) + } + remainder -= coreHdrSize + } + + // Of course, the .BTF.ext header has different semantics than the + // .BTF ext header. We need to ignore non-null values. + _, err = io.CopyN(ioutil.Discard, r, remainder) + if err != nil { + return nil, nil, nil, fmt.Errorf("header padding: %v", err) + } + + if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil { + return nil, nil, nil, fmt.Errorf("can't seek to function info section: %v", err) + } + + buf := bufio.NewReader(io.LimitReader(r, int64(header.FuncInfoLen))) + funcInfo, err = parseExtInfo(buf, bo, strings) + if err != nil { + return nil, nil, nil, fmt.Errorf("function info: %w", err) + } + + if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil { + return nil, nil, nil, fmt.Errorf("can't seek to line info section: %v", err) + } + + buf = bufio.NewReader(io.LimitReader(r, int64(header.LineInfoLen))) + lineInfo, err = parseExtInfo(buf, bo, strings) + if err != nil { + return nil, nil, nil, fmt.Errorf("line info: %w", err) + } + + if coreHeader.CoreReloOff > 0 && coreHeader.CoreReloLen > 0 { + if _, err := r.Seek(int64(header.HdrLen+coreHeader.CoreReloOff), io.SeekStart); err != nil { + return nil, nil, nil, fmt.Errorf("can't seek to CO-RE relocation section: %v", err) + } + + relos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings) + if err != nil { + return nil, nil, nil, fmt.Errorf("CO-RE relocation info: %w", err) + } + } + + return funcInfo, lineInfo, relos, nil +} + +type btfExtInfoSec struct { + SecNameOff uint32 + NumInfo uint32 +} + +type extInfoRecord struct { + InsnOff uint64 + Opaque []byte +} + +type extInfo struct { + recordSize uint32 + records []extInfoRecord +} + +func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) { + if other.recordSize != ei.recordSize { + return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize) + } + + records := make([]extInfoRecord, 0, len(ei.records)+len(other.records)) + records = append(records, ei.records...) + for _, info := range other.records { + records = append(records, extInfoRecord{ + InsnOff: info.InsnOff + offset, + Opaque: info.Opaque, + }) + } + return extInfo{ei.recordSize, records}, nil +} + +func (ei extInfo) MarshalBinary() ([]byte, error) { + if len(ei.records) == 0 { + return nil, nil + } + + buf := bytes.NewBuffer(make([]byte, 0, int(ei.recordSize)*len(ei.records))) + for _, info := range ei.records { + // The kernel expects offsets in number of raw bpf instructions, + // while the ELF tracks it in bytes. + insnOff := uint32(info.InsnOff / asm.InstructionSize) + if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil { + return nil, fmt.Errorf("can't write instruction offset: %v", err) + } + + buf.Write(info.Opaque) + } + + return buf.Bytes(), nil +} + +func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) { + const maxRecordSize = 256 + + var recordSize uint32 + if err := binary.Read(r, bo, &recordSize); err != nil { + return nil, fmt.Errorf("can't read record size: %v", err) + } + + if recordSize < 4 { + // Need at least insnOff + return nil, errors.New("record size too short") + } + if recordSize > maxRecordSize { + return nil, fmt.Errorf("record size %v exceeds %v", recordSize, maxRecordSize) + } + + result := make(map[string]extInfo) + for { + secName, infoHeader, err := parseExtInfoHeader(r, bo, strings) + if errors.Is(err, io.EOF) { + return result, nil + } + + var records []extInfoRecord + for i := uint32(0); i < infoHeader.NumInfo; i++ { + var byteOff uint32 + if err := binary.Read(r, bo, &byteOff); err != nil { + return nil, fmt.Errorf("section %v: can't read extended info offset: %v", secName, err) + } + + buf := make([]byte, int(recordSize-4)) + if _, err := io.ReadFull(r, buf); err != nil { + return nil, fmt.Errorf("section %v: can't read record: %v", secName, err) + } + + if byteOff%asm.InstructionSize != 0 { + return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff) + } + + records = append(records, extInfoRecord{uint64(byteOff), buf}) + } + + result[secName] = extInfo{ + recordSize, + records, + } + } +} + +// bpfCoreRelo matches `struct bpf_core_relo` from the kernel +type bpfCoreRelo struct { + InsnOff uint32 + TypeID TypeID + AccessStrOff uint32 + Kind COREKind +} + +type coreRelo struct { + insnOff uint32 + typeID TypeID + accessor coreAccessor + kind COREKind +} + +type coreRelos []coreRelo + +// append two slices of extInfoRelo to each other. The InsnOff of b are adjusted +// by offset. +func (r coreRelos) append(other coreRelos, offset uint64) coreRelos { + result := make([]coreRelo, 0, len(r)+len(other)) + result = append(result, r...) + for _, relo := range other { + relo.insnOff += uint32(offset) + result = append(result, relo) + } + return result +} + +var extInfoReloSize = binary.Size(bpfCoreRelo{}) + +func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]coreRelos, error) { + var recordSize uint32 + if err := binary.Read(r, bo, &recordSize); err != nil { + return nil, fmt.Errorf("read record size: %v", err) + } + + if recordSize != uint32(extInfoReloSize) { + return nil, fmt.Errorf("expected record size %d, got %d", extInfoReloSize, recordSize) + } + + result := make(map[string]coreRelos) + for { + secName, infoHeader, err := parseExtInfoHeader(r, bo, strings) + if errors.Is(err, io.EOF) { + return result, nil + } + + var relos coreRelos + for i := uint32(0); i < infoHeader.NumInfo; i++ { + var relo bpfCoreRelo + if err := binary.Read(r, bo, &relo); err != nil { + return nil, fmt.Errorf("section %v: read record: %v", secName, err) + } + + if relo.InsnOff%asm.InstructionSize != 0 { + return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, relo.InsnOff) + } + + accessorStr, err := strings.Lookup(relo.AccessStrOff) + if err != nil { + return nil, err + } + + accessor, err := parseCoreAccessor(accessorStr) + if err != nil { + return nil, fmt.Errorf("accessor %q: %s", accessorStr, err) + } + + relos = append(relos, coreRelo{ + relo.InsnOff, + relo.TypeID, + accessor, + relo.Kind, + }) + } + + result[secName] = relos + } +} + +func parseExtInfoHeader(r io.Reader, bo binary.ByteOrder, strings stringTable) (string, *btfExtInfoSec, error) { + var infoHeader btfExtInfoSec + if err := binary.Read(r, bo, &infoHeader); err != nil { + return "", nil, fmt.Errorf("read ext info header: %w", err) + } + + secName, err := strings.Lookup(infoHeader.SecNameOff) + if err != nil { + return "", nil, fmt.Errorf("get section name: %w", err) + } + + if infoHeader.NumInfo == 0 { + return "", nil, fmt.Errorf("section %s has zero records", secName) + } + + return secName, &infoHeader, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,49 @@ +// +build gofuzz + +// Use with https://github.com/dvyukov/go-fuzz + +package btf + +import ( + "bytes" + "encoding/binary" + + "github.com/cilium/ebpf/internal" +) + +func FuzzSpec(data []byte) int { + if len(data) < binary.Size(btfHeader{}) { + return -1 + } + + spec, err := loadNakedSpec(bytes.NewReader(data), internal.NativeEndian, nil, nil) + if err != nil { + if spec != nil { + panic("spec is not nil") + } + return 0 + } + if spec == nil { + panic("spec is nil") + } + return 1 +} + +func FuzzExtInfo(data []byte) int { + if len(data) < binary.Size(btfExtHeader{}) { + return -1 + } + + table := stringTable("\x00foo\x00barfoo\x00") + info, err := parseExtInfo(bytes.NewReader(data), internal.NativeEndian, table) + if err != nil { + if info != nil { + panic("info is not nil") + } + return 0 + } + if info == nil { + panic("info is nil") + } + return 1 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/strings.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/strings.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/strings.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/strings.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +package btf + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" +) + +type stringTable []byte + +func readStringTable(r io.Reader) (stringTable, error) { + contents, err := ioutil.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("can't read string table: %v", err) + } + + if len(contents) < 1 { + return nil, errors.New("string table is empty") + } + + if contents[0] != '\x00' { + return nil, errors.New("first item in string table is non-empty") + } + + if contents[len(contents)-1] != '\x00' { + return nil, errors.New("string table isn't null terminated") + } + + return stringTable(contents), nil +} + +func (st stringTable) Lookup(offset uint32) (string, error) { + if int64(offset) > int64(^uint(0)>>1) { + return "", fmt.Errorf("offset %d overflows int", offset) + } + + pos := int(offset) + if pos >= len(st) { + return "", fmt.Errorf("offset %d is out of bounds", offset) + } + + if pos > 0 && st[pos-1] != '\x00' { + return "", fmt.Errorf("offset %d isn't start of a string", offset) + } + + str := st[pos:] + end := bytes.IndexByte(str, '\x00') + if end == -1 { + return "", fmt.Errorf("offset %d isn't null terminated", offset) + } + + return string(str[:end]), nil +} + +func (st stringTable) LookupName(offset uint32) (Name, error) { + str, err := st.Lookup(offset) + return Name(str), err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/types.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/types.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/btf/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/btf/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,893 @@ +package btf + +import ( + "fmt" + "math" + "strings" +) + +const maxTypeDepth = 32 + +// TypeID identifies a type in a BTF section. +type TypeID uint32 + +// ID implements part of the Type interface. +func (tid TypeID) ID() TypeID { + return tid +} + +// Type represents a type described by BTF. +type Type interface { + ID() TypeID + + String() string + + // Make a copy of the type, without copying Type members. + copy() Type + + // Enumerate all nested Types. Repeated calls must visit nested + // types in the same order. + walk(*typeDeque) +} + +// namedType is a type with a name. +// +// Most named types simply embed Name. +type namedType interface { + Type + name() string + essentialName() string +} + +// Name identifies a type. +// +// Anonymous types have an empty name. +type Name string + +func (n Name) name() string { + return string(n) +} + +func (n Name) essentialName() string { + return essentialName(string(n)) +} + +// Void is the unit type of BTF. +type Void struct{} + +func (v *Void) ID() TypeID { return 0 } +func (v *Void) String() string { return "void#0" } +func (v *Void) size() uint32 { return 0 } +func (v *Void) copy() Type { return (*Void)(nil) } +func (v *Void) walk(*typeDeque) {} + +type IntEncoding byte + +const ( + Signed IntEncoding = 1 << iota + Char + Bool +) + +// Int is an integer of a given length. +type Int struct { + TypeID + Name + + // The size of the integer in bytes. + Size uint32 + Encoding IntEncoding + // Offset is the starting bit offset. Currently always 0. + // See https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-int + Offset uint32 + Bits byte +} + +var _ namedType = (*Int)(nil) + +func (i *Int) String() string { + var s strings.Builder + + switch { + case i.Encoding&Char != 0: + s.WriteString("char") + case i.Encoding&Bool != 0: + s.WriteString("bool") + default: + if i.Encoding&Signed == 0 { + s.WriteRune('u') + } + s.WriteString("int") + fmt.Fprintf(&s, "%d", i.Size*8) + } + + fmt.Fprintf(&s, "#%d", i.TypeID) + + if i.Bits > 0 { + fmt.Fprintf(&s, "[bits=%d]", i.Bits) + } + + return s.String() +} + +func (i *Int) size() uint32 { return i.Size } +func (i *Int) walk(*typeDeque) {} +func (i *Int) copy() Type { + cpy := *i + return &cpy +} + +func (i *Int) isBitfield() bool { + return i.Offset > 0 +} + +// Pointer is a pointer to another type. +type Pointer struct { + TypeID + Target Type +} + +func (p *Pointer) String() string { + return fmt.Sprintf("pointer#%d[target=#%d]", p.TypeID, p.Target.ID()) +} + +func (p *Pointer) size() uint32 { return 8 } +func (p *Pointer) walk(tdq *typeDeque) { tdq.push(&p.Target) } +func (p *Pointer) copy() Type { + cpy := *p + return &cpy +} + +// Array is an array with a fixed number of elements. +type Array struct { + TypeID + Type Type + Nelems uint32 +} + +func (arr *Array) String() string { + return fmt.Sprintf("array#%d[type=#%d n=%d]", arr.TypeID, arr.Type.ID(), arr.Nelems) +} + +func (arr *Array) walk(tdq *typeDeque) { tdq.push(&arr.Type) } +func (arr *Array) copy() Type { + cpy := *arr + return &cpy +} + +// Struct is a compound type of consecutive members. +type Struct struct { + TypeID + Name + // The size of the struct including padding, in bytes + Size uint32 + Members []Member +} + +func (s *Struct) String() string { + return fmt.Sprintf("struct#%d[%q]", s.TypeID, s.Name) +} + +func (s *Struct) size() uint32 { return s.Size } + +func (s *Struct) walk(tdq *typeDeque) { + for i := range s.Members { + tdq.push(&s.Members[i].Type) + } +} + +func (s *Struct) copy() Type { + cpy := *s + cpy.Members = copyMembers(s.Members) + return &cpy +} + +func (s *Struct) members() []Member { + return s.Members +} + +// Union is a compound type where members occupy the same memory. +type Union struct { + TypeID + Name + // The size of the union including padding, in bytes. + Size uint32 + Members []Member +} + +func (u *Union) String() string { + return fmt.Sprintf("union#%d[%q]", u.TypeID, u.Name) +} + +func (u *Union) size() uint32 { return u.Size } + +func (u *Union) walk(tdq *typeDeque) { + for i := range u.Members { + tdq.push(&u.Members[i].Type) + } +} + +func (u *Union) copy() Type { + cpy := *u + cpy.Members = copyMembers(u.Members) + return &cpy +} + +func (u *Union) members() []Member { + return u.Members +} + +func copyMembers(orig []Member) []Member { + cpy := make([]Member, len(orig)) + copy(cpy, orig) + return cpy +} + +type composite interface { + members() []Member +} + +var ( + _ composite = (*Struct)(nil) + _ composite = (*Union)(nil) +) + +// Member is part of a Struct or Union. +// +// It is not a valid Type. +type Member struct { + Name + Type Type + // Offset is the bit offset of this member + Offset uint32 + BitfieldSize uint32 +} + +// Enum lists possible values. +type Enum struct { + TypeID + Name + Values []EnumValue +} + +func (e *Enum) String() string { + return fmt.Sprintf("enum#%d[%q]", e.TypeID, e.Name) +} + +// EnumValue is part of an Enum +// +// Is is not a valid Type +type EnumValue struct { + Name + Value int32 +} + +func (e *Enum) size() uint32 { return 4 } +func (e *Enum) walk(*typeDeque) {} +func (e *Enum) copy() Type { + cpy := *e + cpy.Values = make([]EnumValue, len(e.Values)) + copy(cpy.Values, e.Values) + return &cpy +} + +// FwdKind is the type of forward declaration. +type FwdKind int + +// Valid types of forward declaration. +const ( + FwdStruct FwdKind = iota + FwdUnion +) + +func (fk FwdKind) String() string { + switch fk { + case FwdStruct: + return "struct" + case FwdUnion: + return "union" + default: + return fmt.Sprintf("%T(%d)", fk, int(fk)) + } +} + +// Fwd is a forward declaration of a Type. +type Fwd struct { + TypeID + Name + Kind FwdKind +} + +func (f *Fwd) String() string { + return fmt.Sprintf("fwd#%d[%s %q]", f.TypeID, f.Kind, f.Name) +} + +func (f *Fwd) walk(*typeDeque) {} +func (f *Fwd) copy() Type { + cpy := *f + return &cpy +} + +// Typedef is an alias of a Type. +type Typedef struct { + TypeID + Name + Type Type +} + +func (td *Typedef) String() string { + return fmt.Sprintf("typedef#%d[%q #%d]", td.TypeID, td.Name, td.Type.ID()) +} + +func (td *Typedef) walk(tdq *typeDeque) { tdq.push(&td.Type) } +func (td *Typedef) copy() Type { + cpy := *td + return &cpy +} + +// Volatile is a qualifier. +type Volatile struct { + TypeID + Type Type +} + +func (v *Volatile) String() string { + return fmt.Sprintf("volatile#%d[#%d]", v.TypeID, v.Type.ID()) +} + +func (v *Volatile) qualify() Type { return v.Type } +func (v *Volatile) walk(tdq *typeDeque) { tdq.push(&v.Type) } +func (v *Volatile) copy() Type { + cpy := *v + return &cpy +} + +// Const is a qualifier. +type Const struct { + TypeID + Type Type +} + +func (c *Const) String() string { + return fmt.Sprintf("const#%d[#%d]", c.TypeID, c.Type.ID()) +} + +func (c *Const) qualify() Type { return c.Type } +func (c *Const) walk(tdq *typeDeque) { tdq.push(&c.Type) } +func (c *Const) copy() Type { + cpy := *c + return &cpy +} + +// Restrict is a qualifier. +type Restrict struct { + TypeID + Type Type +} + +func (r *Restrict) String() string { + return fmt.Sprintf("restrict#%d[#%d]", r.TypeID, r.Type.ID()) +} + +func (r *Restrict) qualify() Type { return r.Type } +func (r *Restrict) walk(tdq *typeDeque) { tdq.push(&r.Type) } +func (r *Restrict) copy() Type { + cpy := *r + return &cpy +} + +// Func is a function definition. +type Func struct { + TypeID + Name + Type Type + Linkage FuncLinkage +} + +func (f *Func) String() string { + return fmt.Sprintf("func#%d[%s %q proto=#%d]", f.TypeID, f.Linkage, f.Name, f.Type.ID()) +} + +func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) } +func (f *Func) copy() Type { + cpy := *f + return &cpy +} + +// FuncProto is a function declaration. +type FuncProto struct { + TypeID + Return Type + Params []FuncParam +} + +func (fp *FuncProto) String() string { + var s strings.Builder + fmt.Fprintf(&s, "proto#%d[", fp.TypeID) + for _, param := range fp.Params { + fmt.Fprintf(&s, "%q=#%d, ", param.Name, param.Type.ID()) + } + fmt.Fprintf(&s, "return=#%d]", fp.Return.ID()) + return s.String() +} + +func (fp *FuncProto) walk(tdq *typeDeque) { + tdq.push(&fp.Return) + for i := range fp.Params { + tdq.push(&fp.Params[i].Type) + } +} + +func (fp *FuncProto) copy() Type { + cpy := *fp + cpy.Params = make([]FuncParam, len(fp.Params)) + copy(cpy.Params, fp.Params) + return &cpy +} + +type FuncParam struct { + Name + Type Type +} + +// Var is a global variable. +type Var struct { + TypeID + Name + Type Type + Linkage VarLinkage +} + +func (v *Var) String() string { + return fmt.Sprintf("var#%d[%s %q]", v.TypeID, v.Linkage, v.Name) +} + +func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) } +func (v *Var) copy() Type { + cpy := *v + return &cpy +} + +// Datasec is a global program section containing data. +type Datasec struct { + TypeID + Name + Size uint32 + Vars []VarSecinfo +} + +func (ds *Datasec) String() string { + return fmt.Sprintf("section#%d[%q]", ds.TypeID, ds.Name) +} + +func (ds *Datasec) size() uint32 { return ds.Size } + +func (ds *Datasec) walk(tdq *typeDeque) { + for i := range ds.Vars { + tdq.push(&ds.Vars[i].Type) + } +} + +func (ds *Datasec) copy() Type { + cpy := *ds + cpy.Vars = make([]VarSecinfo, len(ds.Vars)) + copy(cpy.Vars, ds.Vars) + return &cpy +} + +// VarSecinfo describes variable in a Datasec +// +// It is not a valid Type. +type VarSecinfo struct { + Type Type + Offset uint32 + Size uint32 +} + +type sizer interface { + size() uint32 +} + +var ( + _ sizer = (*Int)(nil) + _ sizer = (*Pointer)(nil) + _ sizer = (*Struct)(nil) + _ sizer = (*Union)(nil) + _ sizer = (*Enum)(nil) + _ sizer = (*Datasec)(nil) +) + +type qualifier interface { + qualify() Type +} + +var ( + _ qualifier = (*Const)(nil) + _ qualifier = (*Restrict)(nil) + _ qualifier = (*Volatile)(nil) +) + +// Sizeof returns the size of a type in bytes. +// +// Returns an error if the size can't be computed. +func Sizeof(typ Type) (int, error) { + var ( + n = int64(1) + elem int64 + ) + + for i := 0; i < maxTypeDepth; i++ { + switch v := typ.(type) { + case *Array: + if n > 0 && int64(v.Nelems) > math.MaxInt64/n { + return 0, fmt.Errorf("type %s: overflow", typ) + } + + // Arrays may be of zero length, which allows + // n to be zero as well. + n *= int64(v.Nelems) + typ = v.Type + continue + + case sizer: + elem = int64(v.size()) + + case *Typedef: + typ = v.Type + continue + + case qualifier: + typ = v.qualify() + continue + + default: + return 0, fmt.Errorf("unsized type %T", typ) + } + + if n > 0 && elem > math.MaxInt64/n { + return 0, fmt.Errorf("type %s: overflow", typ) + } + + size := n * elem + if int64(int(size)) != size { + return 0, fmt.Errorf("type %s: overflow", typ) + } + + return int(size), nil + } + + return 0, fmt.Errorf("type %s: exceeded type depth", typ) +} + +// copy a Type recursively. +// +// typ may form a cycle. +// +// Returns any errors from transform verbatim. +func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) { + var ( + copies = make(map[Type]Type) + work typeDeque + ) + + for t := &typ; t != nil; t = work.pop() { + // *t is the identity of the type. + if cpy := copies[*t]; cpy != nil { + *t = cpy + continue + } + + var cpy Type + if transform != nil { + tf, err := transform(*t) + if err != nil { + return nil, fmt.Errorf("copy %s: %w", typ, err) + } + cpy = tf.copy() + } else { + cpy = (*t).copy() + } + + copies[*t] = cpy + *t = cpy + + // Mark any nested types for copying. + cpy.walk(&work) + } + + return typ, nil +} + +// typeDeque keeps track of pointers to types which still +// need to be visited. +type typeDeque struct { + types []*Type + read, write uint64 + mask uint64 +} + +// push adds a type to the stack. +func (dq *typeDeque) push(t *Type) { + if dq.write-dq.read < uint64(len(dq.types)) { + dq.types[dq.write&dq.mask] = t + dq.write++ + return + } + + new := len(dq.types) * 2 + if new == 0 { + new = 8 + } + + types := make([]*Type, new) + pivot := dq.read & dq.mask + n := copy(types, dq.types[pivot:]) + n += copy(types[n:], dq.types[:pivot]) + types[n] = t + + dq.types = types + dq.mask = uint64(new) - 1 + dq.read, dq.write = 0, uint64(n+1) +} + +// shift returns the first element or null. +func (dq *typeDeque) shift() *Type { + if dq.read == dq.write { + return nil + } + + index := dq.read & dq.mask + t := dq.types[index] + dq.types[index] = nil + dq.read++ + return t +} + +// pop returns the last element or null. +func (dq *typeDeque) pop() *Type { + if dq.read == dq.write { + return nil + } + + dq.write-- + index := dq.write & dq.mask + t := dq.types[index] + dq.types[index] = nil + return t +} + +// all returns all elements. +// +// The deque is empty after calling this method. +func (dq *typeDeque) all() []*Type { + length := dq.write - dq.read + types := make([]*Type, 0, length) + for t := dq.shift(); t != nil; t = dq.shift() { + types = append(types, t) + } + return types +} + +// inflateRawTypes takes a list of raw btf types linked via type IDs, and turns +// it into a graph of Types connected via pointers. +// +// Returns a map of named types (so, where NameOff is non-zero) and a slice of types +// indexed by TypeID. Since BTF ignores compilation units, multiple types may share +// the same name. A Type may form a cyclic graph by pointing at itself. +func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]namedType, err error) { + type fixupDef struct { + id TypeID + expectedKind btfKind + typ *Type + } + + var fixups []fixupDef + fixup := func(id TypeID, expectedKind btfKind, typ *Type) { + fixups = append(fixups, fixupDef{id, expectedKind, typ}) + } + + convertMembers := func(raw []btfMember, kindFlag bool) ([]Member, error) { + // NB: The fixup below relies on pre-allocating this array to + // work, since otherwise append might re-allocate members. + members := make([]Member, 0, len(raw)) + for i, btfMember := range raw { + name, err := rawStrings.LookupName(btfMember.NameOff) + if err != nil { + return nil, fmt.Errorf("can't get name for member %d: %w", i, err) + } + m := Member{ + Name: name, + Offset: btfMember.Offset, + } + if kindFlag { + m.BitfieldSize = btfMember.Offset >> 24 + m.Offset &= 0xffffff + } + members = append(members, m) + } + for i := range members { + fixup(raw[i].Type, kindUnknown, &members[i].Type) + } + return members, nil + } + + types = make([]Type, 0, len(rawTypes)) + types = append(types, (*Void)(nil)) + namedTypes = make(map[string][]namedType) + + for i, raw := range rawTypes { + var ( + // Void is defined to always be type ID 0, and is thus + // omitted from BTF. + id = TypeID(i + 1) + typ Type + ) + + name, err := rawStrings.LookupName(raw.NameOff) + if err != nil { + return nil, nil, fmt.Errorf("get name for type id %d: %w", id, err) + } + + switch raw.Kind() { + case kindInt: + encoding, offset, bits := intEncoding(*raw.data.(*uint32)) + typ = &Int{id, name, raw.Size(), encoding, offset, bits} + + case kindPointer: + ptr := &Pointer{id, nil} + fixup(raw.Type(), kindUnknown, &ptr.Target) + typ = ptr + + case kindArray: + btfArr := raw.data.(*btfArray) + + // IndexType is unused according to btf.rst. + // Don't make it available right now. + arr := &Array{id, nil, btfArr.Nelems} + fixup(btfArr.Type, kindUnknown, &arr.Type) + typ = arr + + case kindStruct: + members, err := convertMembers(raw.data.([]btfMember), raw.KindFlag()) + if err != nil { + return nil, nil, fmt.Errorf("struct %s (id %d): %w", name, id, err) + } + typ = &Struct{id, name, raw.Size(), members} + + case kindUnion: + members, err := convertMembers(raw.data.([]btfMember), raw.KindFlag()) + if err != nil { + return nil, nil, fmt.Errorf("union %s (id %d): %w", name, id, err) + } + typ = &Union{id, name, raw.Size(), members} + + case kindEnum: + rawvals := raw.data.([]btfEnum) + vals := make([]EnumValue, 0, len(rawvals)) + for i, btfVal := range rawvals { + name, err := rawStrings.LookupName(btfVal.NameOff) + if err != nil { + return nil, nil, fmt.Errorf("get name for enum value %d: %s", i, err) + } + vals = append(vals, EnumValue{ + Name: name, + Value: btfVal.Val, + }) + } + typ = &Enum{id, name, vals} + + case kindForward: + if raw.KindFlag() { + typ = &Fwd{id, name, FwdUnion} + } else { + typ = &Fwd{id, name, FwdStruct} + } + + case kindTypedef: + typedef := &Typedef{id, name, nil} + fixup(raw.Type(), kindUnknown, &typedef.Type) + typ = typedef + + case kindVolatile: + volatile := &Volatile{id, nil} + fixup(raw.Type(), kindUnknown, &volatile.Type) + typ = volatile + + case kindConst: + cnst := &Const{id, nil} + fixup(raw.Type(), kindUnknown, &cnst.Type) + typ = cnst + + case kindRestrict: + restrict := &Restrict{id, nil} + fixup(raw.Type(), kindUnknown, &restrict.Type) + typ = restrict + + case kindFunc: + fn := &Func{id, name, nil, raw.Linkage()} + fixup(raw.Type(), kindFuncProto, &fn.Type) + typ = fn + + case kindFuncProto: + rawparams := raw.data.([]btfParam) + params := make([]FuncParam, 0, len(rawparams)) + for i, param := range rawparams { + name, err := rawStrings.LookupName(param.NameOff) + if err != nil { + return nil, nil, fmt.Errorf("get name for func proto parameter %d: %s", i, err) + } + params = append(params, FuncParam{ + Name: name, + }) + } + for i := range params { + fixup(rawparams[i].Type, kindUnknown, ¶ms[i].Type) + } + + fp := &FuncProto{id, nil, params} + fixup(raw.Type(), kindUnknown, &fp.Return) + typ = fp + + case kindVar: + variable := raw.data.(*btfVariable) + v := &Var{id, name, nil, VarLinkage(variable.Linkage)} + fixup(raw.Type(), kindUnknown, &v.Type) + typ = v + + case kindDatasec: + btfVars := raw.data.([]btfVarSecinfo) + vars := make([]VarSecinfo, 0, len(btfVars)) + for _, btfVar := range btfVars { + vars = append(vars, VarSecinfo{ + Offset: btfVar.Offset, + Size: btfVar.Size, + }) + } + for i := range vars { + fixup(btfVars[i].Type, kindVar, &vars[i].Type) + } + typ = &Datasec{id, name, raw.SizeType, vars} + + default: + return nil, nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind()) + } + + types = append(types, typ) + + if named, ok := typ.(namedType); ok { + if name := essentialName(named.name()); name != "" { + namedTypes[name] = append(namedTypes[name], named) + } + } + } + + for _, fixup := range fixups { + i := int(fixup.id) + if i >= len(types) { + return nil, nil, fmt.Errorf("reference to invalid type id: %d", fixup.id) + } + + // Default void (id 0) to unknown + rawKind := kindUnknown + if i > 0 { + rawKind = rawTypes[i-1].Kind() + } + + if expected := fixup.expectedKind; expected != kindUnknown && rawKind != expected { + return nil, nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind) + } + + *fixup.typ = types[i] + } + + return types, namedTypes, nil +} + +// essentialName returns name without a ___ suffix. +func essentialName(name string) string { + lastIdx := strings.LastIndex(name, "___") + if lastIdx > 0 { + return name[:lastIdx] + } + return name +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/cpu.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/cpu.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/cpu.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/cpu.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +package internal + +import ( + "fmt" + "io/ioutil" + "strings" + "sync" +) + +var sysCPU struct { + once sync.Once + err error + num int +} + +// PossibleCPUs returns the max number of CPUs a system may possibly have +// Logical CPU numbers must be of the form 0-n +func PossibleCPUs() (int, error) { + sysCPU.once.Do(func() { + sysCPU.num, sysCPU.err = parseCPUsFromFile("/sys/devices/system/cpu/possible") + }) + + return sysCPU.num, sysCPU.err +} + +func parseCPUsFromFile(path string) (int, error) { + spec, err := ioutil.ReadFile(path) + if err != nil { + return 0, err + } + + n, err := parseCPUs(string(spec)) + if err != nil { + return 0, fmt.Errorf("can't parse %s: %v", path, err) + } + + return n, nil +} + +// parseCPUs parses the number of cpus from a string produced +// by bitmap_list_string() in the Linux kernel. +// Multiple ranges are rejected, since they can't be unified +// into a single number. +// This is the format of /sys/devices/system/cpu/possible, it +// is not suitable for /sys/devices/system/cpu/online, etc. +func parseCPUs(spec string) (int, error) { + if strings.Trim(spec, "\n") == "0" { + return 1, nil + } + + var low, high int + n, err := fmt.Sscanf(spec, "%d-%d\n", &low, &high) + if n != 2 || err != nil { + return 0, fmt.Errorf("invalid format: %s", spec) + } + if low != 0 { + return 0, fmt.Errorf("CPU spec doesn't start at zero: %s", spec) + } + + // cpus is 0 indexed + return high + 1, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/elf.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/elf.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/elf.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/elf.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,68 @@ +package internal + +import ( + "debug/elf" + "fmt" + "io" +) + +type SafeELFFile struct { + *elf.File +} + +// NewSafeELFFile reads an ELF safely. +// +// Any panic during parsing is turned into an error. This is necessary since +// there are a bunch of unfixed bugs in debug/elf. +// +// https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+debug%2Felf+in%3Atitle +func NewSafeELFFile(r io.ReaderAt) (safe *SafeELFFile, err error) { + defer func() { + r := recover() + if r == nil { + return + } + + safe = nil + err = fmt.Errorf("reading ELF file panicked: %s", r) + }() + + file, err := elf.NewFile(r) + if err != nil { + return nil, err + } + + return &SafeELFFile{file}, nil +} + +// Symbols is the safe version of elf.File.Symbols. +func (se *SafeELFFile) Symbols() (syms []elf.Symbol, err error) { + defer func() { + r := recover() + if r == nil { + return + } + + syms = nil + err = fmt.Errorf("reading ELF symbols panicked: %s", r) + }() + + syms, err = se.File.Symbols() + return +} + +// DynamicSymbols is the safe version of elf.File.DynamicSymbols. +func (se *SafeELFFile) DynamicSymbols() (syms []elf.Symbol, err error) { + defer func() { + r := recover() + if r == nil { + return + } + + syms = nil + err = fmt.Errorf("reading ELF dynamic symbols panicked: %s", r) + }() + + syms, err = se.File.DynamicSymbols() + return +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/endian.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/endian.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/endian.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/endian.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +package internal + +import ( + "encoding/binary" + "unsafe" +) + +// NativeEndian is set to either binary.BigEndian or binary.LittleEndian, +// depending on the host's endianness. +var NativeEndian binary.ByteOrder + +// Clang is set to either "el" or "eb" depending on the host's endianness. +var ClangEndian string + +func init() { + if isBigEndian() { + NativeEndian = binary.BigEndian + ClangEndian = "eb" + } else { + NativeEndian = binary.LittleEndian + ClangEndian = "el" + } +} + +func isBigEndian() (ret bool) { + i := int(0x1) + bs := (*[int(unsafe.Sizeof(i))]byte)(unsafe.Pointer(&i)) + return bs[0] == 0 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/errors.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/errors.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,51 @@ +package internal + +import ( + "bytes" + "errors" + "fmt" + "strings" + + "github.com/cilium/ebpf/internal/unix" +) + +// ErrorWithLog returns an error that includes logs from the +// kernel verifier. +// +// logErr should be the error returned by the syscall that generated +// the log. It is used to check for truncation of the output. +func ErrorWithLog(err error, log []byte, logErr error) error { + logStr := strings.Trim(CString(log), "\t\r\n ") + if errors.Is(logErr, unix.ENOSPC) { + logStr += " (truncated...)" + } + + return &VerifierError{err, logStr} +} + +// VerifierError includes information from the eBPF verifier. +type VerifierError struct { + cause error + log string +} + +func (le *VerifierError) Unwrap() error { + return le.cause +} + +func (le *VerifierError) Error() string { + if le.log == "" { + return le.cause.Error() + } + + return fmt.Sprintf("%s: %s", le.cause, le.log) +} + +// CString turns a NUL / zero terminated byte buffer into a string. +func CString(in []byte) string { + inLen := bytes.IndexByte(in, 0) + if inLen == -1 { + return "" + } + return string(in[:inLen]) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/fd.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/fd.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/fd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/fd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,69 @@ +package internal + +import ( + "errors" + "fmt" + "os" + "runtime" + "strconv" + + "github.com/cilium/ebpf/internal/unix" +) + +var ErrClosedFd = errors.New("use of closed file descriptor") + +type FD struct { + raw int64 +} + +func NewFD(value uint32) *FD { + fd := &FD{int64(value)} + runtime.SetFinalizer(fd, (*FD).Close) + return fd +} + +func (fd *FD) String() string { + return strconv.FormatInt(fd.raw, 10) +} + +func (fd *FD) Value() (uint32, error) { + if fd.raw < 0 { + return 0, ErrClosedFd + } + + return uint32(fd.raw), nil +} + +func (fd *FD) Close() error { + if fd.raw < 0 { + return nil + } + + value := int(fd.raw) + fd.raw = -1 + + fd.Forget() + return unix.Close(value) +} + +func (fd *FD) Forget() { + runtime.SetFinalizer(fd, nil) +} + +func (fd *FD) Dup() (*FD, error) { + if fd.raw < 0 { + return nil, ErrClosedFd + } + + dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0) + if err != nil { + return nil, fmt.Errorf("can't dup fd: %v", err) + } + + return NewFD(uint32(dup)), nil +} + +func (fd *FD) File(name string) *os.File { + fd.Forget() + return os.NewFile(uintptr(fd.raw), name) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/feature.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/feature.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/feature.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/feature.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,100 @@ +package internal + +import ( + "errors" + "fmt" + "sync" +) + +// ErrNotSupported indicates that a feature is not supported by the current kernel. +var ErrNotSupported = errors.New("not supported") + +// UnsupportedFeatureError is returned by FeatureTest() functions. +type UnsupportedFeatureError struct { + // The minimum Linux mainline version required for this feature. + // Used for the error string, and for sanity checking during testing. + MinimumVersion Version + + // The name of the feature that isn't supported. + Name string +} + +func (ufe *UnsupportedFeatureError) Error() string { + if ufe.MinimumVersion.Unspecified() { + return fmt.Sprintf("%s not supported", ufe.Name) + } + return fmt.Sprintf("%s not supported (requires >= %s)", ufe.Name, ufe.MinimumVersion) +} + +// Is indicates that UnsupportedFeatureError is ErrNotSupported. +func (ufe *UnsupportedFeatureError) Is(target error) bool { + return target == ErrNotSupported +} + +type featureTest struct { + sync.RWMutex + successful bool + result error +} + +// FeatureTestFn is used to determine whether the kernel supports +// a certain feature. +// +// The return values have the following semantics: +// +// err == ErrNotSupported: the feature is not available +// err == nil: the feature is available +// err != nil: the test couldn't be executed +type FeatureTestFn func() error + +// FeatureTest wraps a function so that it is run at most once. +// +// name should identify the tested feature, while version must be in the +// form Major.Minor[.Patch]. +// +// Returns an error wrapping ErrNotSupported if the feature is not supported. +func FeatureTest(name, version string, fn FeatureTestFn) func() error { + v, err := NewVersion(version) + if err != nil { + return func() error { return err } + } + + ft := new(featureTest) + return func() error { + ft.RLock() + if ft.successful { + defer ft.RUnlock() + return ft.result + } + ft.RUnlock() + ft.Lock() + defer ft.Unlock() + // check one more time on the off + // chance that two go routines + // were able to call into the write + // lock + if ft.successful { + return ft.result + } + err := fn() + switch { + case errors.Is(err, ErrNotSupported): + ft.result = &UnsupportedFeatureError{ + MinimumVersion: v, + Name: name, + } + fallthrough + + case err == nil: + ft.successful = true + + default: + // We couldn't execute the feature test to a point + // where it could make a determination. + // Don't cache the result, just return it. + return fmt.Errorf("detect support for %s: %w", name, err) + } + + return ft.result + } +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/io.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/io.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +package internal + +import "errors" + +// DiscardZeroes makes sure that all written bytes are zero +// before discarding them. +type DiscardZeroes struct{} + +func (DiscardZeroes) Write(p []byte) (int, error) { + for _, b := range p { + if b != 0 { + return 0, errors.New("encountered non-zero byte") + } + } + return len(p), nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/pinning.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/pinning.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/pinning.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/pinning.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +package internal + +import ( + "errors" + "fmt" + "os" + + "github.com/cilium/ebpf/internal/unix" +) + +func Pin(currentPath, newPath string, fd *FD) error { + if newPath == "" { + return errors.New("given pinning path cannot be empty") + } + if currentPath == newPath { + return nil + } + if currentPath == "" { + return BPFObjPin(newPath, fd) + } + var err error + // Renameat2 is used instead of os.Rename to disallow the new path replacing + // an existing path. + if err = unix.Renameat2(unix.AT_FDCWD, currentPath, unix.AT_FDCWD, newPath, unix.RENAME_NOREPLACE); err == nil { + // Object is now moved to the new pinning path. + return nil + } + if !os.IsNotExist(err) { + return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err) + } + // Internal state not in sync with the file system so let's fix it. + return BPFObjPin(newPath, fd) +} + +func Unpin(pinnedPath string) error { + if pinnedPath == "" { + return nil + } + err := os.Remove(pinnedPath) + if err == nil || os.IsNotExist(err) { + return nil + } + return err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +// +build armbe mips mips64p32 + +package internal + +import ( + "unsafe" +) + +// Pointer wraps an unsafe.Pointer to be 64bit to +// conform to the syscall specification. +type Pointer struct { + pad uint32 + ptr unsafe.Pointer +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +// +build 386 amd64p32 arm mipsle mips64p32le + +package internal + +import ( + "unsafe" +) + +// Pointer wraps an unsafe.Pointer to be 64bit to +// conform to the syscall specification. +type Pointer struct { + ptr unsafe.Pointer + pad uint32 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_64.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_64.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr_64.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr_64.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le +// +build !armbe,!mips,!mips64p32 + +package internal + +import ( + "unsafe" +) + +// Pointer wraps an unsafe.Pointer to be 64bit to +// conform to the syscall specification. +type Pointer struct { + ptr unsafe.Pointer +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/ptr.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/ptr.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +package internal + +import ( + "unsafe" + + "github.com/cilium/ebpf/internal/unix" +) + +// NewPointer creates a 64-bit pointer from an unsafe Pointer. +func NewPointer(ptr unsafe.Pointer) Pointer { + return Pointer{ptr: ptr} +} + +// NewSlicePointer creates a 64-bit pointer from a byte slice. +func NewSlicePointer(buf []byte) Pointer { + if len(buf) == 0 { + return Pointer{} + } + + return Pointer{ptr: unsafe.Pointer(&buf[0])} +} + +// NewStringPointer creates a 64-bit pointer from a string. +func NewStringPointer(str string) Pointer { + p, err := unix.BytePtrFromString(str) + if err != nil { + return Pointer{} + } + + return Pointer{ptr: unsafe.Pointer(p)} +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/syscall.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/syscall.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/syscall.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/syscall.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,245 @@ +package internal + +import ( + "fmt" + "path/filepath" + "runtime" + "syscall" + "unsafe" + + "github.com/cilium/ebpf/internal/unix" +) + +//go:generate stringer -output syscall_string.go -type=BPFCmd + +// BPFCmd identifies a subcommand of the bpf syscall. +type BPFCmd int + +// Well known BPF commands. +const ( + BPF_MAP_CREATE BPFCmd = iota + BPF_MAP_LOOKUP_ELEM + BPF_MAP_UPDATE_ELEM + BPF_MAP_DELETE_ELEM + BPF_MAP_GET_NEXT_KEY + BPF_PROG_LOAD + BPF_OBJ_PIN + BPF_OBJ_GET + BPF_PROG_ATTACH + BPF_PROG_DETACH + BPF_PROG_TEST_RUN + BPF_PROG_GET_NEXT_ID + BPF_MAP_GET_NEXT_ID + BPF_PROG_GET_FD_BY_ID + BPF_MAP_GET_FD_BY_ID + BPF_OBJ_GET_INFO_BY_FD + BPF_PROG_QUERY + BPF_RAW_TRACEPOINT_OPEN + BPF_BTF_LOAD + BPF_BTF_GET_FD_BY_ID + BPF_TASK_FD_QUERY + BPF_MAP_LOOKUP_AND_DELETE_ELEM + BPF_MAP_FREEZE + BPF_BTF_GET_NEXT_ID + BPF_MAP_LOOKUP_BATCH + BPF_MAP_LOOKUP_AND_DELETE_BATCH + BPF_MAP_UPDATE_BATCH + BPF_MAP_DELETE_BATCH + BPF_LINK_CREATE + BPF_LINK_UPDATE + BPF_LINK_GET_FD_BY_ID + BPF_LINK_GET_NEXT_ID + BPF_ENABLE_STATS + BPF_ITER_CREATE +) + +// BPF wraps SYS_BPF. +// +// Any pointers contained in attr must use the Pointer type from this package. +func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) { + r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) + runtime.KeepAlive(attr) + + var err error + if errNo != 0 { + err = wrappedErrno{errNo} + } + + return r1, err +} + +type BPFProgAttachAttr struct { + TargetFd uint32 + AttachBpfFd uint32 + AttachType uint32 + AttachFlags uint32 + ReplaceBpfFd uint32 +} + +func BPFProgAttach(attr *BPFProgAttachAttr) error { + _, err := BPF(BPF_PROG_ATTACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +type BPFProgDetachAttr struct { + TargetFd uint32 + AttachBpfFd uint32 + AttachType uint32 +} + +func BPFProgDetach(attr *BPFProgDetachAttr) error { + _, err := BPF(BPF_PROG_DETACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +type BPFEnableStatsAttr struct { + StatsType uint32 +} + +func BPFEnableStats(attr *BPFEnableStatsAttr) (*FD, error) { + ptr, err := BPF(BPF_ENABLE_STATS, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, fmt.Errorf("enable stats: %w", err) + } + return NewFD(uint32(ptr)), nil + +} + +type bpfObjAttr struct { + fileName Pointer + fd uint32 + fileFlags uint32 +} + +const bpfFSType = 0xcafe4a11 + +// BPFObjPin wraps BPF_OBJ_PIN. +func BPFObjPin(fileName string, fd *FD) error { + dirName := filepath.Dir(fileName) + var statfs unix.Statfs_t + if err := unix.Statfs(dirName, &statfs); err != nil { + return err + } + if uint64(statfs.Type) != bpfFSType { + return fmt.Errorf("%s is not on a bpf filesystem", fileName) + } + + value, err := fd.Value() + if err != nil { + return err + } + + attr := bpfObjAttr{ + fileName: NewStringPointer(fileName), + fd: value, + } + _, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return fmt.Errorf("pin object %s: %w", fileName, err) + } + return nil +} + +// BPFObjGet wraps BPF_OBJ_GET. +func BPFObjGet(fileName string, flags uint32) (*FD, error) { + attr := bpfObjAttr{ + fileName: NewStringPointer(fileName), + fileFlags: flags, + } + ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return nil, fmt.Errorf("get object %s: %w", fileName, err) + } + return NewFD(uint32(ptr)), nil +} + +type bpfObjGetInfoByFDAttr struct { + fd uint32 + infoLen uint32 + info Pointer +} + +// BPFObjGetInfoByFD wraps BPF_OBJ_GET_INFO_BY_FD. +// +// Available from 4.13. +func BPFObjGetInfoByFD(fd *FD, info unsafe.Pointer, size uintptr) error { + value, err := fd.Value() + if err != nil { + return err + } + + attr := bpfObjGetInfoByFDAttr{ + fd: value, + infoLen: uint32(size), + info: NewPointer(info), + } + _, err = BPF(BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + if err != nil { + return fmt.Errorf("fd %v: %w", fd, err) + } + return nil +} + +// BPFObjName is a null-terminated string made up of +// 'A-Za-z0-9_' characters. +type BPFObjName [unix.BPF_OBJ_NAME_LEN]byte + +// NewBPFObjName truncates the result if it is too long. +func NewBPFObjName(name string) BPFObjName { + var result BPFObjName + copy(result[:unix.BPF_OBJ_NAME_LEN-1], name) + return result +} + +type BPFMapCreateAttr struct { + MapType uint32 + KeySize uint32 + ValueSize uint32 + MaxEntries uint32 + Flags uint32 + InnerMapFd uint32 // since 4.12 56f668dfe00d + NumaNode uint32 // since 4.14 96eabe7a40aa + MapName BPFObjName // since 4.15 ad5b177bd73f + MapIfIndex uint32 + BTFFd uint32 + BTFKeyTypeID uint32 + BTFValueTypeID uint32 +} + +func BPFMapCreate(attr *BPFMapCreateAttr) (*FD, error) { + fd, err := BPF(BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + + return NewFD(uint32(fd)), nil +} + +// wrappedErrno wraps syscall.Errno to prevent direct comparisons with +// syscall.E* or unix.E* constants. +// +// You should never export an error of this type. +type wrappedErrno struct { + syscall.Errno +} + +func (we wrappedErrno) Unwrap() error { + return we.Errno +} + +type syscallError struct { + error + errno syscall.Errno +} + +func SyscallError(err error, errno syscall.Errno) error { + return &syscallError{err, errno} +} + +func (se *syscallError) Is(target error) bool { + return target == se.error +} + +func (se *syscallError) Unwrap() error { + return se.errno +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/syscall_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/syscall_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/syscall_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/syscall_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +// Code generated by "stringer -output syscall_string.go -type=BPFCmd"; DO NOT EDIT. + +package internal + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[BPF_MAP_CREATE-0] + _ = x[BPF_MAP_LOOKUP_ELEM-1] + _ = x[BPF_MAP_UPDATE_ELEM-2] + _ = x[BPF_MAP_DELETE_ELEM-3] + _ = x[BPF_MAP_GET_NEXT_KEY-4] + _ = x[BPF_PROG_LOAD-5] + _ = x[BPF_OBJ_PIN-6] + _ = x[BPF_OBJ_GET-7] + _ = x[BPF_PROG_ATTACH-8] + _ = x[BPF_PROG_DETACH-9] + _ = x[BPF_PROG_TEST_RUN-10] + _ = x[BPF_PROG_GET_NEXT_ID-11] + _ = x[BPF_MAP_GET_NEXT_ID-12] + _ = x[BPF_PROG_GET_FD_BY_ID-13] + _ = x[BPF_MAP_GET_FD_BY_ID-14] + _ = x[BPF_OBJ_GET_INFO_BY_FD-15] + _ = x[BPF_PROG_QUERY-16] + _ = x[BPF_RAW_TRACEPOINT_OPEN-17] + _ = x[BPF_BTF_LOAD-18] + _ = x[BPF_BTF_GET_FD_BY_ID-19] + _ = x[BPF_TASK_FD_QUERY-20] + _ = x[BPF_MAP_LOOKUP_AND_DELETE_ELEM-21] + _ = x[BPF_MAP_FREEZE-22] + _ = x[BPF_BTF_GET_NEXT_ID-23] + _ = x[BPF_MAP_LOOKUP_BATCH-24] + _ = x[BPF_MAP_LOOKUP_AND_DELETE_BATCH-25] + _ = x[BPF_MAP_UPDATE_BATCH-26] + _ = x[BPF_MAP_DELETE_BATCH-27] + _ = x[BPF_LINK_CREATE-28] + _ = x[BPF_LINK_UPDATE-29] + _ = x[BPF_LINK_GET_FD_BY_ID-30] + _ = x[BPF_LINK_GET_NEXT_ID-31] + _ = x[BPF_ENABLE_STATS-32] + _ = x[BPF_ITER_CREATE-33] +} + +const _BPFCmd_name = "BPF_MAP_CREATEBPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEMBPF_MAP_GET_NEXT_KEYBPF_PROG_LOADBPF_OBJ_PINBPF_OBJ_GETBPF_PROG_ATTACHBPF_PROG_DETACHBPF_PROG_TEST_RUNBPF_PROG_GET_NEXT_IDBPF_MAP_GET_NEXT_IDBPF_PROG_GET_FD_BY_IDBPF_MAP_GET_FD_BY_IDBPF_OBJ_GET_INFO_BY_FDBPF_PROG_QUERYBPF_RAW_TRACEPOINT_OPENBPF_BTF_LOADBPF_BTF_GET_FD_BY_IDBPF_TASK_FD_QUERYBPF_MAP_LOOKUP_AND_DELETE_ELEMBPF_MAP_FREEZEBPF_BTF_GET_NEXT_IDBPF_MAP_LOOKUP_BATCHBPF_MAP_LOOKUP_AND_DELETE_BATCHBPF_MAP_UPDATE_BATCHBPF_MAP_DELETE_BATCHBPF_LINK_CREATEBPF_LINK_UPDATEBPF_LINK_GET_FD_BY_IDBPF_LINK_GET_NEXT_IDBPF_ENABLE_STATSBPF_ITER_CREATE" + +var _BPFCmd_index = [...]uint16{0, 14, 33, 52, 71, 91, 104, 115, 126, 141, 156, 173, 193, 212, 233, 253, 275, 289, 312, 324, 344, 361, 391, 405, 424, 444, 475, 495, 515, 530, 545, 566, 586, 602, 617} + +func (i BPFCmd) String() string { + if i < 0 || i >= BPFCmd(len(_BPFCmd_index)-1) { + return "BPFCmd(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BPFCmd_name[_BPFCmd_index[i]:_BPFCmd_index[i+1]] +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,204 @@ +// +build linux + +package unix + +import ( + "bytes" + "syscall" + + linux "golang.org/x/sys/unix" +) + +const ( + ENOENT = linux.ENOENT + EEXIST = linux.EEXIST + EAGAIN = linux.EAGAIN + ENOSPC = linux.ENOSPC + EINVAL = linux.EINVAL + EPOLLIN = linux.EPOLLIN + EINTR = linux.EINTR + EPERM = linux.EPERM + ESRCH = linux.ESRCH + ENODEV = linux.ENODEV + // ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP + ENOTSUPP = syscall.Errno(0x20c) + + EBADF = linux.EBADF + BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC + BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE + BPF_F_RDONLY = linux.BPF_F_RDONLY + BPF_F_WRONLY = linux.BPF_F_WRONLY + BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG + BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG + BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE + BPF_F_MMAPABLE = linux.BPF_F_MMAPABLE + BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP + BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN + BPF_TAG_SIZE = linux.BPF_TAG_SIZE + SYS_BPF = linux.SYS_BPF + F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC + EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD + EPOLL_CLOEXEC = linux.EPOLL_CLOEXEC + O_CLOEXEC = linux.O_CLOEXEC + O_NONBLOCK = linux.O_NONBLOCK + PROT_READ = linux.PROT_READ + PROT_WRITE = linux.PROT_WRITE + MAP_SHARED = linux.MAP_SHARED + PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1 + PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE + PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT + PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT + PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE + PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE + PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF + PerfBitWatermark = linux.PerfBitWatermark + PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW + PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC + RLIM_INFINITY = linux.RLIM_INFINITY + RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK + BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME + PERF_RECORD_LOST = linux.PERF_RECORD_LOST + PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE + AT_FDCWD = linux.AT_FDCWD + RENAME_NOREPLACE = linux.RENAME_NOREPLACE +) + +// Statfs_t is a wrapper +type Statfs_t = linux.Statfs_t + +// Rlimit is a wrapper +type Rlimit = linux.Rlimit + +// Setrlimit is a wrapper +func Setrlimit(resource int, rlim *Rlimit) (err error) { + return linux.Setrlimit(resource, rlim) +} + +// Syscall is a wrapper +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return linux.Syscall(trap, a1, a2, a3) +} + +// FcntlInt is a wrapper +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + return linux.FcntlInt(fd, cmd, arg) +} + +// IoctlSetInt is a wrapper +func IoctlSetInt(fd int, req uint, value int) error { + return linux.IoctlSetInt(fd, req, value) +} + +// Statfs is a wrapper +func Statfs(path string, buf *Statfs_t) (err error) { + return linux.Statfs(path, buf) +} + +// Close is a wrapper +func Close(fd int) (err error) { + return linux.Close(fd) +} + +// EpollEvent is a wrapper +type EpollEvent = linux.EpollEvent + +// EpollWait is a wrapper +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + return linux.EpollWait(epfd, events, msec) +} + +// EpollCtl is a wrapper +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { + return linux.EpollCtl(epfd, op, fd, event) +} + +// Eventfd is a wrapper +func Eventfd(initval uint, flags int) (fd int, err error) { + return linux.Eventfd(initval, flags) +} + +// Write is a wrapper +func Write(fd int, p []byte) (n int, err error) { + return linux.Write(fd, p) +} + +// EpollCreate1 is a wrapper +func EpollCreate1(flag int) (fd int, err error) { + return linux.EpollCreate1(flag) +} + +// PerfEventMmapPage is a wrapper +type PerfEventMmapPage linux.PerfEventMmapPage + +// SetNonblock is a wrapper +func SetNonblock(fd int, nonblocking bool) (err error) { + return linux.SetNonblock(fd, nonblocking) +} + +// Mmap is a wrapper +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return linux.Mmap(fd, offset, length, prot, flags) +} + +// Munmap is a wrapper +func Munmap(b []byte) (err error) { + return linux.Munmap(b) +} + +// PerfEventAttr is a wrapper +type PerfEventAttr = linux.PerfEventAttr + +// PerfEventOpen is a wrapper +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + return linux.PerfEventOpen(attr, pid, cpu, groupFd, flags) +} + +// Utsname is a wrapper +type Utsname = linux.Utsname + +// Uname is a wrapper +func Uname(buf *Utsname) (err error) { + return linux.Uname(buf) +} + +// Getpid is a wrapper +func Getpid() int { + return linux.Getpid() +} + +// Gettid is a wrapper +func Gettid() int { + return linux.Gettid() +} + +// Tgkill is a wrapper +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + return linux.Tgkill(tgid, tid, sig) +} + +// BytePtrFromString is a wrapper +func BytePtrFromString(s string) (*byte, error) { + return linux.BytePtrFromString(s) +} + +// ByteSliceToString is a wrapper +func ByteSliceToString(s []byte) string { + return linux.ByteSliceToString(s) +} + +// Renameat2 is a wrapper +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error { + return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags) +} + +func KernelRelease() (string, error) { + var uname Utsname + err := Uname(&uname) + if err != nil { + return "", err + } + + end := bytes.IndexByte(uname.Release[:], 0) + release := string(uname.Release[:end]) + return release, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/unix/types_other.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/unix/types_other.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/unix/types_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/unix/types_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,263 @@ +// +build !linux + +package unix + +import ( + "fmt" + "runtime" + "syscall" +) + +var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH) + +const ( + ENOENT = syscall.ENOENT + EEXIST = syscall.EEXIST + EAGAIN = syscall.EAGAIN + ENOSPC = syscall.ENOSPC + EINVAL = syscall.EINVAL + EINTR = syscall.EINTR + EPERM = syscall.EPERM + ESRCH = syscall.ESRCH + ENODEV = syscall.ENODEV + EBADF = syscall.Errno(0) + // ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP + ENOTSUPP = syscall.Errno(0x20c) + + BPF_F_NO_PREALLOC = 0 + BPF_F_NUMA_NODE = 0 + BPF_F_RDONLY = 0 + BPF_F_WRONLY = 0 + BPF_F_RDONLY_PROG = 0 + BPF_F_WRONLY_PROG = 0 + BPF_F_SLEEPABLE = 0 + BPF_F_MMAPABLE = 0 + BPF_F_INNER_MAP = 0 + BPF_OBJ_NAME_LEN = 0x10 + BPF_TAG_SIZE = 0x8 + SYS_BPF = 321 + F_DUPFD_CLOEXEC = 0x406 + EPOLLIN = 0x1 + EPOLL_CTL_ADD = 0x1 + EPOLL_CLOEXEC = 0x80000 + O_CLOEXEC = 0x80000 + O_NONBLOCK = 0x800 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + MAP_SHARED = 0x1 + PERF_ATTR_SIZE_VER1 = 0 + PERF_TYPE_SOFTWARE = 0x1 + PERF_TYPE_TRACEPOINT = 0 + PERF_COUNT_SW_BPF_OUTPUT = 0xa + PERF_EVENT_IOC_DISABLE = 0 + PERF_EVENT_IOC_ENABLE = 0 + PERF_EVENT_IOC_SET_BPF = 0 + PerfBitWatermark = 0x4000 + PERF_SAMPLE_RAW = 0x400 + PERF_FLAG_FD_CLOEXEC = 0x8 + RLIM_INFINITY = 0x7fffffffffffffff + RLIMIT_MEMLOCK = 8 + BPF_STATS_RUN_TIME = 0 + PERF_RECORD_LOST = 2 + PERF_RECORD_SAMPLE = 9 + AT_FDCWD = -0x2 + RENAME_NOREPLACE = 0x1 +) + +// Statfs_t is a wrapper +type Statfs_t struct { + Type int64 + Bsize int64 + Blocks uint64 + Bfree uint64 + Bavail uint64 + Files uint64 + Ffree uint64 + Fsid [2]int32 + Namelen int64 + Frsize int64 + Flags int64 + Spare [4]int64 +} + +// Rlimit is a wrapper +type Rlimit struct { + Cur uint64 + Max uint64 +} + +// Setrlimit is a wrapper +func Setrlimit(resource int, rlim *Rlimit) (err error) { + return errNonLinux +} + +// Syscall is a wrapper +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return 0, 0, syscall.Errno(1) +} + +// FcntlInt is a wrapper +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + return -1, errNonLinux +} + +// IoctlSetInt is a wrapper +func IoctlSetInt(fd int, req uint, value int) error { + return errNonLinux +} + +// Statfs is a wrapper +func Statfs(path string, buf *Statfs_t) error { + return errNonLinux +} + +// Close is a wrapper +func Close(fd int) (err error) { + return errNonLinux +} + +// EpollEvent is a wrapper +type EpollEvent struct { + Events uint32 + Fd int32 + Pad int32 +} + +// EpollWait is a wrapper +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + return 0, errNonLinux +} + +// EpollCtl is a wrapper +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { + return errNonLinux +} + +// Eventfd is a wrapper +func Eventfd(initval uint, flags int) (fd int, err error) { + return 0, errNonLinux +} + +// Write is a wrapper +func Write(fd int, p []byte) (n int, err error) { + return 0, errNonLinux +} + +// EpollCreate1 is a wrapper +func EpollCreate1(flag int) (fd int, err error) { + return 0, errNonLinux +} + +// PerfEventMmapPage is a wrapper +type PerfEventMmapPage struct { + Version uint32 + Compat_version uint32 + Lock uint32 + Index uint32 + Offset int64 + Time_enabled uint64 + Time_running uint64 + Capabilities uint64 + Pmc_width uint16 + Time_shift uint16 + Time_mult uint32 + Time_offset uint64 + Time_zero uint64 + Size uint32 + + Data_head uint64 + Data_tail uint64 + Data_offset uint64 + Data_size uint64 + Aux_head uint64 + Aux_tail uint64 + Aux_offset uint64 + Aux_size uint64 +} + +// SetNonblock is a wrapper +func SetNonblock(fd int, nonblocking bool) (err error) { + return errNonLinux +} + +// Mmap is a wrapper +func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { + return []byte{}, errNonLinux +} + +// Munmap is a wrapper +func Munmap(b []byte) (err error) { + return errNonLinux +} + +// PerfEventAttr is a wrapper +type PerfEventAttr struct { + Type uint32 + Size uint32 + Config uint64 + Sample uint64 + Sample_type uint64 + Read_format uint64 + Bits uint64 + Wakeup uint32 + Bp_type uint32 + Ext1 uint64 + Ext2 uint64 + Branch_sample_type uint64 + Sample_regs_user uint64 + Sample_stack_user uint32 + Clockid int32 + Sample_regs_intr uint64 + Aux_watermark uint32 + Sample_max_stack uint16 +} + +// PerfEventOpen is a wrapper +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + return 0, errNonLinux +} + +// Utsname is a wrapper +type Utsname struct { + Release [65]byte + Version [65]byte +} + +// Uname is a wrapper +func Uname(buf *Utsname) (err error) { + return errNonLinux +} + +// Getpid is a wrapper +func Getpid() int { + return -1 +} + +// Gettid is a wrapper +func Gettid() int { + return -1 +} + +// Tgkill is a wrapper +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + return errNonLinux +} + +// BytePtrFromString is a wrapper +func BytePtrFromString(s string) (*byte, error) { + return nil, errNonLinux +} + +// ByteSliceToString is a wrapper +func ByteSliceToString(s []byte) string { + return "" +} + +// Renameat2 is a wrapper +func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error { + return errNonLinux +} + +func KernelRelease() (string, error) { + return "", errNonLinux +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/version.go containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/version.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/internal/version.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/internal/version.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,163 @@ +package internal + +import ( + "fmt" + "io/ioutil" + "regexp" + "sync" + + "github.com/cilium/ebpf/internal/unix" +) + +const ( + // Version constant used in ELF binaries indicating that the loader needs to + // substitute the eBPF program's version with the value of the kernel's + // KERNEL_VERSION compile-time macro. Used for compatibility with BCC, gobpf + // and RedSift. + MagicKernelVersion = 0xFFFFFFFE +) + +var ( + // Match between one and three decimals separated by dots, with the last + // segment (patch level) being optional on some kernels. + // The x.y.z string must appear at the start of a string or right after + // whitespace to prevent sequences like 'x.y.z-a.b.c' from matching 'a.b.c'. + rgxKernelVersion = regexp.MustCompile(`(?:\A|\s)\d{1,3}\.\d{1,3}(?:\.\d{1,3})?`) + + kernelVersion = struct { + once sync.Once + version Version + err error + }{} +) + +// A Version in the form Major.Minor.Patch. +type Version [3]uint16 + +// NewVersion creates a version from a string like "Major.Minor.Patch". +// +// Patch is optional. +func NewVersion(ver string) (Version, error) { + var major, minor, patch uint16 + n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch) + if n < 2 { + return Version{}, fmt.Errorf("invalid version: %s", ver) + } + return Version{major, minor, patch}, nil +} + +func (v Version) String() string { + if v[2] == 0 { + return fmt.Sprintf("v%d.%d", v[0], v[1]) + } + return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2]) +} + +// Less returns true if the version is less than another version. +func (v Version) Less(other Version) bool { + for i, a := range v { + if a == other[i] { + continue + } + return a < other[i] + } + return false +} + +// Unspecified returns true if the version is all zero. +func (v Version) Unspecified() bool { + return v[0] == 0 && v[1] == 0 && v[2] == 0 +} + +// Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h. +// It represents the kernel version and patch level as a single value. +func (v Version) Kernel() uint32 { + + // Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid + // overflowing into PATCHLEVEL. + // See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255"). + s := v[2] + if s > 255 { + s = 255 + } + + // Truncate members to uint8 to prevent them from spilling over into + // each other when overflowing 8 bits. + return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s)) +} + +// KernelVersion returns the version of the currently running kernel. +func KernelVersion() (Version, error) { + kernelVersion.once.Do(func() { + kernelVersion.version, kernelVersion.err = detectKernelVersion() + }) + + if kernelVersion.err != nil { + return Version{}, kernelVersion.err + } + return kernelVersion.version, nil +} + +// detectKernelVersion returns the version of the running kernel. It scans the +// following sources in order: /proc/version_signature, uname -v, uname -r. +// In each of those locations, the last-appearing x.y(.z) value is selected +// for parsing. The first location that yields a usable version number is +// returned. +func detectKernelVersion() (Version, error) { + + // Try reading /proc/version_signature for Ubuntu compatibility. + // Example format: Ubuntu 4.15.0-91.92-generic 4.15.18 + // This method exists in the kernel itself, see d18acd15c + // ("perf tools: Fix kernel version error in ubuntu"). + if pvs, err := ioutil.ReadFile("/proc/version_signature"); err == nil { + // If /proc/version_signature exists, failing to parse it is an error. + // It only exists on Ubuntu, where the real patch level is not obtainable + // through any other method. + v, err := findKernelVersion(string(pvs)) + if err != nil { + return Version{}, err + } + return v, nil + } + + var uname unix.Utsname + if err := unix.Uname(&uname); err != nil { + return Version{}, fmt.Errorf("calling uname: %w", err) + } + + // Debian puts the version including the patch level in uname.Version. + // It is not an error if there's no version number in uname.Version, + // as most distributions don't use it. Parsing can continue on uname.Release. + // Example format: #1 SMP Debian 4.19.37-5+deb10u2 (2019-08-08) + if v, err := findKernelVersion(unix.ByteSliceToString(uname.Version[:])); err == nil { + return v, nil + } + + // Most other distributions have the full kernel version including patch + // level in uname.Release. + // Example format: 4.19.0-5-amd64, 5.5.10-arch1-1 + v, err := findKernelVersion(unix.ByteSliceToString(uname.Release[:])) + if err != nil { + return Version{}, err + } + + return v, nil +} + +// findKernelVersion matches s against rgxKernelVersion and parses the result +// into a Version. If s contains multiple matches, the last entry is selected. +func findKernelVersion(s string) (Version, error) { + m := rgxKernelVersion.FindAllString(s, -1) + if m == nil { + return Version{}, fmt.Errorf("no kernel version in string: %s", s) + } + // Pick the last match of the string in case there are multiple. + s = m[len(m)-1] + + v, err := NewVersion(s) + if err != nil { + return Version{}, fmt.Errorf("parsing version string %s: %w", s, err) + } + + return v, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/LICENSE containerd-1.5.9/vendor/github.com/cilium/ebpf/LICENSE --- containerd-1.2.6/vendor/github.com/cilium/ebpf/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2017 Nathan Sweet +Copyright (c) 2018, 2019 Cloudflare +Copyright (c) 2019 Authors of Cilium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/cgroup.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/cgroup.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/cgroup.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/cgroup.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,171 @@ +package link + +import ( + "errors" + "fmt" + "os" + + "github.com/cilium/ebpf" +) + +type cgroupAttachFlags uint32 + +// cgroup attach flags +const ( + flagAllowOverride cgroupAttachFlags = 1 << iota + flagAllowMulti + flagReplace +) + +type CgroupOptions struct { + // Path to a cgroupv2 folder. + Path string + // One of the AttachCgroup* constants + Attach ebpf.AttachType + // Program must be of type CGroup*, and the attach type must match Attach. + Program *ebpf.Program +} + +// AttachCgroup links a BPF program to a cgroup. +func AttachCgroup(opts CgroupOptions) (Link, error) { + cgroup, err := os.Open(opts.Path) + if err != nil { + return nil, fmt.Errorf("can't open cgroup: %s", err) + } + + clone, err := opts.Program.Clone() + if err != nil { + cgroup.Close() + return nil, err + } + + var cg Link + cg, err = newLinkCgroup(cgroup, opts.Attach, clone) + if errors.Is(err, ErrNotSupported) { + cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowMulti) + } + if errors.Is(err, ErrNotSupported) { + cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowOverride) + } + if err != nil { + cgroup.Close() + clone.Close() + return nil, err + } + + return cg, nil +} + +// LoadPinnedCgroup loads a pinned cgroup from a bpffs. +func LoadPinnedCgroup(fileName string, opts *ebpf.LoadPinOptions) (Link, error) { + link, err := LoadPinnedRawLink(fileName, CgroupType, opts) + if err != nil { + return nil, err + } + + return &linkCgroup{*link}, nil +} + +type progAttachCgroup struct { + cgroup *os.File + current *ebpf.Program + attachType ebpf.AttachType + flags cgroupAttachFlags +} + +var _ Link = (*progAttachCgroup)(nil) + +func (cg *progAttachCgroup) isLink() {} + +func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program, flags cgroupAttachFlags) (*progAttachCgroup, error) { + if flags&flagAllowMulti > 0 { + if err := haveProgAttachReplace(); err != nil { + return nil, fmt.Errorf("can't support multiple programs: %w", err) + } + } + + err := RawAttachProgram(RawAttachProgramOptions{ + Target: int(cgroup.Fd()), + Program: prog, + Flags: uint32(flags), + Attach: attach, + }) + if err != nil { + return nil, fmt.Errorf("cgroup: %w", err) + } + + return &progAttachCgroup{cgroup, prog, attach, flags}, nil +} + +func (cg *progAttachCgroup) Close() error { + defer cg.cgroup.Close() + defer cg.current.Close() + + err := RawDetachProgram(RawDetachProgramOptions{ + Target: int(cg.cgroup.Fd()), + Program: cg.current, + Attach: cg.attachType, + }) + if err != nil { + return fmt.Errorf("close cgroup: %s", err) + } + return nil +} + +func (cg *progAttachCgroup) Update(prog *ebpf.Program) error { + new, err := prog.Clone() + if err != nil { + return err + } + + args := RawAttachProgramOptions{ + Target: int(cg.cgroup.Fd()), + Program: prog, + Attach: cg.attachType, + Flags: uint32(cg.flags), + } + + if cg.flags&flagAllowMulti > 0 { + // Atomically replacing multiple programs requires at least + // 5.5 (commit 7dd68b3279f17921 "bpf: Support replacing cgroup-bpf + // program in MULTI mode") + args.Flags |= uint32(flagReplace) + args.Replace = cg.current + } + + if err := RawAttachProgram(args); err != nil { + new.Close() + return fmt.Errorf("can't update cgroup: %s", err) + } + + cg.current.Close() + cg.current = new + return nil +} + +func (cg *progAttachCgroup) Pin(string) error { + return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported) +} + +func (cg *progAttachCgroup) Unpin() error { + return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported) +} + +type linkCgroup struct { + RawLink +} + +var _ Link = (*linkCgroup)(nil) + +func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) (*linkCgroup, error) { + link, err := AttachRawLink(RawLinkOptions{ + Target: int(cgroup.Fd()), + Program: prog, + Attach: attach, + }) + if err != nil { + return nil, err + } + + return &linkCgroup{*link}, err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/doc.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/doc.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +// Package link allows attaching eBPF programs to various kernel hooks. +package link diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/iter.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/iter.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/iter.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/iter.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,100 @@ +package link + +import ( + "fmt" + "io" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" +) + +type IterOptions struct { + // Program must be of type Tracing with attach type + // AttachTraceIter. The kind of iterator to attach to is + // determined at load time via the AttachTo field. + // + // AttachTo requires the kernel to include BTF of itself, + // and it to be compiled with a recent pahole (>= 1.16). + Program *ebpf.Program + + // Map specifies the target map for bpf_map_elem and sockmap iterators. + // It may be nil. + Map *ebpf.Map +} + +// AttachIter attaches a BPF seq_file iterator. +func AttachIter(opts IterOptions) (*Iter, error) { + if err := haveBPFLink(); err != nil { + return nil, err + } + + progFd := opts.Program.FD() + if progFd < 0 { + return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd) + } + + var info bpfIterLinkInfoMap + if opts.Map != nil { + mapFd := opts.Map.FD() + if mapFd < 0 { + return nil, fmt.Errorf("invalid map: %w", internal.ErrClosedFd) + } + info.map_fd = uint32(mapFd) + } + + attr := bpfLinkCreateIterAttr{ + prog_fd: uint32(progFd), + attach_type: ebpf.AttachTraceIter, + iter_info: internal.NewPointer(unsafe.Pointer(&info)), + iter_info_len: uint32(unsafe.Sizeof(info)), + } + + fd, err := bpfLinkCreateIter(&attr) + if err != nil { + return nil, fmt.Errorf("can't link iterator: %w", err) + } + + return &Iter{RawLink{fd, ""}}, err +} + +// LoadPinnedIter loads a pinned iterator from a bpffs. +func LoadPinnedIter(fileName string, opts *ebpf.LoadPinOptions) (*Iter, error) { + link, err := LoadPinnedRawLink(fileName, IterType, opts) + if err != nil { + return nil, err + } + + return &Iter{*link}, err +} + +// Iter represents an attached bpf_iter. +type Iter struct { + RawLink +} + +// Open creates a new instance of the iterator. +// +// Reading from the returned reader triggers the BPF program. +func (it *Iter) Open() (io.ReadCloser, error) { + linkFd, err := it.fd.Value() + if err != nil { + return nil, err + } + + attr := &bpfIterCreateAttr{ + linkFd: linkFd, + } + + fd, err := bpfIterCreate(attr) + if err != nil { + return nil, fmt.Errorf("can't create iterator: %w", err) + } + + return fd.File("bpf_iter"), nil +} + +// union bpf_iter_link_info.map +type bpfIterLinkInfoMap struct { + map_fd uint32 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/kprobe.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/kprobe.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/kprobe.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/kprobe.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,438 @@ +package link + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sync" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/unix" +) + +var ( + kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events") + + kprobeRetprobeBit = struct { + once sync.Once + value uint64 + err error + }{} +) + +type probeType uint8 + +const ( + kprobeType probeType = iota + uprobeType +) + +func (pt probeType) String() string { + if pt == kprobeType { + return "kprobe" + } + return "uprobe" +} + +func (pt probeType) EventsPath() string { + if pt == kprobeType { + return kprobeEventsPath + } + return uprobeEventsPath +} + +func (pt probeType) PerfEventType(ret bool) perfEventType { + if pt == kprobeType { + if ret { + return kretprobeEvent + } + return kprobeEvent + } + if ret { + return uretprobeEvent + } + return uprobeEvent +} + +func (pt probeType) RetprobeBit() (uint64, error) { + if pt == kprobeType { + return kretprobeBit() + } + return uretprobeBit() +} + +// Kprobe attaches the given eBPF program to a perf event that fires when the +// given kernel symbol starts executing. See /proc/kallsyms for available +// symbols. For example, printk(): +// +// Kprobe("printk", prog) +// +// The resulting Link must be Closed during program shutdown to avoid leaking +// system resources. +func Kprobe(symbol string, prog *ebpf.Program) (Link, error) { + k, err := kprobe(symbol, prog, false) + if err != nil { + return nil, err + } + + err = k.attach(prog) + if err != nil { + k.Close() + return nil, err + } + + return k, nil +} + +// Kretprobe attaches the given eBPF program to a perf event that fires right +// before the given kernel symbol exits, with the function stack left intact. +// See /proc/kallsyms for available symbols. For example, printk(): +// +// Kretprobe("printk", prog) +// +// The resulting Link must be Closed during program shutdown to avoid leaking +// system resources. +func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) { + k, err := kprobe(symbol, prog, true) + if err != nil { + return nil, err + } + + err = k.attach(prog) + if err != nil { + k.Close() + return nil, err + } + + return k, nil +} + +// kprobe opens a perf event on the given symbol and attaches prog to it. +// If ret is true, create a kretprobe. +func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) { + if symbol == "" { + return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput) + } + if prog == nil { + return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput) + } + if !rgxTraceEvent.MatchString(symbol) { + return nil, fmt.Errorf("symbol '%s' must be alphanumeric or underscore: %w", symbol, errInvalidInput) + } + if prog.Type() != ebpf.Kprobe { + return nil, fmt.Errorf("eBPF program type %s is not a Kprobe: %w", prog.Type(), errInvalidInput) + } + + // Use kprobe PMU if the kernel has it available. + tp, err := pmuKprobe(platformPrefix(symbol), ret) + if errors.Is(err, os.ErrNotExist) { + tp, err = pmuKprobe(symbol, ret) + } + if err == nil { + return tp, nil + } + if err != nil && !errors.Is(err, ErrNotSupported) { + return nil, fmt.Errorf("creating perf_kprobe PMU: %w", err) + } + + // Use tracefs if kprobe PMU is missing. + tp, err = tracefsKprobe(platformPrefix(symbol), ret) + if errors.Is(err, os.ErrNotExist) { + tp, err = tracefsKprobe(symbol, ret) + } + if err != nil { + return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err) + } + + return tp, nil +} + +// pmuKprobe opens a perf event based on the kprobe PMU. +// Returns os.ErrNotExist if the given symbol does not exist in the kernel. +func pmuKprobe(symbol string, ret bool) (*perfEvent, error) { + return pmuProbe(kprobeType, symbol, "", 0, ret) +} + +// pmuProbe opens a perf event based on a Performance Monitoring Unit. +// +// Requires at least a 4.17 kernel. +// e12f03d7031a "perf/core: Implement the 'perf_kprobe' PMU" +// 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU" +// +// Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU +func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { + // Getting the PMU type will fail if the kernel doesn't support + // the perf_[k,u]probe PMU. + et, err := getPMUEventType(typ) + if err != nil { + return nil, err + } + + var config uint64 + if ret { + bit, err := typ.RetprobeBit() + if err != nil { + return nil, err + } + config |= 1 << bit + } + + var ( + attr unix.PerfEventAttr + sp unsafe.Pointer + ) + switch typ { + case kprobeType: + // Create a pointer to a NUL-terminated string for the kernel. + sp, err := unsafeStringPtr(symbol) + if err != nil { + return nil, err + } + + attr = unix.PerfEventAttr{ + Type: uint32(et), // PMU event type read from sysfs + Ext1: uint64(uintptr(sp)), // Kernel symbol to trace + Config: config, // Retprobe flag + } + case uprobeType: + sp, err := unsafeStringPtr(path) + if err != nil { + return nil, err + } + + attr = unix.PerfEventAttr{ + // The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1, + // since it added the config2 (Ext2) field. The Size field controls the + // size of the internal buffer the kernel allocates for reading the + // perf_event_attr argument from userspace. + Size: unix.PERF_ATTR_SIZE_VER1, + Type: uint32(et), // PMU event type read from sysfs + Ext1: uint64(uintptr(sp)), // Uprobe path + Ext2: offset, // Uprobe offset + Config: config, // Retprobe flag + } + } + + fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + + // Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL + // when trying to create a kretprobe for a missing symbol. Make sure ENOENT + // is returned to the caller. + if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) { + return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist) + } + if err != nil { + return nil, fmt.Errorf("opening perf event: %w", err) + } + + // Ensure the string pointer is not collected before PerfEventOpen returns. + runtime.KeepAlive(sp) + + // Kernel has perf_[k,u]probe PMU available, initialize perf event. + return &perfEvent{ + fd: internal.NewFD(uint32(fd)), + pmuID: et, + name: symbol, + typ: typ.PerfEventType(ret), + }, nil +} + +// tracefsKprobe creates a Kprobe tracefs entry. +func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) { + return tracefsProbe(kprobeType, symbol, "", 0, ret) +} + +// tracefsProbe creates a trace event by writing an entry to /[k,u]probe_events. +// A new trace event group name is generated on every call to support creating +// multiple trace events for the same kernel or userspace symbol. +// Path and offset are only set in the case of uprobe(s) and are used to set +// the executable/library path on the filesystem and the offset where the probe is inserted. +// A perf event is then opened on the newly-created trace event and returned to the caller. +func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) { + // Generate a random string for each trace event we attempt to create. + // This value is used as the 'group' token in tracefs to allow creating + // multiple kprobe trace events with the same name. + group, err := randomGroup("ebpf") + if err != nil { + return nil, fmt.Errorf("randomizing group name: %w", err) + } + + // Before attempting to create a trace event through tracefs, + // check if an event with the same group and name already exists. + // Kernels 4.x and earlier don't return os.ErrExist on writing a duplicate + // entry, so we need to rely on reads for detecting uniqueness. + _, err = getTraceEventID(group, symbol) + if err == nil { + return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol) + } + if err != nil && !errors.Is(err, os.ErrNotExist) { + return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err) + } + + // Create the [k,u]probe trace event using tracefs. + if err := createTraceFSProbeEvent(typ, group, symbol, path, offset, ret); err != nil { + return nil, fmt.Errorf("creating probe entry on tracefs: %w", err) + } + + // Get the newly-created trace event's id. + tid, err := getTraceEventID(group, symbol) + if err != nil { + return nil, fmt.Errorf("getting trace event id: %w", err) + } + + // Kprobes are ephemeral tracepoints and share the same perf event type. + fd, err := openTracepointPerfEvent(tid) + if err != nil { + return nil, err + } + + return &perfEvent{ + fd: fd, + group: group, + name: symbol, + tracefsID: tid, + typ: typ.PerfEventType(ret), + }, nil +} + +// createTraceFSProbeEvent creates a new ephemeral trace event by writing to +// /[k,u]probe_events. Returns os.ErrNotExist if symbol is not a valid +// kernel symbol, or if it is not traceable with kprobes. Returns os.ErrExist +// if a probe with the same group and symbol already exists. +func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset uint64, ret bool) error { + // Open the kprobe_events file in tracefs. + f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666) + if err != nil { + return fmt.Errorf("error opening '%s': %w", typ.EventsPath(), err) + } + defer f.Close() + + var pe string + switch typ { + case kprobeType: + // The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt): + // p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe + // r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe + // -:[GRP/]EVENT : Clear a probe + // + // Some examples: + // r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy + // p:ebpf_5678/p_my_kprobe __x64_sys_execve + // + // Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the + // kernel default to NR_CPUS. This is desired in most eBPF cases since + // subsampling or rate limiting logic can be more accurately implemented in + // the eBPF program itself. + // See Documentation/kprobes.txt for more details. + pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, symbol) + case uprobeType: + // The uprobe_events syntax is as follows: + // p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a probe + // r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return probe + // -:[GRP/]EVENT : Clear a probe + // + // Some examples: + // r:ebpf_1234/readline /bin/bash:0x12345 + // p:ebpf_5678/main_mySymbol /bin/mybin:0x12345 + // + // See Documentation/trace/uprobetracer.txt for more details. + pathOffset := uprobePathOffset(path, offset) + pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, pathOffset) + } + _, err = f.WriteString(pe) + // Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL + // when trying to create a kretprobe for a missing symbol. Make sure ENOENT + // is returned to the caller. + if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) { + return fmt.Errorf("symbol %s not found: %w", symbol, os.ErrNotExist) + } + if err != nil { + return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err) + } + + return nil +} + +// closeTraceFSProbeEvent removes the [k,u]probe with the given type, group and symbol +// from /[k,u]probe_events. +func closeTraceFSProbeEvent(typ probeType, group, symbol string) error { + f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666) + if err != nil { + return fmt.Errorf("error opening %s: %w", typ.EventsPath(), err) + } + defer f.Close() + + // See [k,u]probe_events syntax above. The probe type does not need to be specified + // for removals. + pe := fmt.Sprintf("-:%s/%s", group, symbol) + if _, err = f.WriteString(pe); err != nil { + return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err) + } + + return nil +} + +// randomGroup generates a pseudorandom string for use as a tracefs group name. +// Returns an error when the output string would exceed 63 characters (kernel +// limitation), when rand.Read() fails or when prefix contains characters not +// allowed by rgxTraceEvent. +func randomGroup(prefix string) (string, error) { + if !rgxTraceEvent.MatchString(prefix) { + return "", fmt.Errorf("prefix '%s' must be alphanumeric or underscore: %w", prefix, errInvalidInput) + } + + b := make([]byte, 8) + if _, err := rand.Read(b); err != nil { + return "", fmt.Errorf("reading random bytes: %w", err) + } + + group := fmt.Sprintf("%s_%x", prefix, b) + if len(group) > 63 { + return "", fmt.Errorf("group name '%s' cannot be longer than 63 characters: %w", group, errInvalidInput) + } + + return group, nil +} + +func probePrefix(ret bool) string { + if ret { + return "r" + } + return "p" +} + +// determineRetprobeBit reads a Performance Monitoring Unit's retprobe bit +// from /sys/bus/event_source/devices//format/retprobe. +func determineRetprobeBit(typ probeType) (uint64, error) { + p := filepath.Join("/sys/bus/event_source/devices/", typ.String(), "/format/retprobe") + + data, err := ioutil.ReadFile(p) + if err != nil { + return 0, err + } + + var rp uint64 + n, err := fmt.Sscanf(string(bytes.TrimSpace(data)), "config:%d", &rp) + if err != nil { + return 0, fmt.Errorf("parse retprobe bit: %w", err) + } + if n != 1 { + return 0, fmt.Errorf("parse retprobe bit: expected 1 item, got %d", n) + } + + return rp, nil +} + +func kretprobeBit() (uint64, error) { + kprobeRetprobeBit.once.Do(func() { + kprobeRetprobeBit.value, kprobeRetprobeBit.err = determineRetprobeBit(kprobeType) + }) + return kprobeRetprobeBit.value, kprobeRetprobeBit.err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/link.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/link.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/link.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/link.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,229 @@ +package link + +import ( + "fmt" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" +) + +var ErrNotSupported = internal.ErrNotSupported + +// Link represents a Program attached to a BPF hook. +type Link interface { + // Replace the current program with a new program. + // + // Passing a nil program is an error. May return an error wrapping ErrNotSupported. + Update(*ebpf.Program) error + + // Persist a link by pinning it into a bpffs. + // + // May return an error wrapping ErrNotSupported. + Pin(string) error + + // Undo a previous call to Pin. + // + // May return an error wrapping ErrNotSupported. + Unpin() error + + // Close frees resources. + // + // The link will be broken unless it has been pinned. A link + // may continue past the lifetime of the process if Close is + // not called. + Close() error + + // Prevent external users from implementing this interface. + isLink() +} + +// ID uniquely identifies a BPF link. +type ID uint32 + +// RawLinkOptions control the creation of a raw link. +type RawLinkOptions struct { + // File descriptor to attach to. This differs for each attach type. + Target int + // Program to attach. + Program *ebpf.Program + // Attach must match the attach type of Program. + Attach ebpf.AttachType +} + +// RawLinkInfo contains metadata on a link. +type RawLinkInfo struct { + Type Type + ID ID + Program ebpf.ProgramID +} + +// RawLink is the low-level API to bpf_link. +// +// You should consider using the higher level interfaces in this +// package instead. +type RawLink struct { + fd *internal.FD + pinnedPath string +} + +// AttachRawLink creates a raw link. +func AttachRawLink(opts RawLinkOptions) (*RawLink, error) { + if err := haveBPFLink(); err != nil { + return nil, err + } + + if opts.Target < 0 { + return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd) + } + + progFd := opts.Program.FD() + if progFd < 0 { + return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd) + } + + attr := bpfLinkCreateAttr{ + targetFd: uint32(opts.Target), + progFd: uint32(progFd), + attachType: opts.Attach, + } + fd, err := bpfLinkCreate(&attr) + if err != nil { + return nil, fmt.Errorf("can't create link: %s", err) + } + + return &RawLink{fd, ""}, nil +} + +// LoadPinnedRawLink loads a persisted link from a bpffs. +// +// Returns an error if the pinned link type doesn't match linkType. Pass +// UnspecifiedType to disable this behaviour. +func LoadPinnedRawLink(fileName string, linkType Type, opts *ebpf.LoadPinOptions) (*RawLink, error) { + fd, err := internal.BPFObjGet(fileName, opts.Marshal()) + if err != nil { + return nil, fmt.Errorf("load pinned link: %w", err) + } + + link := &RawLink{fd, fileName} + if linkType == UnspecifiedType { + return link, nil + } + + info, err := link.Info() + if err != nil { + link.Close() + return nil, fmt.Errorf("get pinned link info: %s", err) + } + + if info.Type != linkType { + link.Close() + return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, linkType) + } + + return link, nil +} + +func (l *RawLink) isLink() {} + +// FD returns the raw file descriptor. +func (l *RawLink) FD() int { + fd, err := l.fd.Value() + if err != nil { + return -1 + } + return int(fd) +} + +// Close breaks the link. +// +// Use Pin if you want to make the link persistent. +func (l *RawLink) Close() error { + return l.fd.Close() +} + +// Pin persists a link past the lifetime of the process. +// +// Calling Close on a pinned Link will not break the link +// until the pin is removed. +func (l *RawLink) Pin(fileName string) error { + if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil { + return err + } + l.pinnedPath = fileName + return nil +} + +// Unpin implements the Link interface. +func (l *RawLink) Unpin() error { + if err := internal.Unpin(l.pinnedPath); err != nil { + return err + } + l.pinnedPath = "" + return nil +} + +// Update implements the Link interface. +func (l *RawLink) Update(new *ebpf.Program) error { + return l.UpdateArgs(RawLinkUpdateOptions{ + New: new, + }) +} + +// RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs. +type RawLinkUpdateOptions struct { + New *ebpf.Program + Old *ebpf.Program + Flags uint32 +} + +// UpdateArgs updates a link based on args. +func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error { + newFd := opts.New.FD() + if newFd < 0 { + return fmt.Errorf("invalid program: %s", internal.ErrClosedFd) + } + + var oldFd int + if opts.Old != nil { + oldFd = opts.Old.FD() + if oldFd < 0 { + return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd) + } + } + + linkFd, err := l.fd.Value() + if err != nil { + return fmt.Errorf("can't update link: %s", err) + } + + attr := bpfLinkUpdateAttr{ + linkFd: linkFd, + newProgFd: uint32(newFd), + oldProgFd: uint32(oldFd), + flags: opts.Flags, + } + return bpfLinkUpdate(&attr) +} + +// struct bpf_link_info +type bpfLinkInfo struct { + typ uint32 + id uint32 + prog_id uint32 +} + +// Info returns metadata about the link. +func (l *RawLink) Info() (*RawLinkInfo, error) { + var info bpfLinkInfo + err := internal.BPFObjGetInfoByFD(l.fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) + if err != nil { + return nil, fmt.Errorf("link info: %s", err) + } + + return &RawLinkInfo{ + Type(info.typ), + ID(info.id), + ebpf.ProgramID(info.prog_id), + }, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/netns.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/netns.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/netns.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/netns.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" +) + +// NetNsInfo contains metadata about a network namespace link. +type NetNsInfo struct { + RawLinkInfo +} + +// NetNsLink is a program attached to a network namespace. +type NetNsLink struct { + *RawLink +} + +// AttachNetNs attaches a program to a network namespace. +func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) { + var attach ebpf.AttachType + switch t := prog.Type(); t { + case ebpf.FlowDissector: + attach = ebpf.AttachFlowDissector + case ebpf.SkLookup: + attach = ebpf.AttachSkLookup + default: + return nil, fmt.Errorf("can't attach %v to network namespace", t) + } + + link, err := AttachRawLink(RawLinkOptions{ + Target: ns, + Program: prog, + Attach: attach, + }) + if err != nil { + return nil, err + } + + return &NetNsLink{link}, nil +} + +// LoadPinnedNetNs loads a network namespace link from bpffs. +func LoadPinnedNetNs(fileName string, opts *ebpf.LoadPinOptions) (*NetNsLink, error) { + link, err := LoadPinnedRawLink(fileName, NetNsType, opts) + if err != nil { + return nil, err + } + + return &NetNsLink{link}, nil +} + +// Info returns information about the link. +func (nns *NetNsLink) Info() (*NetNsInfo, error) { + info, err := nns.RawLink.Info() + if err != nil { + return nil, err + } + return &NetNsInfo{*info}, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/perf_event.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/perf_event.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/perf_event.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/perf_event.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,273 @@ +package link + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/unix" +) + +// Getting the terminology right is usually the hardest part. For posterity and +// for staying sane during implementation: +// +// - trace event: Representation of a kernel runtime hook. Filesystem entries +// under /events. Can be tracepoints (static), kprobes or uprobes. +// Can be instantiated into perf events (see below). +// - tracepoint: A predetermined hook point in the kernel. Exposed as trace +// events in (sub)directories under /events. Cannot be closed or +// removed, they are static. +// - k(ret)probe: Ephemeral trace events based on entry or exit points of +// exported kernel symbols. kprobe-based (tracefs) trace events can be +// created system-wide by writing to the /kprobe_events file, or +// they can be scoped to the current process by creating PMU perf events. +// - u(ret)probe: Ephemeral trace events based on user provides ELF binaries +// and offsets. uprobe-based (tracefs) trace events can be +// created system-wide by writing to the /uprobe_events file, or +// they can be scoped to the current process by creating PMU perf events. +// - perf event: An object instantiated based on an existing trace event or +// kernel symbol. Referred to by fd in userspace. +// Exactly one eBPF program can be attached to a perf event. Multiple perf +// events can be created from a single trace event. Closing a perf event +// stops any further invocations of the attached eBPF program. + +var ( + tracefsPath = "/sys/kernel/debug/tracing" + + // Trace event groups, names and kernel symbols must adhere to this set + // of characters. Non-empty, first character must not be a number, all + // characters must be alphanumeric or underscore. + rgxTraceEvent = regexp.MustCompile("^[a-zA-Z_][0-9a-zA-Z_]*$") + + errInvalidInput = errors.New("invalid input") +) + +const ( + perfAllThreads = -1 +) + +type perfEventType uint8 + +const ( + tracepointEvent perfEventType = iota + kprobeEvent + kretprobeEvent + uprobeEvent + uretprobeEvent +) + +// A perfEvent represents a perf event kernel object. Exactly one eBPF program +// can be attached to it. It is created based on a tracefs trace event or a +// Performance Monitoring Unit (PMU). +type perfEvent struct { + + // Group and name of the tracepoint/kprobe/uprobe. + group string + name string + + // PMU event ID read from sysfs. Valid IDs are non-zero. + pmuID uint64 + // ID of the trace event read from tracefs. Valid IDs are non-zero. + tracefsID uint64 + + // The event type determines the types of programs that can be attached. + typ perfEventType + + fd *internal.FD +} + +func (pe *perfEvent) isLink() {} + +func (pe *perfEvent) Pin(string) error { + return fmt.Errorf("pin perf event: %w", ErrNotSupported) +} + +func (pe *perfEvent) Unpin() error { + return fmt.Errorf("unpin perf event: %w", ErrNotSupported) +} + +// Since 4.15 (e87c6bc3852b "bpf: permit multiple bpf attachments for a single perf event"), +// calling PERF_EVENT_IOC_SET_BPF appends the given program to a prog_array +// owned by the perf event, which means multiple programs can be attached +// simultaneously. +// +// Before 4.15, calling PERF_EVENT_IOC_SET_BPF more than once on a perf event +// returns EEXIST. +// +// Detaching a program from a perf event is currently not possible, so a +// program replacement mechanism cannot be implemented for perf events. +func (pe *perfEvent) Update(prog *ebpf.Program) error { + return fmt.Errorf("can't replace eBPF program in perf event: %w", ErrNotSupported) +} + +func (pe *perfEvent) Close() error { + if pe.fd == nil { + return nil + } + + pfd, err := pe.fd.Value() + if err != nil { + return fmt.Errorf("getting perf event fd: %w", err) + } + + err = unix.IoctlSetInt(int(pfd), unix.PERF_EVENT_IOC_DISABLE, 0) + if err != nil { + return fmt.Errorf("disabling perf event: %w", err) + } + + err = pe.fd.Close() + if err != nil { + return fmt.Errorf("closing perf event fd: %w", err) + } + + switch pe.typ { + case kprobeEvent, kretprobeEvent: + // Clean up kprobe tracefs entry. + if pe.tracefsID != 0 { + return closeTraceFSProbeEvent(kprobeType, pe.group, pe.name) + } + case uprobeEvent, uretprobeEvent: + // Clean up uprobe tracefs entry. + if pe.tracefsID != 0 { + return closeTraceFSProbeEvent(uprobeType, pe.group, pe.name) + } + case tracepointEvent: + // Tracepoint trace events don't hold any extra resources. + return nil + } + + return nil +} + +// attach the given eBPF prog to the perf event stored in pe. +// pe must contain a valid perf event fd. +// prog's type must match the program type stored in pe. +func (pe *perfEvent) attach(prog *ebpf.Program) error { + if prog == nil { + return errors.New("cannot attach a nil program") + } + if pe.fd == nil { + return errors.New("cannot attach to nil perf event") + } + if prog.FD() < 0 { + return fmt.Errorf("invalid program: %w", internal.ErrClosedFd) + } + switch pe.typ { + case kprobeEvent, kretprobeEvent, uprobeEvent, uretprobeEvent: + if t := prog.Type(); t != ebpf.Kprobe { + return fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t) + } + case tracepointEvent: + if t := prog.Type(); t != ebpf.TracePoint { + return fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t) + } + default: + return fmt.Errorf("unknown perf event type: %d", pe.typ) + } + + // The ioctl below will fail when the fd is invalid. + kfd, _ := pe.fd.Value() + + // Assign the eBPF program to the perf event. + err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_SET_BPF, prog.FD()) + if err != nil { + return fmt.Errorf("setting perf event bpf program: %w", err) + } + + // PERF_EVENT_IOC_ENABLE and _DISABLE ignore their given values. + if err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_ENABLE, 0); err != nil { + return fmt.Errorf("enable perf event: %s", err) + } + + // Close the perf event when its reference is lost to avoid leaking system resources. + runtime.SetFinalizer(pe, (*perfEvent).Close) + return nil +} + +// unsafeStringPtr returns an unsafe.Pointer to a NUL-terminated copy of str. +func unsafeStringPtr(str string) (unsafe.Pointer, error) { + p, err := unix.BytePtrFromString(str) + if err != nil { + return nil, err + } + return unsafe.Pointer(p), nil +} + +// getTraceEventID reads a trace event's ID from tracefs given its group and name. +// group and name must be alphanumeric or underscore, as required by the kernel. +func getTraceEventID(group, name string) (uint64, error) { + tid, err := uint64FromFile(tracefsPath, "events", group, name, "id") + if errors.Is(err, os.ErrNotExist) { + return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist) + } + if err != nil { + return 0, fmt.Errorf("reading trace event ID of %s/%s: %w", group, name, err) + } + + return tid, nil +} + +// getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier) +// from /sys/bus/event_source/devices//type. +// +// Returns ErrNotSupported if the pmu type is not supported. +func getPMUEventType(typ probeType) (uint64, error) { + et, err := uint64FromFile("/sys/bus/event_source/devices", typ.String(), "type") + if errors.Is(err, os.ErrNotExist) { + return 0, fmt.Errorf("pmu type %s: %w", typ, ErrNotSupported) + } + if err != nil { + return 0, fmt.Errorf("reading pmu type %s: %w", typ, err) + } + + return et, nil +} + +// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide +// [k,u]probes created by writing to /[k,u]probe_events are tracepoints +// behind the scenes, and can be attached to using these perf events. +func openTracepointPerfEvent(tid uint64) (*internal.FD, error) { + attr := unix.PerfEventAttr{ + Type: unix.PERF_TYPE_TRACEPOINT, + Config: tid, + Sample_type: unix.PERF_SAMPLE_RAW, + Sample: 1, + Wakeup: 1, + } + + fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + if err != nil { + return nil, fmt.Errorf("opening tracepoint perf event: %w", err) + } + + return internal.NewFD(uint32(fd)), nil +} + +// uint64FromFile reads a uint64 from a file. All elements of path are sanitized +// and joined onto base. Returns error if base no longer prefixes the path after +// joining all components. +func uint64FromFile(base string, path ...string) (uint64, error) { + l := filepath.Join(path...) + p := filepath.Join(base, l) + if !strings.HasPrefix(p, base) { + return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput) + } + + data, err := ioutil.ReadFile(p) + if err != nil { + return 0, fmt.Errorf("reading file %s: %w", p, err) + } + + et := bytes.TrimSpace(data) + return strconv.ParseUint(string(et), 10, 64) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/platform.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/platform.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/platform.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/platform.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +package link + +import ( + "fmt" + "runtime" +) + +func platformPrefix(symbol string) string { + + prefix := runtime.GOARCH + + // per https://github.com/golang/go/blob/master/src/go/build/syslist.go + switch prefix { + case "386": + prefix = "ia32" + case "amd64", "amd64p32": + prefix = "x64" + case "arm64", "arm64be": + prefix = "arm64" + default: + return symbol + } + + return fmt.Sprintf("__%s_%s", prefix, symbol) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/program.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/program.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/program.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/program.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,76 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" +) + +type RawAttachProgramOptions struct { + // File descriptor to attach to. This differs for each attach type. + Target int + // Program to attach. + Program *ebpf.Program + // Program to replace (cgroups). + Replace *ebpf.Program + // Attach must match the attach type of Program (and Replace). + Attach ebpf.AttachType + // Flags control the attach behaviour. This differs for each attach type. + Flags uint32 +} + +// RawAttachProgram is a low level wrapper around BPF_PROG_ATTACH. +// +// You should use one of the higher level abstractions available in this +// package if possible. +func RawAttachProgram(opts RawAttachProgramOptions) error { + if err := haveProgAttach(); err != nil { + return err + } + + var replaceFd uint32 + if opts.Replace != nil { + replaceFd = uint32(opts.Replace.FD()) + } + + attr := internal.BPFProgAttachAttr{ + TargetFd: uint32(opts.Target), + AttachBpfFd: uint32(opts.Program.FD()), + ReplaceBpfFd: replaceFd, + AttachType: uint32(opts.Attach), + AttachFlags: uint32(opts.Flags), + } + + if err := internal.BPFProgAttach(&attr); err != nil { + return fmt.Errorf("can't attach program: %w", err) + } + return nil +} + +type RawDetachProgramOptions struct { + Target int + Program *ebpf.Program + Attach ebpf.AttachType +} + +// RawDetachProgram is a low level wrapper around BPF_PROG_DETACH. +// +// You should use one of the higher level abstractions available in this +// package if possible. +func RawDetachProgram(opts RawDetachProgramOptions) error { + if err := haveProgAttach(); err != nil { + return err + } + + attr := internal.BPFProgDetachAttr{ + TargetFd: uint32(opts.Target), + AttachBpfFd: uint32(opts.Program.FD()), + AttachType: uint32(opts.Attach), + } + if err := internal.BPFProgDetach(&attr); err != nil { + return fmt.Errorf("can't detach program: %w", err) + } + + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,61 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" +) + +type RawTracepointOptions struct { + // Tracepoint name. + Name string + // Program must be of type RawTracepoint* + Program *ebpf.Program +} + +// AttachRawTracepoint links a BPF program to a raw_tracepoint. +// +// Requires at least Linux 4.17. +func AttachRawTracepoint(opts RawTracepointOptions) (Link, error) { + if t := opts.Program.Type(); t != ebpf.RawTracepoint && t != ebpf.RawTracepointWritable { + return nil, fmt.Errorf("invalid program type %s, expected RawTracepoint(Writable)", t) + } + if opts.Program.FD() < 0 { + return nil, fmt.Errorf("invalid program: %w", internal.ErrClosedFd) + } + + fd, err := bpfRawTracepointOpen(&bpfRawTracepointOpenAttr{ + name: internal.NewStringPointer(opts.Name), + fd: uint32(opts.Program.FD()), + }) + if err != nil { + return nil, err + } + + return &progAttachRawTracepoint{fd: fd}, nil +} + +type progAttachRawTracepoint struct { + fd *internal.FD +} + +var _ Link = (*progAttachRawTracepoint)(nil) + +func (rt *progAttachRawTracepoint) isLink() {} + +func (rt *progAttachRawTracepoint) Close() error { + return rt.fd.Close() +} + +func (rt *progAttachRawTracepoint) Update(_ *ebpf.Program) error { + return fmt.Errorf("can't update raw_tracepoint: %w", ErrNotSupported) +} + +func (rt *progAttachRawTracepoint) Pin(_ string) error { + return fmt.Errorf("can't pin raw_tracepoint: %w", ErrNotSupported) +} + +func (rt *progAttachRawTracepoint) Unpin() error { + return fmt.Errorf("unpin raw_tracepoint: %w", ErrNotSupported) +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/syscalls.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/syscalls.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/syscalls.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/syscalls.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,190 @@ +package link + +import ( + "errors" + "unsafe" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/unix" +) + +// Type is the kind of link. +type Type uint32 + +// Valid link types. +// +// Equivalent to enum bpf_link_type. +const ( + UnspecifiedType Type = iota + RawTracepointType + TracingType + CgroupType + IterType + NetNsType + XDPType +) + +var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() error { + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Type: ebpf.CGroupSKB, + AttachType: ebpf.AttachCGroupInetIngress, + License: "MIT", + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + }) + if err != nil { + return internal.ErrNotSupported + } + + // BPF_PROG_ATTACH was introduced at the same time as CGgroupSKB, + // so being able to load the program is enough to infer that we + // have the syscall. + prog.Close() + return nil +}) + +var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replacement", "5.5", func() error { + if err := haveProgAttach(); err != nil { + return err + } + + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Type: ebpf.CGroupSKB, + AttachType: ebpf.AttachCGroupInetIngress, + License: "MIT", + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + }) + if err != nil { + return internal.ErrNotSupported + } + defer prog.Close() + + // We know that we have BPF_PROG_ATTACH since we can load CGroupSKB programs. + // If passing BPF_F_REPLACE gives us EINVAL we know that the feature isn't + // present. + attr := internal.BPFProgAttachAttr{ + // We rely on this being checked after attachFlags. + TargetFd: ^uint32(0), + AttachBpfFd: uint32(prog.FD()), + AttachType: uint32(ebpf.AttachCGroupInetIngress), + AttachFlags: uint32(flagReplace), + } + + err = internal.BPFProgAttach(&attr) + if errors.Is(err, unix.EINVAL) { + return internal.ErrNotSupported + } + if errors.Is(err, unix.EBADF) { + return nil + } + return err +}) + +type bpfLinkCreateAttr struct { + progFd uint32 + targetFd uint32 + attachType ebpf.AttachType + flags uint32 +} + +func bpfLinkCreate(attr *bpfLinkCreateAttr) (*internal.FD, error) { + ptr, err := internal.BPF(internal.BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + return internal.NewFD(uint32(ptr)), nil +} + +type bpfLinkCreateIterAttr struct { + prog_fd uint32 + target_fd uint32 + attach_type ebpf.AttachType + flags uint32 + iter_info internal.Pointer + iter_info_len uint32 +} + +func bpfLinkCreateIter(attr *bpfLinkCreateIterAttr) (*internal.FD, error) { + ptr, err := internal.BPF(internal.BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err != nil { + return nil, err + } + return internal.NewFD(uint32(ptr)), nil +} + +type bpfLinkUpdateAttr struct { + linkFd uint32 + newProgFd uint32 + flags uint32 + oldProgFd uint32 +} + +func bpfLinkUpdate(attr *bpfLinkUpdateAttr) error { + _, err := internal.BPF(internal.BPF_LINK_UPDATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +var haveBPFLink = internal.FeatureTest("bpf_link", "5.7", func() error { + prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ + Type: ebpf.CGroupSKB, + AttachType: ebpf.AttachCGroupInetIngress, + License: "MIT", + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + }) + if err != nil { + return internal.ErrNotSupported + } + defer prog.Close() + + attr := bpfLinkCreateAttr{ + // This is a hopefully invalid file descriptor, which triggers EBADF. + targetFd: ^uint32(0), + progFd: uint32(prog.FD()), + attachType: ebpf.AttachCGroupInetIngress, + } + _, err = bpfLinkCreate(&attr) + if errors.Is(err, unix.EINVAL) { + return internal.ErrNotSupported + } + if errors.Is(err, unix.EBADF) { + return nil + } + return err +}) + +type bpfIterCreateAttr struct { + linkFd uint32 + flags uint32 +} + +func bpfIterCreate(attr *bpfIterCreateAttr) (*internal.FD, error) { + ptr, err := internal.BPF(internal.BPF_ITER_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err == nil { + return internal.NewFD(uint32(ptr)), nil + } + return nil, err +} + +type bpfRawTracepointOpenAttr struct { + name internal.Pointer + fd uint32 + _ uint32 +} + +func bpfRawTracepointOpen(attr *bpfRawTracepointOpenAttr) (*internal.FD, error) { + ptr, err := internal.BPF(internal.BPF_RAW_TRACEPOINT_OPEN, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + if err == nil { + return internal.NewFD(uint32(ptr)), nil + } + return nil, err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/tracepoint.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/tracepoint.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/tracepoint.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/tracepoint.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +package link + +import ( + "fmt" + + "github.com/cilium/ebpf" +) + +// Tracepoint attaches the given eBPF program to the tracepoint with the given +// group and name. See /sys/kernel/debug/tracing/events to find available +// tracepoints. The top-level directory is the group, the event's subdirectory +// is the name. Example: +// +// Tracepoint("syscalls", "sys_enter_fork", prog) +// +// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is +// only possible as of kernel 4.14 (commit cf5f5ce). +func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) { + if group == "" || name == "" { + return nil, fmt.Errorf("group and name cannot be empty: %w", errInvalidInput) + } + if prog == nil { + return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput) + } + if !rgxTraceEvent.MatchString(group) || !rgxTraceEvent.MatchString(name) { + return nil, fmt.Errorf("group and name '%s/%s' must be alphanumeric or underscore: %w", group, name, errInvalidInput) + } + if prog.Type() != ebpf.TracePoint { + return nil, fmt.Errorf("eBPF program type %s is not a Tracepoint: %w", prog.Type(), errInvalidInput) + } + + tid, err := getTraceEventID(group, name) + if err != nil { + return nil, err + } + + fd, err := openTracepointPerfEvent(tid) + if err != nil { + return nil, err + } + + pe := &perfEvent{ + fd: fd, + tracefsID: tid, + group: group, + name: name, + typ: tracepointEvent, + } + + if err := pe.attach(prog); err != nil { + pe.Close() + return nil, err + } + + return pe, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/link/uprobe.go containerd-1.5.9/vendor/github.com/cilium/ebpf/link/uprobe.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/link/uprobe.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/link/uprobe.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,237 @@ +package link + +import ( + "debug/elf" + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "sync" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal" +) + +var ( + uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events") + + // rgxUprobeSymbol is used to strip invalid characters from the uprobe symbol + // as they are not allowed to be used as the EVENT token in tracefs. + rgxUprobeSymbol = regexp.MustCompile("[^a-zA-Z0-9]+") + + uprobeRetprobeBit = struct { + once sync.Once + value uint64 + err error + }{} +) + +// Executable defines an executable program on the filesystem. +type Executable struct { + // Path of the executable on the filesystem. + path string + // Parsed ELF symbols and dynamic symbols. + symbols map[string]elf.Symbol +} + +// UprobeOptions defines additional parameters that will be used +// when loading Uprobes. +type UprobeOptions struct { + // Symbol offset. Must be provided in case of external symbols (shared libs). + // If set, overrides the offset eventually parsed from the executable. + Offset uint64 +} + +// To open a new Executable, use: +// +// OpenExecutable("/bin/bash") +// +// The returned value can then be used to open Uprobe(s). +func OpenExecutable(path string) (*Executable, error) { + if path == "" { + return nil, fmt.Errorf("path cannot be empty") + } + + f, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("open file '%s': %w", path, err) + } + defer f.Close() + + se, err := internal.NewSafeELFFile(f) + if err != nil { + return nil, fmt.Errorf("parse ELF file: %w", err) + } + + var ex = Executable{ + path: path, + symbols: make(map[string]elf.Symbol), + } + if err := ex.addSymbols(se.Symbols); err != nil { + return nil, err + } + + if err := ex.addSymbols(se.DynamicSymbols); err != nil { + return nil, err + } + + return &ex, nil +} + +func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error { + // elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found. + syms, err := f() + if err != nil && !errors.Is(err, elf.ErrNoSymbols) { + return err + } + for _, s := range syms { + if elf.ST_TYPE(s.Info) != elf.STT_FUNC { + // Symbol not associated with a function or other executable code. + continue + } + ex.symbols[s.Name] = s + } + return nil +} + +func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) { + if s, ok := ex.symbols[symbol]; ok { + return &s, nil + } + return nil, fmt.Errorf("symbol %s not found", symbol) +} + +// Uprobe attaches the given eBPF program to a perf event that fires when the +// given symbol starts executing in the given Executable. +// For example, /bin/bash::main(): +// +// ex, _ = OpenExecutable("/bin/bash") +// ex.Uprobe("main", prog, nil) +// +// When using symbols which belongs to shared libraries, +// an offset must be provided via options: +// +// ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// +// The resulting Link must be Closed during program shutdown to avoid leaking +// system resources. Functions provided by shared libraries can currently not +// be traced and will result in an ErrNotSupported. +func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { + u, err := ex.uprobe(symbol, prog, opts, false) + if err != nil { + return nil, err + } + + err = u.attach(prog) + if err != nil { + u.Close() + return nil, err + } + + return u, nil +} + +// Uretprobe attaches the given eBPF program to a perf event that fires right +// before the given symbol exits. For example, /bin/bash::main(): +// +// ex, _ = OpenExecutable("/bin/bash") +// ex.Uretprobe("main", prog, nil) +// +// When using symbols which belongs to shared libraries, +// an offset must be provided via options: +// +// ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123}) +// +// The resulting Link must be Closed during program shutdown to avoid leaking +// system resources. Functions provided by shared libraries can currently not +// be traced and will result in an ErrNotSupported. +func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { + u, err := ex.uprobe(symbol, prog, opts, true) + if err != nil { + return nil, err + } + + err = u.attach(prog) + if err != nil { + u.Close() + return nil, err + } + + return u, nil +} + +// uprobe opens a perf event for the given binary/symbol and attaches prog to it. +// If ret is true, create a uretprobe. +func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions, ret bool) (*perfEvent, error) { + if prog == nil { + return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput) + } + if prog.Type() != ebpf.Kprobe { + return nil, fmt.Errorf("eBPF program type %s is not Kprobe: %w", prog.Type(), errInvalidInput) + } + + var offset uint64 + if opts != nil && opts.Offset != 0 { + offset = opts.Offset + } else { + sym, err := ex.symbol(symbol) + if err != nil { + return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, err) + } + + // Symbols with location 0 from section undef are shared library calls and + // are relocated before the binary is executed. Dynamic linking is not + // implemented by the library, so mark this as unsupported for now. + if sym.Section == elf.SHN_UNDEF && sym.Value == 0 { + return nil, fmt.Errorf("cannot resolve %s library call '%s', "+ + "consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported) + } + + offset = sym.Value + } + + // Use uprobe PMU if the kernel has it available. + tp, err := pmuUprobe(symbol, ex.path, offset, ret) + if err == nil { + return tp, nil + } + if err != nil && !errors.Is(err, ErrNotSupported) { + return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err) + } + + // Use tracefs if uprobe PMU is missing. + tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, ret) + if err != nil { + return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err) + } + + return tp, nil +} + +// pmuUprobe opens a perf event based on the uprobe PMU. +func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { + return pmuProbe(uprobeType, symbol, path, offset, ret) +} + +// tracefsUprobe creates a Uprobe tracefs entry. +func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) { + return tracefsProbe(uprobeType, symbol, path, offset, ret) +} + +// uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore. +func uprobeSanitizedSymbol(symbol string) string { + return rgxUprobeSymbol.ReplaceAllString(symbol, "_") +} + +// uprobePathOffset creates the PATH:OFFSET token for the tracefs api. +func uprobePathOffset(path string, offset uint64) string { + return fmt.Sprintf("%s:%#x", path, offset) +} + +func uretprobeBit() (uint64, error) { + uprobeRetprobeBit.once.Do(func() { + uprobeRetprobeBit.value, uprobeRetprobeBit.err = determineRetprobeBit(uprobeType) + }) + return uprobeRetprobeBit.value, uprobeRetprobeBit.err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/linker.go containerd-1.5.9/vendor/github.com/cilium/ebpf/linker.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/linker.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/linker.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,140 @@ +package ebpf + +import ( + "fmt" + + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal/btf" +) + +// link resolves bpf-to-bpf calls. +// +// Each library may contain multiple functions / labels, and is only linked +// if prog references one of these functions. +// +// Libraries also linked. +func link(prog *ProgramSpec, libs []*ProgramSpec) error { + var ( + linked = make(map[*ProgramSpec]bool) + pending = []asm.Instructions{prog.Instructions} + insns asm.Instructions + ) + for len(pending) > 0 { + insns, pending = pending[0], pending[1:] + for _, lib := range libs { + if linked[lib] { + continue + } + + needed, err := needSection(insns, lib.Instructions) + if err != nil { + return fmt.Errorf("linking %s: %w", lib.Name, err) + } + + if !needed { + continue + } + + linked[lib] = true + prog.Instructions = append(prog.Instructions, lib.Instructions...) + pending = append(pending, lib.Instructions) + + if prog.BTF != nil && lib.BTF != nil { + if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil { + return fmt.Errorf("linking BTF of %s: %w", lib.Name, err) + } + } + } + } + + return nil +} + +func needSection(insns, section asm.Instructions) (bool, error) { + // A map of symbols to the libraries which contain them. + symbols, err := section.SymbolOffsets() + if err != nil { + return false, err + } + + for _, ins := range insns { + if ins.Reference == "" { + continue + } + + if ins.OpCode.JumpOp() != asm.Call || ins.Src != asm.PseudoCall { + continue + } + + if ins.Constant != -1 { + // This is already a valid call, no need to link again. + continue + } + + if _, ok := symbols[ins.Reference]; !ok { + // Symbol isn't available in this section + continue + } + + // At this point we know that at least one function in the + // library is called from insns, so we have to link it. + return true, nil + } + + // None of the functions in the section are called. + return false, nil +} + +func fixupJumpsAndCalls(insns asm.Instructions) error { + symbolOffsets := make(map[string]asm.RawInstructionOffset) + iter := insns.Iterate() + for iter.Next() { + ins := iter.Ins + + if ins.Symbol == "" { + continue + } + + if _, ok := symbolOffsets[ins.Symbol]; ok { + return fmt.Errorf("duplicate symbol %s", ins.Symbol) + } + + symbolOffsets[ins.Symbol] = iter.Offset + } + + iter = insns.Iterate() + for iter.Next() { + i := iter.Index + offset := iter.Offset + ins := iter.Ins + + if ins.Reference == "" { + continue + } + + switch { + case ins.IsFunctionCall() && ins.Constant == -1: + // Rewrite bpf to bpf call + callOffset, ok := symbolOffsets[ins.Reference] + if !ok { + return fmt.Errorf("call at %d: reference to missing symbol %q", i, ins.Reference) + } + + ins.Constant = int64(callOffset - offset - 1) + + case ins.OpCode.Class() == asm.JumpClass && ins.Offset == -1: + // Rewrite jump to label + jumpOffset, ok := symbolOffsets[ins.Reference] + if !ok { + return fmt.Errorf("jump at %d: reference to missing symbol %q", i, ins.Reference) + } + + ins.Offset = int16(jumpOffset - offset - 1) + + case ins.IsLoadFromMap() && ins.MapPtr() == -1: + return fmt.Errorf("map %s: %w", ins.Reference, errUnsatisfiedReference) + } + } + + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/Makefile containerd-1.5.9/vendor/github.com/cilium/ebpf/Makefile --- containerd-1.2.6/vendor/github.com/cilium/ebpf/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,70 @@ +# The development version of clang is distributed as the 'clang' binary, +# while stable/released versions have a version number attached. +# Pin the default clang to a stable version. +CLANG ?= clang-12 +CFLAGS := -target bpf -O2 -g -Wall -Werror $(CFLAGS) + +# Obtain an absolute path to the directory of the Makefile. +# Assume the Makefile is in the root of the repository. +REPODIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +UIDGID := $(shell stat -c '%u:%g' ${REPODIR}) + +IMAGE := $(shell cat ${REPODIR}/testdata/docker/IMAGE) +VERSION := $(shell cat ${REPODIR}/testdata/docker/VERSION) + +# clang <8 doesn't tag relocs properly (STT_NOTYPE) +# clang 9 is the first version emitting BTF +TARGETS := \ + testdata/loader-clang-7 \ + testdata/loader-clang-9 \ + testdata/loader-$(CLANG) \ + testdata/invalid_map \ + testdata/raw_tracepoint \ + testdata/invalid_map_static \ + testdata/initialized_btf_map \ + testdata/strings \ + internal/btf/testdata/relocs + +.PHONY: all clean docker-all docker-shell + +.DEFAULT_TARGET = docker-all + +# Build all ELF binaries using a Dockerized LLVM toolchain. +docker-all: + docker run --rm --user "${UIDGID}" \ + -v "${REPODIR}":/ebpf -w /ebpf --env MAKEFLAGS \ + --env CFLAGS="-fdebug-prefix-map=/ebpf=." \ + "${IMAGE}:${VERSION}" \ + make all + +# (debug) Drop the user into a shell inside the Docker container as root. +docker-shell: + docker run --rm -ti \ + -v "${REPODIR}":/ebpf -w /ebpf \ + "${IMAGE}:${VERSION}" + +clean: + -$(RM) testdata/*.elf + -$(RM) internal/btf/testdata/*.elf + +all: $(addsuffix -el.elf,$(TARGETS)) $(addsuffix -eb.elf,$(TARGETS)) + ln -srf testdata/loader-$(CLANG)-el.elf testdata/loader-el.elf + ln -srf testdata/loader-$(CLANG)-eb.elf testdata/loader-eb.elf + +testdata/loader-%-el.elf: testdata/loader.c + $* $(CFLAGS) -mlittle-endian -c $< -o $@ + +testdata/loader-%-eb.elf: testdata/loader.c + $* $(CFLAGS) -mbig-endian -c $< -o $@ + +%-el.elf: %.c + $(CLANG) $(CFLAGS) -mlittle-endian -c $< -o $@ + +%-eb.elf : %.c + $(CLANG) $(CFLAGS) -mbig-endian -c $< -o $@ + +# Usage: make VMLINUX=/path/to/vmlinux vmlinux-btf +.PHONY: vmlinux-btf +vmlinux-btf: internal/btf/testdata/vmlinux-btf.gz +internal/btf/testdata/vmlinux-btf.gz: $(VMLINUX) + objcopy --dump-section .BTF=/dev/stdout "$<" /dev/null | gzip > "$@" diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/map.go containerd-1.5.9/vendor/github.com/cilium/ebpf/map.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/map.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/map.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,1232 @@ +package ebpf + +import ( + "errors" + "fmt" + "io" + "path/filepath" + "reflect" + "strings" + + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" + "github.com/cilium/ebpf/internal/unix" +) + +// Errors returned by Map and MapIterator methods. +var ( + ErrKeyNotExist = errors.New("key does not exist") + ErrKeyExist = errors.New("key already exists") + ErrIterationAborted = errors.New("iteration aborted") + ErrMapIncompatible = errors.New("map's spec is incompatible with pinned map") +) + +// MapOptions control loading a map into the kernel. +type MapOptions struct { + // The base path to pin maps in if requested via PinByName. + // Existing maps will be re-used if they are compatible, otherwise an + // error is returned. + PinPath string + LoadPinOptions LoadPinOptions +} + +// MapID represents the unique ID of an eBPF map +type MapID uint32 + +// MapSpec defines a Map. +type MapSpec struct { + // Name is passed to the kernel as a debug aid. Must only contain + // alpha numeric and '_' characters. + Name string + Type MapType + KeySize uint32 + ValueSize uint32 + MaxEntries uint32 + + // Flags is passed to the kernel and specifies additional map + // creation attributes. + Flags uint32 + + // Automatically pin and load a map from MapOptions.PinPath. + // Generates an error if an existing pinned map is incompatible with the MapSpec. + Pinning PinType + + // Specify numa node during map creation + // (effective only if unix.BPF_F_NUMA_NODE flag is set, + // which can be imported from golang.org/x/sys/unix) + NumaNode uint32 + + // The initial contents of the map. May be nil. + Contents []MapKV + + // Whether to freeze a map after setting its initial contents. + Freeze bool + + // InnerMap is used as a template for ArrayOfMaps and HashOfMaps + InnerMap *MapSpec + + // The BTF associated with this map. + BTF *btf.Map +} + +func (ms *MapSpec) String() string { + return fmt.Sprintf("%s(keySize=%d, valueSize=%d, maxEntries=%d, flags=%d)", ms.Type, ms.KeySize, ms.ValueSize, ms.MaxEntries, ms.Flags) +} + +// Copy returns a copy of the spec. +// +// MapSpec.Contents is a shallow copy. +func (ms *MapSpec) Copy() *MapSpec { + if ms == nil { + return nil + } + + cpy := *ms + cpy.Contents = make([]MapKV, len(ms.Contents)) + copy(cpy.Contents, ms.Contents) + cpy.InnerMap = ms.InnerMap.Copy() + return &cpy +} + +func (ms *MapSpec) clampPerfEventArraySize() error { + if ms.Type != PerfEventArray { + return nil + } + + n, err := internal.PossibleCPUs() + if err != nil { + return fmt.Errorf("perf event array: %w", err) + } + + if n := uint32(n); ms.MaxEntries > n { + ms.MaxEntries = n + } + + return nil +} + +// MapKV is used to initialize the contents of a Map. +type MapKV struct { + Key interface{} + Value interface{} +} + +func (ms *MapSpec) checkCompatibility(m *Map) error { + switch { + case m.typ != ms.Type: + return fmt.Errorf("expected type %v, got %v: %w", ms.Type, m.typ, ErrMapIncompatible) + + case m.keySize != ms.KeySize: + return fmt.Errorf("expected key size %v, got %v: %w", ms.KeySize, m.keySize, ErrMapIncompatible) + + case m.valueSize != ms.ValueSize: + return fmt.Errorf("expected value size %v, got %v: %w", ms.ValueSize, m.valueSize, ErrMapIncompatible) + + case m.maxEntries != ms.MaxEntries: + return fmt.Errorf("expected max entries %v, got %v: %w", ms.MaxEntries, m.maxEntries, ErrMapIncompatible) + + case m.flags != ms.Flags: + return fmt.Errorf("expected flags %v, got %v: %w", ms.Flags, m.flags, ErrMapIncompatible) + } + return nil +} + +// Map represents a Map file descriptor. +// +// It is not safe to close a map which is used by other goroutines. +// +// Methods which take interface{} arguments by default encode +// them using binary.Read/Write in the machine's native endianness. +// +// Implement encoding.BinaryMarshaler or encoding.BinaryUnmarshaler +// if you require custom encoding. +type Map struct { + name string + fd *internal.FD + typ MapType + keySize uint32 + valueSize uint32 + maxEntries uint32 + flags uint32 + pinnedPath string + // Per CPU maps return values larger than the size in the spec + fullValueSize int +} + +// NewMapFromFD creates a map from a raw fd. +// +// You should not use fd after calling this function. +func NewMapFromFD(fd int) (*Map, error) { + if fd < 0 { + return nil, errors.New("invalid fd") + } + + return newMapFromFD(internal.NewFD(uint32(fd))) +} + +func newMapFromFD(fd *internal.FD) (*Map, error) { + info, err := newMapInfoFromFd(fd) + if err != nil { + fd.Close() + return nil, fmt.Errorf("get map info: %s", err) + } + + return newMap(fd, info.Name, info.Type, info.KeySize, info.ValueSize, info.MaxEntries, info.Flags) +} + +// NewMap creates a new Map. +// +// It's equivalent to calling NewMapWithOptions with default options. +func NewMap(spec *MapSpec) (*Map, error) { + return NewMapWithOptions(spec, MapOptions{}) +} + +// NewMapWithOptions creates a new Map. +// +// Creating a map for the first time will perform feature detection +// by creating small, temporary maps. +// +// The caller is responsible for ensuring the process' rlimit is set +// sufficiently high for locking memory during map creation. This can be done +// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions. +// +// May return an error wrapping ErrMapIncompatible. +func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { + handles := newHandleCache() + defer handles.close() + + return newMapWithOptions(spec, opts, handles) +} + +func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) { + closeOnError := func(c io.Closer) { + if err != nil { + c.Close() + } + } + + switch spec.Pinning { + case PinByName: + if spec.Name == "" || opts.PinPath == "" { + return nil, fmt.Errorf("pin by name: missing Name or PinPath") + } + + path := filepath.Join(opts.PinPath, spec.Name) + m, err := LoadPinnedMap(path, &opts.LoadPinOptions) + if errors.Is(err, unix.ENOENT) { + break + } + if err != nil { + return nil, fmt.Errorf("load pinned map: %w", err) + } + defer closeOnError(m) + + if err := spec.checkCompatibility(m); err != nil { + return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err) + } + + return m, nil + + case PinNone: + // Nothing to do here + + default: + return nil, fmt.Errorf("pin type %d: %w", int(spec.Pinning), ErrNotSupported) + } + + var innerFd *internal.FD + if spec.Type == ArrayOfMaps || spec.Type == HashOfMaps { + if spec.InnerMap == nil { + return nil, fmt.Errorf("%s requires InnerMap", spec.Type) + } + + if spec.InnerMap.Pinning != PinNone { + return nil, errors.New("inner maps cannot be pinned") + } + + template, err := createMap(spec.InnerMap, nil, opts, handles) + if err != nil { + return nil, err + } + defer template.Close() + + innerFd = template.fd + } + + m, err := createMap(spec, innerFd, opts, handles) + if err != nil { + return nil, err + } + defer closeOnError(m) + + if spec.Pinning == PinByName { + path := filepath.Join(opts.PinPath, spec.Name) + if err := m.Pin(path); err != nil { + return nil, fmt.Errorf("pin map: %s", err) + } + } + + return m, nil +} + +func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) { + closeOnError := func(closer io.Closer) { + if err != nil { + closer.Close() + } + } + + spec = spec.Copy() + + switch spec.Type { + case ArrayOfMaps: + fallthrough + case HashOfMaps: + if err := haveNestedMaps(); err != nil { + return nil, err + } + + if spec.ValueSize != 0 && spec.ValueSize != 4 { + return nil, errors.New("ValueSize must be zero or four for map of map") + } + spec.ValueSize = 4 + + case PerfEventArray: + if spec.KeySize != 0 && spec.KeySize != 4 { + return nil, errors.New("KeySize must be zero or four for perf event array") + } + spec.KeySize = 4 + + if spec.ValueSize != 0 && spec.ValueSize != 4 { + return nil, errors.New("ValueSize must be zero or four for perf event array") + } + spec.ValueSize = 4 + + if spec.MaxEntries == 0 { + n, err := internal.PossibleCPUs() + if err != nil { + return nil, fmt.Errorf("perf event array: %w", err) + } + spec.MaxEntries = uint32(n) + } + } + + if spec.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze { + if err := haveMapMutabilityModifiers(); err != nil { + return nil, fmt.Errorf("map create: %w", err) + } + } + if spec.Flags&unix.BPF_F_MMAPABLE > 0 { + if err := haveMmapableMaps(); err != nil { + return nil, fmt.Errorf("map create: %w", err) + } + } + if spec.Flags&unix.BPF_F_INNER_MAP > 0 { + if err := haveInnerMaps(); err != nil { + return nil, fmt.Errorf("map create: %w", err) + } + } + + attr := internal.BPFMapCreateAttr{ + MapType: uint32(spec.Type), + KeySize: spec.KeySize, + ValueSize: spec.ValueSize, + MaxEntries: spec.MaxEntries, + Flags: spec.Flags, + NumaNode: spec.NumaNode, + } + + if inner != nil { + var err error + attr.InnerMapFd, err = inner.Value() + if err != nil { + return nil, fmt.Errorf("map create: %w", err) + } + } + + if haveObjName() == nil { + attr.MapName = internal.NewBPFObjName(spec.Name) + } + + var btfDisabled bool + if spec.BTF != nil { + handle, err := handles.btfHandle(btf.MapSpec(spec.BTF)) + btfDisabled = errors.Is(err, btf.ErrNotSupported) + if err != nil && !btfDisabled { + return nil, fmt.Errorf("load BTF: %w", err) + } + + if handle != nil { + attr.BTFFd = uint32(handle.FD()) + attr.BTFKeyTypeID = uint32(btf.MapKey(spec.BTF).ID()) + attr.BTFValueTypeID = uint32(btf.MapValue(spec.BTF).ID()) + } + } + + fd, err := internal.BPFMapCreate(&attr) + if err != nil { + if errors.Is(err, unix.EPERM) { + return nil, fmt.Errorf("map create: RLIMIT_MEMLOCK may be too low: %w", err) + } + if btfDisabled { + return nil, fmt.Errorf("map create without BTF: %w", err) + } + return nil, fmt.Errorf("map create: %w", err) + } + defer closeOnError(fd) + + m, err := newMap(fd, spec.Name, spec.Type, spec.KeySize, spec.ValueSize, spec.MaxEntries, spec.Flags) + if err != nil { + return nil, fmt.Errorf("map create: %w", err) + } + + if err := m.populate(spec.Contents); err != nil { + return nil, fmt.Errorf("map create: can't set initial contents: %w", err) + } + + if spec.Freeze { + if err := m.Freeze(); err != nil { + return nil, fmt.Errorf("can't freeze map: %w", err) + } + } + + return m, nil +} + +func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEntries, flags uint32) (*Map, error) { + m := &Map{ + name, + fd, + typ, + keySize, + valueSize, + maxEntries, + flags, + "", + int(valueSize), + } + + if !typ.hasPerCPUValue() { + return m, nil + } + + possibleCPUs, err := internal.PossibleCPUs() + if err != nil { + return nil, err + } + + m.fullValueSize = align(int(valueSize), 8) * possibleCPUs + return m, nil +} + +func (m *Map) String() string { + if m.name != "" { + return fmt.Sprintf("%s(%s)#%v", m.typ, m.name, m.fd) + } + return fmt.Sprintf("%s#%v", m.typ, m.fd) +} + +// Type returns the underlying type of the map. +func (m *Map) Type() MapType { + return m.typ +} + +// KeySize returns the size of the map key in bytes. +func (m *Map) KeySize() uint32 { + return m.keySize +} + +// ValueSize returns the size of the map value in bytes. +func (m *Map) ValueSize() uint32 { + return m.valueSize +} + +// MaxEntries returns the maximum number of elements the map can hold. +func (m *Map) MaxEntries() uint32 { + return m.maxEntries +} + +// Flags returns the flags of the map. +func (m *Map) Flags() uint32 { + return m.flags +} + +// Info returns metadata about the map. +func (m *Map) Info() (*MapInfo, error) { + return newMapInfoFromFd(m.fd) +} + +// Lookup retrieves a value from a Map. +// +// Calls Close() on valueOut if it is of type **Map or **Program, +// and *valueOut is not nil. +// +// Returns an error if the key doesn't exist, see ErrKeyNotExist. +func (m *Map) Lookup(key, valueOut interface{}) error { + valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize) + if err := m.lookup(key, valuePtr); err != nil { + return err + } + + return m.unmarshalValue(valueOut, valueBytes) +} + +// LookupAndDelete retrieves and deletes a value from a Map. +// +// Returns ErrKeyNotExist if the key doesn't exist. +func (m *Map) LookupAndDelete(key, valueOut interface{}) error { + valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize) + + keyPtr, err := m.marshalKey(key) + if err != nil { + return fmt.Errorf("can't marshal key: %w", err) + } + + if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil { + return fmt.Errorf("lookup and delete failed: %w", err) + } + + return m.unmarshalValue(valueOut, valueBytes) +} + +// LookupBytes gets a value from Map. +// +// Returns a nil value if a key doesn't exist. +func (m *Map) LookupBytes(key interface{}) ([]byte, error) { + valueBytes := make([]byte, m.fullValueSize) + valuePtr := internal.NewSlicePointer(valueBytes) + + err := m.lookup(key, valuePtr) + if errors.Is(err, ErrKeyNotExist) { + return nil, nil + } + + return valueBytes, err +} + +func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error { + keyPtr, err := m.marshalKey(key) + if err != nil { + return fmt.Errorf("can't marshal key: %w", err) + } + + if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil { + return fmt.Errorf("lookup failed: %w", err) + } + return nil +} + +// MapUpdateFlags controls the behaviour of the Map.Update call. +// +// The exact semantics depend on the specific MapType. +type MapUpdateFlags uint64 + +const ( + // UpdateAny creates a new element or update an existing one. + UpdateAny MapUpdateFlags = iota + // UpdateNoExist creates a new element. + UpdateNoExist MapUpdateFlags = 1 << (iota - 1) + // UpdateExist updates an existing element. + UpdateExist +) + +// Put replaces or creates a value in map. +// +// It is equivalent to calling Update with UpdateAny. +func (m *Map) Put(key, value interface{}) error { + return m.Update(key, value, UpdateAny) +} + +// Update changes the value of a key. +func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error { + keyPtr, err := m.marshalKey(key) + if err != nil { + return fmt.Errorf("can't marshal key: %w", err) + } + + valuePtr, err := m.marshalValue(value) + if err != nil { + return fmt.Errorf("can't marshal value: %w", err) + } + + if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil { + return fmt.Errorf("update failed: %w", err) + } + + return nil +} + +// Delete removes a value. +// +// Returns ErrKeyNotExist if the key does not exist. +func (m *Map) Delete(key interface{}) error { + keyPtr, err := m.marshalKey(key) + if err != nil { + return fmt.Errorf("can't marshal key: %w", err) + } + + if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil { + return fmt.Errorf("delete failed: %w", err) + } + return nil +} + +// NextKey finds the key following an initial key. +// +// See NextKeyBytes for details. +// +// Returns ErrKeyNotExist if there is no next key. +func (m *Map) NextKey(key, nextKeyOut interface{}) error { + nextKeyPtr, nextKeyBytes := makeBuffer(nextKeyOut, int(m.keySize)) + + if err := m.nextKey(key, nextKeyPtr); err != nil { + return err + } + + if err := m.unmarshalKey(nextKeyOut, nextKeyBytes); err != nil { + return fmt.Errorf("can't unmarshal next key: %w", err) + } + return nil +} + +// NextKeyBytes returns the key following an initial key as a byte slice. +// +// Passing nil will return the first key. +// +// Use Iterate if you want to traverse all entries in the map. +// +// Returns nil if there are no more keys. +func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) { + nextKey := make([]byte, m.keySize) + nextKeyPtr := internal.NewSlicePointer(nextKey) + + err := m.nextKey(key, nextKeyPtr) + if errors.Is(err, ErrKeyNotExist) { + return nil, nil + } + + return nextKey, err +} + +func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error { + var ( + keyPtr internal.Pointer + err error + ) + + if key != nil { + keyPtr, err = m.marshalKey(key) + if err != nil { + return fmt.Errorf("can't marshal key: %w", err) + } + } + + if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil { + return fmt.Errorf("next key failed: %w", err) + } + return nil +} + +// BatchLookup looks up many elements in a map at once. +// +// "keysOut" and "valuesOut" must be of type slice, a pointer +// to a slice or buffer will not work. +// "prevKey" is the key to start the batch lookup from, it will +// *not* be included in the results. Use nil to start at the first key. +// +// ErrKeyNotExist is returned when the batch lookup has reached +// the end of all possible results, even when partial results +// are returned. It should be used to evaluate when lookup is "done". +func (m *Map) BatchLookup(prevKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { + return m.batchLookup(internal.BPF_MAP_LOOKUP_BATCH, prevKey, nextKeyOut, keysOut, valuesOut, opts) +} + +// BatchLookupAndDelete looks up many elements in a map at once, +// +// It then deletes all those elements. +// "keysOut" and "valuesOut" must be of type slice, a pointer +// to a slice or buffer will not work. +// "prevKey" is the key to start the batch lookup from, it will +// *not* be included in the results. Use nil to start at the first key. +// +// ErrKeyNotExist is returned when the batch lookup has reached +// the end of all possible results, even when partial results +// are returned. It should be used to evaluate when lookup is "done". +func (m *Map) BatchLookupAndDelete(prevKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { + return m.batchLookup(internal.BPF_MAP_LOOKUP_AND_DELETE_BATCH, prevKey, nextKeyOut, keysOut, valuesOut, opts) +} + +func (m *Map) batchLookup(cmd internal.BPFCmd, startKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { + if err := haveBatchAPI(); err != nil { + return 0, err + } + if m.typ.hasPerCPUValue() { + return 0, ErrNotSupported + } + keysValue := reflect.ValueOf(keysOut) + if keysValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("keys must be a slice") + } + valuesValue := reflect.ValueOf(valuesOut) + if valuesValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("valuesOut must be a slice") + } + count := keysValue.Len() + if count != valuesValue.Len() { + return 0, fmt.Errorf("keysOut and valuesOut must be the same length") + } + keyBuf := make([]byte, count*int(m.keySize)) + keyPtr := internal.NewSlicePointer(keyBuf) + valueBuf := make([]byte, count*int(m.fullValueSize)) + valuePtr := internal.NewSlicePointer(valueBuf) + + var ( + startPtr internal.Pointer + err error + retErr error + ) + if startKey != nil { + startPtr, err = marshalPtr(startKey, int(m.keySize)) + if err != nil { + return 0, err + } + } + nextPtr, nextBuf := makeBuffer(nextKeyOut, int(m.keySize)) + + ct, err := bpfMapBatch(cmd, m.fd, startPtr, nextPtr, keyPtr, valuePtr, uint32(count), opts) + if err != nil { + if !errors.Is(err, ErrKeyNotExist) { + return 0, err + } + retErr = ErrKeyNotExist + } + + err = m.unmarshalKey(nextKeyOut, nextBuf) + if err != nil { + return 0, err + } + err = unmarshalBytes(keysOut, keyBuf) + if err != nil { + return 0, err + } + err = unmarshalBytes(valuesOut, valueBuf) + if err != nil { + retErr = err + } + return int(ct), retErr +} + +// BatchUpdate updates the map with multiple keys and values +// simultaneously. +// "keys" and "values" must be of type slice, a pointer +// to a slice or buffer will not work. +func (m *Map) BatchUpdate(keys, values interface{}, opts *BatchOptions) (int, error) { + if err := haveBatchAPI(); err != nil { + return 0, err + } + if m.typ.hasPerCPUValue() { + return 0, ErrNotSupported + } + keysValue := reflect.ValueOf(keys) + if keysValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("keys must be a slice") + } + valuesValue := reflect.ValueOf(values) + if valuesValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("values must be a slice") + } + var ( + count = keysValue.Len() + valuePtr internal.Pointer + err error + ) + if count != valuesValue.Len() { + return 0, fmt.Errorf("keys and values must be the same length") + } + keyPtr, err := marshalPtr(keys, count*int(m.keySize)) + if err != nil { + return 0, err + } + valuePtr, err = marshalPtr(values, count*int(m.valueSize)) + if err != nil { + return 0, err + } + var nilPtr internal.Pointer + ct, err := bpfMapBatch(internal.BPF_MAP_UPDATE_BATCH, m.fd, nilPtr, nilPtr, keyPtr, valuePtr, uint32(count), opts) + return int(ct), err +} + +// BatchDelete batch deletes entries in the map by keys. +// "keys" must be of type slice, a pointer to a slice or buffer will not work. +func (m *Map) BatchDelete(keys interface{}, opts *BatchOptions) (int, error) { + if err := haveBatchAPI(); err != nil { + return 0, err + } + if m.typ.hasPerCPUValue() { + return 0, ErrNotSupported + } + keysValue := reflect.ValueOf(keys) + if keysValue.Kind() != reflect.Slice { + return 0, fmt.Errorf("keys must be a slice") + } + count := keysValue.Len() + keyPtr, err := marshalPtr(keys, count*int(m.keySize)) + if err != nil { + return 0, fmt.Errorf("cannot marshal keys: %v", err) + } + var nilPtr internal.Pointer + ct, err := bpfMapBatch(internal.BPF_MAP_DELETE_BATCH, m.fd, nilPtr, nilPtr, keyPtr, nilPtr, uint32(count), opts) + return int(ct), err +} + +// Iterate traverses a map. +// +// It's safe to create multiple iterators at the same time. +// +// It's not possible to guarantee that all keys in a map will be +// returned if there are concurrent modifications to the map. +func (m *Map) Iterate() *MapIterator { + return newMapIterator(m) +} + +// Close removes a Map +func (m *Map) Close() error { + if m == nil { + // This makes it easier to clean up when iterating maps + // of maps / programs. + return nil + } + + return m.fd.Close() +} + +// FD gets the file descriptor of the Map. +// +// Calling this function is invalid after Close has been called. +func (m *Map) FD() int { + fd, err := m.fd.Value() + if err != nil { + // Best effort: -1 is the number most likely to be an + // invalid file descriptor. + return -1 + } + + return int(fd) +} + +// Clone creates a duplicate of the Map. +// +// Closing the duplicate does not affect the original, and vice versa. +// Changes made to the map are reflected by both instances however. +// If the original map was pinned, the cloned map will not be pinned by default. +// +// Cloning a nil Map returns nil. +func (m *Map) Clone() (*Map, error) { + if m == nil { + return nil, nil + } + + dup, err := m.fd.Dup() + if err != nil { + return nil, fmt.Errorf("can't clone map: %w", err) + } + + return &Map{ + m.name, + dup, + m.typ, + m.keySize, + m.valueSize, + m.maxEntries, + m.flags, + "", + m.fullValueSize, + }, nil +} + +// Pin persists the map on the BPF virtual file system past the lifetime of +// the process that created it . +// +// Calling Pin on a previously pinned map will overwrite the path, except when +// the new path already exists. Re-pinning across filesystems is not supported. +// You can Clone a map to pin it to a different path. +// +// This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs +func (m *Map) Pin(fileName string) error { + if err := internal.Pin(m.pinnedPath, fileName, m.fd); err != nil { + return err + } + m.pinnedPath = fileName + return nil +} + +// Unpin removes the persisted state for the map from the BPF virtual filesystem. +// +// Failed calls to Unpin will not alter the state returned by IsPinned. +// +// Unpinning an unpinned Map returns nil. +func (m *Map) Unpin() error { + if err := internal.Unpin(m.pinnedPath); err != nil { + return err + } + m.pinnedPath = "" + return nil +} + +// IsPinned returns true if the map has a non-empty pinned path. +func (m *Map) IsPinned() bool { + return m.pinnedPath != "" +} + +// Freeze prevents a map to be modified from user space. +// +// It makes no changes to kernel-side restrictions. +func (m *Map) Freeze() error { + if err := haveMapMutabilityModifiers(); err != nil { + return fmt.Errorf("can't freeze map: %w", err) + } + + if err := bpfMapFreeze(m.fd); err != nil { + return fmt.Errorf("can't freeze map: %w", err) + } + return nil +} + +func (m *Map) populate(contents []MapKV) error { + for _, kv := range contents { + if err := m.Put(kv.Key, kv.Value); err != nil { + return fmt.Errorf("key %v: %w", kv.Key, err) + } + } + return nil +} + +func (m *Map) marshalKey(data interface{}) (internal.Pointer, error) { + if data == nil { + if m.keySize == 0 { + // Queues have a key length of zero, so passing nil here is valid. + return internal.NewPointer(nil), nil + } + return internal.Pointer{}, errors.New("can't use nil as key of map") + } + + return marshalPtr(data, int(m.keySize)) +} + +func (m *Map) unmarshalKey(data interface{}, buf []byte) error { + if buf == nil { + // This is from a makeBuffer call, nothing do do here. + return nil + } + + return unmarshalBytes(data, buf) +} + +func (m *Map) marshalValue(data interface{}) (internal.Pointer, error) { + if m.typ.hasPerCPUValue() { + return marshalPerCPUValue(data, int(m.valueSize)) + } + + var ( + buf []byte + err error + ) + + switch value := data.(type) { + case *Map: + if !m.typ.canStoreMap() { + return internal.Pointer{}, fmt.Errorf("can't store map in %s", m.typ) + } + buf, err = marshalMap(value, int(m.valueSize)) + + case *Program: + if !m.typ.canStoreProgram() { + return internal.Pointer{}, fmt.Errorf("can't store program in %s", m.typ) + } + buf, err = marshalProgram(value, int(m.valueSize)) + + default: + return marshalPtr(data, int(m.valueSize)) + } + + if err != nil { + return internal.Pointer{}, err + } + + return internal.NewSlicePointer(buf), nil +} + +func (m *Map) unmarshalValue(value interface{}, buf []byte) error { + if buf == nil { + // This is from a makeBuffer call, nothing do do here. + return nil + } + + if m.typ.hasPerCPUValue() { + return unmarshalPerCPUValue(value, int(m.valueSize), buf) + } + + switch value := value.(type) { + case **Map: + if !m.typ.canStoreMap() { + return fmt.Errorf("can't read a map from %s", m.typ) + } + + other, err := unmarshalMap(buf) + if err != nil { + return err + } + + // The caller might close the map externally, so ignore errors. + _ = (*value).Close() + + *value = other + return nil + + case *Map: + if !m.typ.canStoreMap() { + return fmt.Errorf("can't read a map from %s", m.typ) + } + return errors.New("require pointer to *Map") + + case **Program: + if !m.typ.canStoreProgram() { + return fmt.Errorf("can't read a program from %s", m.typ) + } + + other, err := unmarshalProgram(buf) + if err != nil { + return err + } + + // The caller might close the program externally, so ignore errors. + _ = (*value).Close() + + *value = other + return nil + + case *Program: + if !m.typ.canStoreProgram() { + return fmt.Errorf("can't read a program from %s", m.typ) + } + return errors.New("require pointer to *Program") + } + + return unmarshalBytes(value, buf) +} + +// LoadPinnedMap loads a Map from a BPF file. +func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) { + fd, err := internal.BPFObjGet(fileName, opts.Marshal()) + if err != nil { + return nil, err + } + + m, err := newMapFromFD(fd) + if err == nil { + m.pinnedPath = fileName + } + + return m, err +} + +// unmarshalMap creates a map from a map ID encoded in host endianness. +func unmarshalMap(buf []byte) (*Map, error) { + if len(buf) != 4 { + return nil, errors.New("map id requires 4 byte value") + } + + id := internal.NativeEndian.Uint32(buf) + return NewMapFromID(MapID(id)) +} + +// marshalMap marshals the fd of a map into a buffer in host endianness. +func marshalMap(m *Map, length int) ([]byte, error) { + if length != 4 { + return nil, fmt.Errorf("can't marshal map to %d bytes", length) + } + + fd, err := m.fd.Value() + if err != nil { + return nil, err + } + + buf := make([]byte, 4) + internal.NativeEndian.PutUint32(buf, fd) + return buf, nil +} + +func patchValue(value []byte, typ btf.Type, replacements map[string]interface{}) error { + replaced := make(map[string]bool) + replace := func(name string, offset, size int, replacement interface{}) error { + if offset+size > len(value) { + return fmt.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size) + } + + buf, err := marshalBytes(replacement, size) + if err != nil { + return fmt.Errorf("marshal %s: %w", name, err) + } + + copy(value[offset:offset+size], buf) + replaced[name] = true + return nil + } + + switch parent := typ.(type) { + case *btf.Datasec: + for _, secinfo := range parent.Vars { + name := string(secinfo.Type.(*btf.Var).Name) + replacement, ok := replacements[name] + if !ok { + continue + } + + err := replace(name, int(secinfo.Offset), int(secinfo.Size), replacement) + if err != nil { + return err + } + } + + default: + return fmt.Errorf("patching %T is not supported", typ) + } + + if len(replaced) == len(replacements) { + return nil + } + + var missing []string + for name := range replacements { + if !replaced[name] { + missing = append(missing, name) + } + } + + if len(missing) == 1 { + return fmt.Errorf("unknown field: %s", missing[0]) + } + + return fmt.Errorf("unknown fields: %s", strings.Join(missing, ",")) +} + +// MapIterator iterates a Map. +// +// See Map.Iterate. +type MapIterator struct { + target *Map + prevKey interface{} + prevBytes []byte + count, maxEntries uint32 + done bool + err error +} + +func newMapIterator(target *Map) *MapIterator { + return &MapIterator{ + target: target, + maxEntries: target.maxEntries, + prevBytes: make([]byte, target.keySize), + } +} + +// Next decodes the next key and value. +// +// Iterating a hash map from which keys are being deleted is not +// safe. You may see the same key multiple times. Iteration may +// also abort with an error, see IsIterationAborted. +// +// Returns false if there are no more entries. You must check +// the result of Err afterwards. +// +// See Map.Get for further caveats around valueOut. +func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool { + if mi.err != nil || mi.done { + return false + } + + // For array-like maps NextKeyBytes returns nil only on after maxEntries + // iterations. + for mi.count <= mi.maxEntries { + var nextBytes []byte + nextBytes, mi.err = mi.target.NextKeyBytes(mi.prevKey) + if mi.err != nil { + return false + } + + if nextBytes == nil { + mi.done = true + return false + } + + // The user can get access to nextBytes since unmarshalBytes + // does not copy when unmarshaling into a []byte. + // Make a copy to prevent accidental corruption of + // iterator state. + copy(mi.prevBytes, nextBytes) + mi.prevKey = mi.prevBytes + + mi.count++ + mi.err = mi.target.Lookup(nextBytes, valueOut) + if errors.Is(mi.err, ErrKeyNotExist) { + // Even though the key should be valid, we couldn't look up + // its value. If we're iterating a hash map this is probably + // because a concurrent delete removed the value before we + // could get it. This means that the next call to NextKeyBytes + // is very likely to restart iteration. + // If we're iterating one of the fd maps like + // ProgramArray it means that a given slot doesn't have + // a valid fd associated. It's OK to continue to the next slot. + continue + } + if mi.err != nil { + return false + } + + mi.err = mi.target.unmarshalKey(keyOut, nextBytes) + return mi.err == nil + } + + mi.err = fmt.Errorf("%w", ErrIterationAborted) + return false +} + +// Err returns any encountered error. +// +// The method must be called after Next returns nil. +// +// Returns ErrIterationAborted if it wasn't possible to do a full iteration. +func (mi *MapIterator) Err() error { + return mi.err +} + +// MapGetNextID returns the ID of the next eBPF map. +// +// Returns ErrNotExist, if there is no next eBPF map. +func MapGetNextID(startID MapID) (MapID, error) { + id, err := objGetNextID(internal.BPF_MAP_GET_NEXT_ID, uint32(startID)) + return MapID(id), err +} + +// NewMapFromID returns the map for a given id. +// +// Returns ErrNotExist, if there is no eBPF map with the given id. +func NewMapFromID(id MapID) (*Map, error) { + fd, err := bpfObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id)) + if err != nil { + return nil, err + } + + return newMapFromFD(fd) +} + +// ID returns the systemwide unique ID of the map. +// +// Deprecated: use MapInfo.ID() instead. +func (m *Map) ID() (MapID, error) { + info, err := bpfGetMapInfoByFD(m.fd) + if err != nil { + return MapID(0), err + } + return MapID(info.id), nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/marshalers.go containerd-1.5.9/vendor/github.com/cilium/ebpf/marshalers.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/marshalers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/marshalers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,218 @@ +package ebpf + +import ( + "bytes" + "encoding" + "encoding/binary" + "errors" + "fmt" + "reflect" + "runtime" + "unsafe" + + "github.com/cilium/ebpf/internal" +) + +// marshalPtr converts an arbitrary value into a pointer suitable +// to be passed to the kernel. +// +// As an optimization, it returns the original value if it is an +// unsafe.Pointer. +func marshalPtr(data interface{}, length int) (internal.Pointer, error) { + if ptr, ok := data.(unsafe.Pointer); ok { + return internal.NewPointer(ptr), nil + } + + buf, err := marshalBytes(data, length) + if err != nil { + return internal.Pointer{}, err + } + + return internal.NewSlicePointer(buf), nil +} + +// marshalBytes converts an arbitrary value into a byte buffer. +// +// Prefer using Map.marshalKey and Map.marshalValue if possible, since +// those have special cases that allow more types to be encoded. +// +// Returns an error if the given value isn't representable in exactly +// length bytes. +func marshalBytes(data interface{}, length int) (buf []byte, err error) { + switch value := data.(type) { + case encoding.BinaryMarshaler: + buf, err = value.MarshalBinary() + case string: + buf = []byte(value) + case []byte: + buf = value + case unsafe.Pointer: + err = errors.New("can't marshal from unsafe.Pointer") + case Map, *Map, Program, *Program: + err = fmt.Errorf("can't marshal %T", value) + default: + var wr bytes.Buffer + err = binary.Write(&wr, internal.NativeEndian, value) + if err != nil { + err = fmt.Errorf("encoding %T: %v", value, err) + } + buf = wr.Bytes() + } + if err != nil { + return nil, err + } + + if len(buf) != length { + return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length) + } + return buf, nil +} + +func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) { + if ptr, ok := dst.(unsafe.Pointer); ok { + return internal.NewPointer(ptr), nil + } + + buf := make([]byte, length) + return internal.NewSlicePointer(buf), buf +} + +// unmarshalBytes converts a byte buffer into an arbitrary value. +// +// Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since +// those have special cases that allow more types to be encoded. +func unmarshalBytes(data interface{}, buf []byte) error { + switch value := data.(type) { + case unsafe.Pointer: + // This could be solved in Go 1.17 by unsafe.Slice instead. (https://github.com/golang/go/issues/19367) + // We could opt for removing unsafe.Pointer support in the lib as well. + sh := &reflect.SliceHeader{ //nolint:govet + Data: uintptr(value), + Len: len(buf), + Cap: len(buf), + } + + dst := *(*[]byte)(unsafe.Pointer(sh)) + copy(dst, buf) + runtime.KeepAlive(value) + return nil + case Map, *Map, Program, *Program: + return fmt.Errorf("can't unmarshal into %T", value) + case encoding.BinaryUnmarshaler: + return value.UnmarshalBinary(buf) + case *string: + *value = string(buf) + return nil + case *[]byte: + *value = buf + return nil + case string: + return errors.New("require pointer to string") + case []byte: + return errors.New("require pointer to []byte") + default: + rd := bytes.NewReader(buf) + if err := binary.Read(rd, internal.NativeEndian, value); err != nil { + return fmt.Errorf("decoding %T: %v", value, err) + } + return nil + } +} + +// marshalPerCPUValue encodes a slice containing one value per +// possible CPU into a buffer of bytes. +// +// Values are initialized to zero if the slice has less elements than CPUs. +// +// slice must have a type like []elementType. +func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) { + sliceType := reflect.TypeOf(slice) + if sliceType.Kind() != reflect.Slice { + return internal.Pointer{}, errors.New("per-CPU value requires slice") + } + + possibleCPUs, err := internal.PossibleCPUs() + if err != nil { + return internal.Pointer{}, err + } + + sliceValue := reflect.ValueOf(slice) + sliceLen := sliceValue.Len() + if sliceLen > possibleCPUs { + return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs") + } + + alignedElemLength := align(elemLength, 8) + buf := make([]byte, alignedElemLength*possibleCPUs) + + for i := 0; i < sliceLen; i++ { + elem := sliceValue.Index(i).Interface() + elemBytes, err := marshalBytes(elem, elemLength) + if err != nil { + return internal.Pointer{}, err + } + + offset := i * alignedElemLength + copy(buf[offset:offset+elemLength], elemBytes) + } + + return internal.NewSlicePointer(buf), nil +} + +// unmarshalPerCPUValue decodes a buffer into a slice containing one value per +// possible CPU. +// +// valueOut must have a type like *[]elementType +func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error { + slicePtrType := reflect.TypeOf(slicePtr) + if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice { + return fmt.Errorf("per-cpu value requires pointer to slice") + } + + possibleCPUs, err := internal.PossibleCPUs() + if err != nil { + return err + } + + sliceType := slicePtrType.Elem() + slice := reflect.MakeSlice(sliceType, possibleCPUs, possibleCPUs) + + sliceElemType := sliceType.Elem() + sliceElemIsPointer := sliceElemType.Kind() == reflect.Ptr + if sliceElemIsPointer { + sliceElemType = sliceElemType.Elem() + } + + step := len(buf) / possibleCPUs + if step < elemLength { + return fmt.Errorf("per-cpu element length is larger than available data") + } + for i := 0; i < possibleCPUs; i++ { + var elem interface{} + if sliceElemIsPointer { + newElem := reflect.New(sliceElemType) + slice.Index(i).Set(newElem) + elem = newElem.Interface() + } else { + elem = slice.Index(i).Addr().Interface() + } + + // Make a copy, since unmarshal can hold on to itemBytes + elemBytes := make([]byte, elemLength) + copy(elemBytes, buf[:elemLength]) + + err := unmarshalBytes(elem, elemBytes) + if err != nil { + return fmt.Errorf("cpu %d: %w", i, err) + } + + buf = buf[step:] + } + + reflect.ValueOf(slicePtr).Elem().Set(slice) + return nil +} + +func align(n, alignment int) int { + return (int(n) + alignment - 1) / alignment * alignment +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/prog.go containerd-1.5.9/vendor/github.com/cilium/ebpf/prog.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/prog.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/prog.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,728 @@ +package ebpf + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "path/filepath" + "strings" + "time" + + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" + "github.com/cilium/ebpf/internal/unix" +) + +// ErrNotSupported is returned whenever the kernel doesn't support a feature. +var ErrNotSupported = internal.ErrNotSupported + +var errUnsatisfiedReference = errors.New("unsatisfied reference") + +// ProgramID represents the unique ID of an eBPF program. +type ProgramID uint32 + +const ( + // Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN. + // This is currently the maximum of spare space allocated for SKB + // and XDP programs, and equal to XDP_PACKET_HEADROOM + NET_IP_ALIGN. + outputPad = 256 + 2 +) + +// DefaultVerifierLogSize is the default number of bytes allocated for the +// verifier log. +const DefaultVerifierLogSize = 64 * 1024 + +// ProgramOptions control loading a program into the kernel. +type ProgramOptions struct { + // Controls the detail emitted by the kernel verifier. Set to non-zero + // to enable logging. + LogLevel uint32 + // Controls the output buffer size for the verifier. Defaults to + // DefaultVerifierLogSize. + LogSize int + // An ELF containing the target BTF for this program. It is used both to + // find the correct function to trace and to apply CO-RE relocations. + // This is useful in environments where the kernel BTF is not available + // (containers) or where it is in a non-standard location. Defaults to + // use the kernel BTF from a well-known location. + TargetBTF io.ReaderAt +} + +// ProgramSpec defines a Program. +type ProgramSpec struct { + // Name is passed to the kernel as a debug aid. Must only contain + // alpha numeric and '_' characters. + Name string + // Type determines at which hook in the kernel a program will run. + Type ProgramType + AttachType AttachType + // Name of a kernel data structure to attach to. It's interpretation + // depends on Type and AttachType. + AttachTo string + Instructions asm.Instructions + // Flags is passed to the kernel and specifies additional program + // load attributes. + Flags uint32 + // License of the program. Some helpers are only available if + // the license is deemed compatible with the GPL. + // + // See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1 + License string + + // Version used by Kprobe programs. + // + // Deprecated on kernels 5.0 and later. Leave empty to let the library + // detect this value automatically. + KernelVersion uint32 + + // The BTF associated with this program. Changing Instructions + // will most likely invalidate the contained data, and may + // result in errors when attempting to load it into the kernel. + BTF *btf.Program + + // The byte order this program was compiled for, may be nil. + ByteOrder binary.ByteOrder +} + +// Copy returns a copy of the spec. +func (ps *ProgramSpec) Copy() *ProgramSpec { + if ps == nil { + return nil + } + + cpy := *ps + cpy.Instructions = make(asm.Instructions, len(ps.Instructions)) + copy(cpy.Instructions, ps.Instructions) + return &cpy +} + +// Tag calculates the kernel tag for a series of instructions. +// +// Use asm.Instructions.Tag if you need to calculate for non-native endianness. +func (ps *ProgramSpec) Tag() (string, error) { + return ps.Instructions.Tag(internal.NativeEndian) +} + +// Program represents BPF program loaded into the kernel. +// +// It is not safe to close a Program which is used by other goroutines. +type Program struct { + // Contains the output of the kernel verifier if enabled, + // otherwise it is empty. + VerifierLog string + + fd *internal.FD + name string + pinnedPath string + typ ProgramType +} + +// NewProgram creates a new Program. +// +// Loading a program for the first time will perform +// feature detection by loading small, temporary programs. +func NewProgram(spec *ProgramSpec) (*Program, error) { + return NewProgramWithOptions(spec, ProgramOptions{}) +} + +// NewProgramWithOptions creates a new Program. +// +// Loading a program for the first time will perform +// feature detection by loading small, temporary programs. +func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) { + handles := newHandleCache() + defer handles.close() + + prog, err := newProgramWithOptions(spec, opts, handles) + if errors.Is(err, errUnsatisfiedReference) { + return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err) + } + return prog, err +} + +func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) { + if len(spec.Instructions) == 0 { + return nil, errors.New("Instructions cannot be empty") + } + + if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian { + return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian) + } + + // Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load") + // require the version field to be set to the value of the KERNEL_VERSION + // macro for kprobe-type programs. + // Overwrite Kprobe program version if set to zero or the magic version constant. + kv := spec.KernelVersion + if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) { + v, err := internal.KernelVersion() + if err != nil { + return nil, fmt.Errorf("detecting kernel version: %w", err) + } + kv = v.Kernel() + } + + attr := &bpfProgLoadAttr{ + progType: spec.Type, + progFlags: spec.Flags, + expectedAttachType: spec.AttachType, + license: internal.NewStringPointer(spec.License), + kernelVersion: kv, + } + + if haveObjName() == nil { + attr.progName = internal.NewBPFObjName(spec.Name) + } + + var err error + var targetBTF *btf.Spec + if opts.TargetBTF != nil { + targetBTF, err = handles.btfSpec(opts.TargetBTF) + if err != nil { + return nil, fmt.Errorf("load target BTF: %w", err) + } + } + + var btfDisabled bool + var core btf.COREFixups + if spec.BTF != nil { + core, err = btf.ProgramFixups(spec.BTF, targetBTF) + if err != nil { + return nil, fmt.Errorf("CO-RE relocations: %w", err) + } + + handle, err := handles.btfHandle(btf.ProgramSpec(spec.BTF)) + btfDisabled = errors.Is(err, btf.ErrNotSupported) + if err != nil && !btfDisabled { + return nil, fmt.Errorf("load BTF: %w", err) + } + + if handle != nil { + attr.progBTFFd = uint32(handle.FD()) + + recSize, bytes, err := btf.ProgramLineInfos(spec.BTF) + if err != nil { + return nil, fmt.Errorf("get BTF line infos: %w", err) + } + attr.lineInfoRecSize = recSize + attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) + attr.lineInfo = internal.NewSlicePointer(bytes) + + recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF) + if err != nil { + return nil, fmt.Errorf("get BTF function infos: %w", err) + } + attr.funcInfoRecSize = recSize + attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) + attr.funcInfo = internal.NewSlicePointer(bytes) + } + } + + insns, err := core.Apply(spec.Instructions) + if err != nil { + return nil, fmt.Errorf("CO-RE fixup: %w", err) + } + + if err := fixupJumpsAndCalls(insns); err != nil { + return nil, err + } + + buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize)) + err = insns.Marshal(buf, internal.NativeEndian) + if err != nil { + return nil, err + } + + bytecode := buf.Bytes() + attr.instructions = internal.NewSlicePointer(bytecode) + attr.insCount = uint32(len(bytecode) / asm.InstructionSize) + + if spec.AttachTo != "" { + target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType) + if err != nil { + return nil, err + } + if target != nil { + attr.attachBTFID = target.ID() + } + } + + logSize := DefaultVerifierLogSize + if opts.LogSize > 0 { + logSize = opts.LogSize + } + + var logBuf []byte + if opts.LogLevel > 0 { + logBuf = make([]byte, logSize) + attr.logLevel = opts.LogLevel + attr.logSize = uint32(len(logBuf)) + attr.logBuf = internal.NewSlicePointer(logBuf) + } + + fd, err := bpfProgLoad(attr) + if err == nil { + return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil + } + + logErr := err + if opts.LogLevel == 0 && opts.LogSize >= 0 { + // Re-run with the verifier enabled to get better error messages. + logBuf = make([]byte, logSize) + attr.logLevel = 1 + attr.logSize = uint32(len(logBuf)) + attr.logBuf = internal.NewSlicePointer(logBuf) + + _, logErr = bpfProgLoad(attr) + } + + if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 { + // EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can + // check that the log is empty to reduce false positives. + return nil, fmt.Errorf("load program: RLIMIT_MEMLOCK may be too low: %w", logErr) + } + + err = internal.ErrorWithLog(err, logBuf, logErr) + if btfDisabled { + return nil, fmt.Errorf("load program without BTF: %w", err) + } + return nil, fmt.Errorf("load program: %w", err) +} + +// NewProgramFromFD creates a program from a raw fd. +// +// You should not use fd after calling this function. +// +// Requires at least Linux 4.10. +func NewProgramFromFD(fd int) (*Program, error) { + if fd < 0 { + return nil, errors.New("invalid fd") + } + + return newProgramFromFD(internal.NewFD(uint32(fd))) +} + +// NewProgramFromID returns the program for a given id. +// +// Returns ErrNotExist, if there is no eBPF program with the given id. +func NewProgramFromID(id ProgramID) (*Program, error) { + fd, err := bpfObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id)) + if err != nil { + return nil, fmt.Errorf("get program by id: %w", err) + } + + return newProgramFromFD(fd) +} + +func newProgramFromFD(fd *internal.FD) (*Program, error) { + info, err := newProgramInfoFromFd(fd) + if err != nil { + fd.Close() + return nil, fmt.Errorf("discover program type: %w", err) + } + + return &Program{"", fd, "", "", info.Type}, nil +} + +func (p *Program) String() string { + if p.name != "" { + return fmt.Sprintf("%s(%s)#%v", p.typ, p.name, p.fd) + } + return fmt.Sprintf("%s(%v)", p.typ, p.fd) +} + +// Type returns the underlying type of the program. +func (p *Program) Type() ProgramType { + return p.typ +} + +// Info returns metadata about the program. +// +// Requires at least 4.10. +func (p *Program) Info() (*ProgramInfo, error) { + return newProgramInfoFromFd(p.fd) +} + +// FD gets the file descriptor of the Program. +// +// It is invalid to call this function after Close has been called. +func (p *Program) FD() int { + fd, err := p.fd.Value() + if err != nil { + // Best effort: -1 is the number most likely to be an + // invalid file descriptor. + return -1 + } + + return int(fd) +} + +// Clone creates a duplicate of the Program. +// +// Closing the duplicate does not affect the original, and vice versa. +// +// Cloning a nil Program returns nil. +func (p *Program) Clone() (*Program, error) { + if p == nil { + return nil, nil + } + + dup, err := p.fd.Dup() + if err != nil { + return nil, fmt.Errorf("can't clone program: %w", err) + } + + return &Program{p.VerifierLog, dup, p.name, "", p.typ}, nil +} + +// Pin persists the Program on the BPF virtual file system past the lifetime of +// the process that created it +// +// Calling Pin on a previously pinned program will overwrite the path, except when +// the new path already exists. Re-pinning across filesystems is not supported. +// +// This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs +func (p *Program) Pin(fileName string) error { + if err := internal.Pin(p.pinnedPath, fileName, p.fd); err != nil { + return err + } + p.pinnedPath = fileName + return nil +} + +// Unpin removes the persisted state for the Program from the BPF virtual filesystem. +// +// Failed calls to Unpin will not alter the state returned by IsPinned. +// +// Unpinning an unpinned Program returns nil. +func (p *Program) Unpin() error { + if err := internal.Unpin(p.pinnedPath); err != nil { + return err + } + p.pinnedPath = "" + return nil +} + +// IsPinned returns true if the Program has a non-empty pinned path. +func (p *Program) IsPinned() bool { + return p.pinnedPath != "" +} + +// Close unloads the program from the kernel. +func (p *Program) Close() error { + if p == nil { + return nil + } + + return p.fd.Close() +} + +// Test runs the Program in the kernel with the given input and returns the +// value returned by the eBPF program. outLen may be zero. +// +// Note: the kernel expects at least 14 bytes input for an ethernet header for +// XDP and SKB programs. +// +// This function requires at least Linux 4.12. +func (p *Program) Test(in []byte) (uint32, []byte, error) { + ret, out, _, err := p.testRun(in, 1, nil) + if err != nil { + return ret, nil, fmt.Errorf("can't test program: %w", err) + } + return ret, out, nil +} + +// Benchmark runs the Program with the given input for a number of times +// and returns the time taken per iteration. +// +// Returns the result of the last execution of the program and the time per +// run or an error. reset is called whenever the benchmark syscall is +// interrupted, and should be set to testing.B.ResetTimer or similar. +// +// Note: profiling a call to this function will skew it's results, see +// https://github.com/cilium/ebpf/issues/24 +// +// This function requires at least Linux 4.12. +func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) { + ret, _, total, err := p.testRun(in, repeat, reset) + if err != nil { + return ret, total, fmt.Errorf("can't benchmark program: %w", err) + } + return ret, total, nil +} + +var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() error { + prog, err := NewProgram(&ProgramSpec{ + Type: SocketFilter, + Instructions: asm.Instructions{ + asm.LoadImm(asm.R0, 0, asm.DWord), + asm.Return(), + }, + License: "MIT", + }) + if err != nil { + // This may be because we lack sufficient permissions, etc. + return err + } + defer prog.Close() + + // Programs require at least 14 bytes input + in := make([]byte, 14) + attr := bpfProgTestRunAttr{ + fd: uint32(prog.FD()), + dataSizeIn: uint32(len(in)), + dataIn: internal.NewSlicePointer(in), + } + + err = bpfProgTestRun(&attr) + if errors.Is(err, unix.EINVAL) { + // Check for EINVAL specifically, rather than err != nil since we + // otherwise misdetect due to insufficient permissions. + return internal.ErrNotSupported + } + if errors.Is(err, unix.EINTR) { + // We know that PROG_TEST_RUN is supported if we get EINTR. + return nil + } + return err +}) + +func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) { + if uint(repeat) > math.MaxUint32 { + return 0, nil, 0, fmt.Errorf("repeat is too high") + } + + if len(in) == 0 { + return 0, nil, 0, fmt.Errorf("missing input") + } + + if uint(len(in)) > math.MaxUint32 { + return 0, nil, 0, fmt.Errorf("input is too long") + } + + if err := haveProgTestRun(); err != nil { + return 0, nil, 0, err + } + + // Older kernels ignore the dataSizeOut argument when copying to user space. + // Combined with things like bpf_xdp_adjust_head() we don't really know what the final + // size will be. Hence we allocate an output buffer which we hope will always be large + // enough, and panic if the kernel wrote past the end of the allocation. + // See https://patchwork.ozlabs.org/cover/1006822/ + out := make([]byte, len(in)+outputPad) + + fd, err := p.fd.Value() + if err != nil { + return 0, nil, 0, err + } + + attr := bpfProgTestRunAttr{ + fd: fd, + dataSizeIn: uint32(len(in)), + dataSizeOut: uint32(len(out)), + dataIn: internal.NewSlicePointer(in), + dataOut: internal.NewSlicePointer(out), + repeat: uint32(repeat), + } + + for { + err = bpfProgTestRun(&attr) + if err == nil { + break + } + + if errors.Is(err, unix.EINTR) { + if reset != nil { + reset() + } + continue + } + + return 0, nil, 0, fmt.Errorf("can't run test: %w", err) + } + + if int(attr.dataSizeOut) > cap(out) { + // Houston, we have a problem. The program created more data than we allocated, + // and the kernel wrote past the end of our buffer. + panic("kernel wrote past end of output buffer") + } + out = out[:int(attr.dataSizeOut)] + + total := time.Duration(attr.duration) * time.Nanosecond + return attr.retval, out, total, nil +} + +func unmarshalProgram(buf []byte) (*Program, error) { + if len(buf) != 4 { + return nil, errors.New("program id requires 4 byte value") + } + + // Looking up an entry in a nested map or prog array returns an id, + // not an fd. + id := internal.NativeEndian.Uint32(buf) + return NewProgramFromID(ProgramID(id)) +} + +func marshalProgram(p *Program, length int) ([]byte, error) { + if length != 4 { + return nil, fmt.Errorf("can't marshal program to %d bytes", length) + } + + value, err := p.fd.Value() + if err != nil { + return nil, err + } + + buf := make([]byte, 4) + internal.NativeEndian.PutUint32(buf, value) + return buf, nil +} + +// Attach a Program. +// +// Deprecated: use link.RawAttachProgram instead. +func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error { + if fd < 0 { + return errors.New("invalid fd") + } + + pfd, err := p.fd.Value() + if err != nil { + return err + } + + attr := internal.BPFProgAttachAttr{ + TargetFd: uint32(fd), + AttachBpfFd: pfd, + AttachType: uint32(typ), + AttachFlags: uint32(flags), + } + + return internal.BPFProgAttach(&attr) +} + +// Detach a Program. +// +// Deprecated: use link.RawDetachProgram instead. +func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error { + if fd < 0 { + return errors.New("invalid fd") + } + + if flags != 0 { + return errors.New("flags must be zero") + } + + pfd, err := p.fd.Value() + if err != nil { + return err + } + + attr := internal.BPFProgDetachAttr{ + TargetFd: uint32(fd), + AttachBpfFd: pfd, + AttachType: uint32(typ), + } + + return internal.BPFProgDetach(&attr) +} + +// LoadPinnedProgram loads a Program from a BPF file. +// +// Requires at least Linux 4.11. +func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) { + fd, err := internal.BPFObjGet(fileName, opts.Marshal()) + if err != nil { + return nil, err + } + + info, err := newProgramInfoFromFd(fd) + if err != nil { + _ = fd.Close() + return nil, fmt.Errorf("info for %s: %w", fileName, err) + } + + return &Program{"", fd, filepath.Base(fileName), fileName, info.Type}, nil +} + +// SanitizeName replaces all invalid characters in name with replacement. +// Passing a negative value for replacement will delete characters instead +// of replacing them. Use this to automatically generate valid names for maps +// and programs at runtime. +// +// The set of allowed characters depends on the running kernel version. +// Dots are only allowed as of kernel 5.2. +func SanitizeName(name string, replacement rune) string { + return strings.Map(func(char rune) rune { + if invalidBPFObjNameChar(char) { + return replacement + } + return char + }, name) +} + +// ProgramGetNextID returns the ID of the next eBPF program. +// +// Returns ErrNotExist, if there is no next eBPF program. +func ProgramGetNextID(startID ProgramID) (ProgramID, error) { + id, err := objGetNextID(internal.BPF_PROG_GET_NEXT_ID, uint32(startID)) + return ProgramID(id), err +} + +// ID returns the systemwide unique ID of the program. +// +// Deprecated: use ProgramInfo.ID() instead. +func (p *Program) ID() (ProgramID, error) { + info, err := bpfGetProgInfoByFD(p.fd) + if err != nil { + return ProgramID(0), err + } + return ProgramID(info.id), nil +} + +func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) { + type match struct { + p ProgramType + a AttachType + } + + var target btf.Type + var typeName, featureName string + switch (match{progType, attachType}) { + case match{LSM, AttachLSMMac}: + target = new(btf.Func) + typeName = "bpf_lsm_" + name + featureName = name + " LSM hook" + + case match{Tracing, AttachTraceIter}: + target = new(btf.Func) + typeName = "bpf_iter_" + name + featureName = name + " iterator" + + default: + return nil, nil + } + + if kernel == nil { + var err error + kernel, err = btf.LoadKernelSpec() + if err != nil { + return nil, fmt.Errorf("load kernel spec: %w", err) + } + } + + err := kernel.FindType(typeName, target) + if errors.Is(err, btf.ErrNotFound) { + return nil, &internal.UnsupportedFeatureError{ + Name: featureName, + } + } + if err != nil { + return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err) + } + return target, nil +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/README.md containerd-1.5.9/vendor/github.com/cilium/ebpf/README.md --- containerd-1.2.6/vendor/github.com/cilium/ebpf/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,62 @@ +# eBPF + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/cilium/ebpf)](https://pkg.go.dev/github.com/cilium/ebpf) + +eBPF is a pure Go library that provides utilities for loading, compiling, and +debugging eBPF programs. It has minimal external dependencies and is intended to +be used in long running processes. + +* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic + assembler +* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF + to various hooks +* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a + `PERF_EVENT_ARRAY` +* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows + compiling and embedding eBPF programs in Go code + +The library is maintained by [Cloudflare](https://www.cloudflare.com) and +[Cilium](https://www.cilium.io). Feel free to +[join](https://cilium.herokuapp.com/) the +[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack. + +## Current status + +The package is production ready, but **the API is explicitly unstable right +now**. Expect to update your code if you want to follow along. + +## Getting Started + +A small collection of Go and eBPF programs that serve as examples for building +your own tools can be found under [examples/](examples/). + +Contributions are highly encouraged, as they highlight certain use cases of +eBPF and the library, and help shape the future of the project. + +## Requirements + +* A version of Go that is [supported by + upstream](https://golang.org/doc/devel/release.html#policy) +* Linux 4.9, 4.19 or 5.4 (versions in-between should work, but are not tested) + +## Useful resources + +* [eBPF.io](https://ebpf.io) (recommended) +* [Cilium eBPF documentation](https://docs.cilium.io/en/latest/bpf/#bpf-guide) + (recommended) +* [Linux documentation on + BPF](https://www.kernel.org/doc/html/latest/networking/filter.html) +* [eBPF features by Linux + version](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md) + +## Regenerating Testdata + +Run `make` in the root of this repository to rebuild testdata in all +subpackages. This requires Docker, as it relies on a standardized build +environment to keep the build output stable. + +The toolchain image build files are kept in [testdata/docker/](testdata/docker/). + +## License + +MIT diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/run-tests.sh containerd-1.5.9/vendor/github.com/cilium/ebpf/run-tests.sh --- containerd-1.2.6/vendor/github.com/cilium/ebpf/run-tests.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/run-tests.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,123 @@ +#!/bin/bash +# Test the current package under a different kernel. +# Requires virtme and qemu to be installed. +# Examples: +# Run all tests on a 5.4 kernel +# $ ./run-tests.sh 5.4 +# Run a subset of tests: +# $ ./run-tests.sh 5.4 go test ./link + +set -euo pipefail + +script="$(realpath "$0")" +readonly script + +# This script is a bit like a Matryoshka doll since it keeps re-executing itself +# in various different contexts: +# +# 1. invoked by the user like run-tests.sh 5.4 +# 2. invoked by go test like run-tests.sh --exec-vm +# 3. invoked by init in the vm like run-tests.sh --exec-test +# +# This allows us to use all available CPU on the host machine to compile our +# code, and then only use the VM to execute the test. This is because the VM +# is usually slower at compiling than the host. +if [[ "${1:-}" = "--exec-vm" ]]; then + shift + + input="$1" + shift + + # Use sudo if /dev/kvm isn't accessible by the current user. + sudo="" + if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then + sudo="sudo" + fi + readonly sudo + + testdir="$(dirname "$1")" + output="$(mktemp -d)" + printf -v cmd "%q " "$@" + + if [[ "$(stat -c '%t:%T' -L /proc/$$/fd/0)" == "1:3" ]]; then + # stdin is /dev/null, which doesn't play well with qemu. Use a fifo as a + # blocking substitute. + mkfifo "${output}/fake-stdin" + # Open for reading and writing to avoid blocking. + exec 0<> "${output}/fake-stdin" + rm "${output}/fake-stdin" + fi + + $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \ + --rwdir="${testdir}=${testdir}" \ + --rodir=/run/input="${input}" \ + --rwdir=/run/output="${output}" \ + --script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \ + --qemu-opts -smp 2 # need at least two CPUs for some tests + + if [[ ! -e "${output}/success" ]]; then + exit 1 + fi + + $sudo rm -r "$output" + exit 0 +elif [[ "${1:-}" = "--exec-test" ]]; then + shift + + mount -t bpf bpf /sys/fs/bpf + mount -t tracefs tracefs /sys/kernel/debug/tracing + + if [[ -d "/run/input/bpf" ]]; then + export KERNEL_SELFTESTS="/run/input/bpf" + fi + + dmesg -C + if ! "$@"; then + dmesg + exit 1 + fi + touch "/run/output/success" + exit 0 +fi + +readonly kernel_version="${1:-}" +if [[ -z "${kernel_version}" ]]; then + echo "Expecting kernel version as first argument" + exit 1 +fi +shift + +readonly kernel="linux-${kernel_version}.bz" +readonly selftests="linux-${kernel_version}-selftests-bpf.bz" +readonly input="$(mktemp -d)" +readonly tmp_dir="${TMPDIR:-/tmp}" +readonly branch="${BRANCH:-master}" + +fetch() { + echo Fetching "${1}" + wget -nv -N -P "${tmp_dir}" "https://github.com/cilium/ci-kernels/raw/${branch}/${1}" +} + +fetch "${kernel}" +cp "${tmp_dir}/${kernel}" "${input}/bzImage" + +if fetch "${selftests}"; then + mkdir "${input}/bpf" + tar --strip-components=4 -xjf "${tmp_dir}/${selftests}" -C "${input}/bpf" +else + echo "No selftests found, disabling" +fi + +args=(-v -short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...) +if (( $# > 0 )); then + args=("$@") +fi + +export GOFLAGS=-mod=readonly +export CGO_ENABLED=0 + +echo Testing on "${kernel_version}" +go test -exec "$script --exec-vm $input" "${args[@]}" +echo "Test successful on ${kernel_version}" + +rm -r "${input}" diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/syscalls.go containerd-1.5.9/vendor/github.com/cilium/ebpf/syscalls.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/syscalls.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/syscalls.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,480 @@ +package ebpf + +import ( + "errors" + "fmt" + "os" + "unsafe" + + "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" + "github.com/cilium/ebpf/internal/unix" +) + +// ErrNotExist is returned when loading a non-existing map or program. +// +// Deprecated: use os.ErrNotExist instead. +var ErrNotExist = os.ErrNotExist + +// invalidBPFObjNameChar returns true if char may not appear in +// a BPF object name. +func invalidBPFObjNameChar(char rune) bool { + dotAllowed := objNameAllowsDot() == nil + + switch { + case char >= 'A' && char <= 'Z': + return false + case char >= 'a' && char <= 'z': + return false + case char >= '0' && char <= '9': + return false + case dotAllowed && char == '.': + return false + case char == '_': + return false + default: + return true + } +} + +type bpfMapOpAttr struct { + mapFd uint32 + padding uint32 + key internal.Pointer + value internal.Pointer + flags uint64 +} + +type bpfBatchMapOpAttr struct { + inBatch internal.Pointer + outBatch internal.Pointer + keys internal.Pointer + values internal.Pointer + count uint32 + mapFd uint32 + elemFlags uint64 + flags uint64 +} + +type bpfMapInfo struct { + map_type uint32 // since 4.12 1e2709769086 + id uint32 + key_size uint32 + value_size uint32 + max_entries uint32 + map_flags uint32 + name internal.BPFObjName // since 4.15 ad5b177bd73f + ifindex uint32 // since 4.16 52775b33bb50 + btf_vmlinux_value_type_id uint32 // since 5.6 85d33df357b6 + netns_dev uint64 // since 4.16 52775b33bb50 + netns_ino uint64 + btf_id uint32 // since 4.18 78958fca7ead + btf_key_type_id uint32 // since 4.18 9b2cf328b2ec + btf_value_type_id uint32 +} + +type bpfProgLoadAttr struct { + progType ProgramType + insCount uint32 + instructions internal.Pointer + license internal.Pointer + logLevel uint32 + logSize uint32 + logBuf internal.Pointer + kernelVersion uint32 // since 4.1 2541517c32be + progFlags uint32 // since 4.11 e07b98d9bffe + progName internal.BPFObjName // since 4.15 067cae47771c + progIfIndex uint32 // since 4.15 1f6f4cb7ba21 + expectedAttachType AttachType // since 4.17 5e43f899b03a + progBTFFd uint32 + funcInfoRecSize uint32 + funcInfo internal.Pointer + funcInfoCnt uint32 + lineInfoRecSize uint32 + lineInfo internal.Pointer + lineInfoCnt uint32 + attachBTFID btf.TypeID + attachProgFd uint32 +} + +type bpfProgInfo struct { + prog_type uint32 + id uint32 + tag [unix.BPF_TAG_SIZE]byte + jited_prog_len uint32 + xlated_prog_len uint32 + jited_prog_insns internal.Pointer + xlated_prog_insns internal.Pointer + load_time uint64 // since 4.15 cb4d2b3f03d8 + created_by_uid uint32 + nr_map_ids uint32 + map_ids internal.Pointer + name internal.BPFObjName // since 4.15 067cae47771c + ifindex uint32 + gpl_compatible uint32 + netns_dev uint64 + netns_ino uint64 + nr_jited_ksyms uint32 + nr_jited_func_lens uint32 + jited_ksyms internal.Pointer + jited_func_lens internal.Pointer + btf_id uint32 + func_info_rec_size uint32 + func_info internal.Pointer + nr_func_info uint32 + nr_line_info uint32 + line_info internal.Pointer + jited_line_info internal.Pointer + nr_jited_line_info uint32 + line_info_rec_size uint32 + jited_line_info_rec_size uint32 + nr_prog_tags uint32 + prog_tags internal.Pointer + run_time_ns uint64 + run_cnt uint64 +} + +type bpfProgTestRunAttr struct { + fd uint32 + retval uint32 + dataSizeIn uint32 + dataSizeOut uint32 + dataIn internal.Pointer + dataOut internal.Pointer + repeat uint32 + duration uint32 +} + +type bpfGetFDByIDAttr struct { + id uint32 + next uint32 +} + +type bpfMapFreezeAttr struct { + mapFd uint32 +} + +type bpfObjGetNextIDAttr struct { + startID uint32 + nextID uint32 + openFlags uint32 +} + +func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { + for { + fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + // As of ~4.20 the verifier can be interrupted by a signal, + // and returns EAGAIN in that case. + if errors.Is(err, unix.EAGAIN) { + continue + } + + if err != nil { + return nil, err + } + + return internal.NewFD(uint32(fd)), nil + } +} + +func bpfProgTestRun(attr *bpfProgTestRunAttr) error { + _, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) + return err +} + +var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error { + _, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{ + MapType: uint32(ArrayOfMaps), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + // Invalid file descriptor. + InnerMapFd: ^uint32(0), + }) + if errors.Is(err, unix.EINVAL) { + return internal.ErrNotSupported + } + if errors.Is(err, unix.EBADF) { + return nil + } + return err +}) + +var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error { + // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since + // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check. + m, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{ + MapType: uint32(Array), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + Flags: unix.BPF_F_RDONLY_PROG, + }) + if err != nil { + return internal.ErrNotSupported + } + _ = m.Close() + return nil +}) + +var haveMmapableMaps = internal.FeatureTest("mmapable maps", "5.5", func() error { + // This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps. + m, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{ + MapType: uint32(Array), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + Flags: unix.BPF_F_MMAPABLE, + }) + if err != nil { + return internal.ErrNotSupported + } + _ = m.Close() + return nil +}) + +var haveInnerMaps = internal.FeatureTest("inner maps", "5.10", func() error { + // This checks BPF_F_INNER_MAP, which appeared in 5.10. + m, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{ + MapType: uint32(Array), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + Flags: unix.BPF_F_INNER_MAP, + }) + if err != nil { + return internal.ErrNotSupported + } + _ = m.Close() + return nil +}) + +func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapOpAttr{ + mapFd: fd, + key: key, + value: valueOut, + } + _, err = internal.BPF(internal.BPF_MAP_LOOKUP_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapOpAttr{ + mapFd: fd, + key: key, + value: valueOut, + } + _, err = internal.BPF(internal.BPF_MAP_LOOKUP_AND_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint64) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapOpAttr{ + mapFd: fd, + key: key, + value: valueOut, + flags: flags, + } + _, err = internal.BPF(internal.BPF_MAP_UPDATE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapOpAttr{ + mapFd: fd, + key: key, + } + _, err = internal.BPF(internal.BPF_MAP_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapOpAttr{ + mapFd: fd, + key: key, + value: nextKeyOut, + } + _, err = internal.BPF(internal.BPF_MAP_GET_NEXT_KEY, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return wrapMapError(err) +} + +func objGetNextID(cmd internal.BPFCmd, start uint32) (uint32, error) { + attr := bpfObjGetNextIDAttr{ + startID: start, + } + _, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return attr.nextID, err +} + +func bpfMapBatch(cmd internal.BPFCmd, m *internal.FD, inBatch, outBatch, keys, values internal.Pointer, count uint32, opts *BatchOptions) (uint32, error) { + fd, err := m.Value() + if err != nil { + return 0, err + } + + attr := bpfBatchMapOpAttr{ + inBatch: inBatch, + outBatch: outBatch, + keys: keys, + values: values, + count: count, + mapFd: fd, + } + if opts != nil { + attr.elemFlags = opts.ElemFlags + attr.flags = opts.Flags + } + _, err = internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + // always return count even on an error, as things like update might partially be fulfilled. + return attr.count, wrapMapError(err) +} + +func wrapMapError(err error) error { + if err == nil { + return nil + } + + if errors.Is(err, unix.ENOENT) { + return internal.SyscallError(ErrKeyNotExist, unix.ENOENT) + } + + if errors.Is(err, unix.EEXIST) { + return internal.SyscallError(ErrKeyExist, unix.EEXIST) + } + + if errors.Is(err, unix.ENOTSUPP) { + return internal.SyscallError(ErrNotSupported, unix.ENOTSUPP) + } + + return err +} + +func bpfMapFreeze(m *internal.FD) error { + fd, err := m.Value() + if err != nil { + return err + } + + attr := bpfMapFreezeAttr{ + mapFd: fd, + } + _, err = internal.BPF(internal.BPF_MAP_FREEZE, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return err +} + +func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) { + var info bpfProgInfo + if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil { + return nil, fmt.Errorf("can't get program info: %w", err) + } + return &info, nil +} + +func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) { + var info bpfMapInfo + err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) + if err != nil { + return nil, fmt.Errorf("can't get map info: %w", err) + } + return &info, nil +} + +var haveObjName = internal.FeatureTest("object names", "4.15", func() error { + attr := internal.BPFMapCreateAttr{ + MapType: uint32(Array), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + MapName: internal.NewBPFObjName("feature_test"), + } + + fd, err := internal.BPFMapCreate(&attr) + if err != nil { + return internal.ErrNotSupported + } + + _ = fd.Close() + return nil +}) + +var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() error { + if err := haveObjName(); err != nil { + return err + } + + attr := internal.BPFMapCreateAttr{ + MapType: uint32(Array), + KeySize: 4, + ValueSize: 4, + MaxEntries: 1, + MapName: internal.NewBPFObjName(".test"), + } + + fd, err := internal.BPFMapCreate(&attr) + if err != nil { + return internal.ErrNotSupported + } + + _ = fd.Close() + return nil +}) + +var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error { + var maxEntries uint32 = 2 + attr := internal.BPFMapCreateAttr{ + MapType: uint32(Hash), + KeySize: 4, + ValueSize: 4, + MaxEntries: maxEntries, + } + + fd, err := internal.BPFMapCreate(&attr) + if err != nil { + return internal.ErrNotSupported + } + defer fd.Close() + keys := []uint32{1, 2} + values := []uint32{3, 4} + kp, _ := marshalPtr(keys, 8) + vp, _ := marshalPtr(values, 8) + nilPtr := internal.NewPointer(nil) + _, err = bpfMapBatch(internal.BPF_MAP_UPDATE_BATCH, fd, nilPtr, nilPtr, kp, vp, maxEntries, nil) + if err != nil { + return internal.ErrNotSupported + } + return nil +}) + +func bpfObjGetFDByID(cmd internal.BPFCmd, id uint32) (*internal.FD, error) { + attr := bpfGetFDByIDAttr{ + id: id, + } + ptr, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) + return internal.NewFD(uint32(ptr)), err +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/types.go containerd-1.5.9/vendor/github.com/cilium/ebpf/types.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,248 @@ +package ebpf + +import ( + "github.com/cilium/ebpf/internal/unix" +) + +//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType + +// MapType indicates the type map structure +// that will be initialized in the kernel. +type MapType uint32 + +// All the various map types that can be created +const ( + UnspecifiedMap MapType = iota + // Hash is a hash map + Hash + // Array is an array map + Array + // ProgramArray - A program array map is a special kind of array map whose map + // values contain only file descriptors referring to other eBPF + // programs. Thus, both the key_size and value_size must be + // exactly four bytes. This map is used in conjunction with the + // TailCall helper. + ProgramArray + // PerfEventArray - A perf event array is used in conjunction with PerfEventRead + // and PerfEventOutput calls, to read the raw bpf_perf_data from the registers. + PerfEventArray + // PerCPUHash - This data structure is useful for people who have high performance + // network needs and can reconcile adds at the end of some cycle, so that + // hashes can be lock free without the use of XAdd, which can be costly. + PerCPUHash + // PerCPUArray - This data structure is useful for people who have high performance + // network needs and can reconcile adds at the end of some cycle, so that + // hashes can be lock free without the use of XAdd, which can be costly. + // Each CPU gets a copy of this hash, the contents of all of which can be reconciled + // later. + PerCPUArray + // StackTrace - This holds whole user and kernel stack traces, it can be retrieved with + // GetStackID + StackTrace + // CGroupArray - This is a very niche structure used to help SKBInCGroup determine + // if an skb is from a socket belonging to a specific cgroup + CGroupArray + // LRUHash - This allows you to create a small hash structure that will purge the + // least recently used items rather than thow an error when you run out of memory + LRUHash + // LRUCPUHash - This is NOT like PerCPUHash, this structure is shared among the CPUs, + // it has more to do with including the CPU id with the LRU calculation so that if a + // particular CPU is using a value over-and-over again, then it will be saved, but if + // a value is being retrieved a lot but sparsely across CPUs it is not as important, basically + // giving weight to CPU locality over overall usage. + LRUCPUHash + // LPMTrie - This is an implementation of Longest-Prefix-Match Trie structure. It is useful, + // for storing things like IP addresses which can be bit masked allowing for keys of differing + // values to refer to the same reference based on their masks. See wikipedia for more details. + LPMTrie + // ArrayOfMaps - Each item in the array is another map. The inner map mustn't be a map of maps + // itself. + ArrayOfMaps + // HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps + // itself. + HashOfMaps + // DevMap - Specialized map to store references to network devices. + DevMap + // SockMap - Specialized map to store references to sockets. + SockMap + // CPUMap - Specialized map to store references to CPUs. + CPUMap + // XSKMap - Specialized map for XDP programs to store references to open sockets. + XSKMap + // SockHash - Specialized hash to store references to sockets. + SockHash + // CGroupStorage - Special map for CGroups. + CGroupStorage + // ReusePortSockArray - Specialized map to store references to sockets that can be reused. + ReusePortSockArray + // PerCPUCGroupStorage - Special per CPU map for CGroups. + PerCPUCGroupStorage + // Queue - FIFO storage for BPF programs. + Queue + // Stack - LIFO storage for BPF programs. + Stack + // SkStorage - Specialized map for local storage at SK for BPF programs. + SkStorage + // DevMapHash - Hash-based indexing scheme for references to network devices. + DevMapHash + StructOpts + RingBuf + InodeStorage + TaskStorage +) + +// hasPerCPUValue returns true if the Map stores a value per CPU. +func (mt MapType) hasPerCPUValue() bool { + return mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash +} + +// canStoreMap returns true if the map type accepts a map fd +// for update and returns a map id for lookup. +func (mt MapType) canStoreMap() bool { + return mt == ArrayOfMaps || mt == HashOfMaps +} + +// canStoreProgram returns true if the map type accepts a program fd +// for update and returns a program id for lookup. +func (mt MapType) canStoreProgram() bool { + return mt == ProgramArray +} + +// ProgramType of the eBPF program +type ProgramType uint32 + +// eBPF program types +const ( + UnspecifiedProgram ProgramType = iota + SocketFilter + Kprobe + SchedCLS + SchedACT + TracePoint + XDP + PerfEvent + CGroupSKB + CGroupSock + LWTIn + LWTOut + LWTXmit + SockOps + SkSKB + CGroupDevice + SkMsg + RawTracepoint + CGroupSockAddr + LWTSeg6Local + LircMode2 + SkReuseport + FlowDissector + CGroupSysctl + RawTracepointWritable + CGroupSockopt + Tracing + StructOps + Extension + LSM + SkLookup +) + +// AttachType of the eBPF program, needed to differentiate allowed context accesses in +// some newer program types like CGroupSockAddr. Should be set to AttachNone if not required. +// Will cause invalid argument (EINVAL) at program load time if set incorrectly. +type AttachType uint32 + +// AttachNone is an alias for AttachCGroupInetIngress for readability reasons. +const AttachNone AttachType = 0 + +const ( + AttachCGroupInetIngress AttachType = iota + AttachCGroupInetEgress + AttachCGroupInetSockCreate + AttachCGroupSockOps + AttachSkSKBStreamParser + AttachSkSKBStreamVerdict + AttachCGroupDevice + AttachSkMsgVerdict + AttachCGroupInet4Bind + AttachCGroupInet6Bind + AttachCGroupInet4Connect + AttachCGroupInet6Connect + AttachCGroupInet4PostBind + AttachCGroupInet6PostBind + AttachCGroupUDP4Sendmsg + AttachCGroupUDP6Sendmsg + AttachLircMode2 + AttachFlowDissector + AttachCGroupSysctl + AttachCGroupUDP4Recvmsg + AttachCGroupUDP6Recvmsg + AttachCGroupGetsockopt + AttachCGroupSetsockopt + AttachTraceRawTp + AttachTraceFEntry + AttachTraceFExit + AttachModifyReturn + AttachLSMMac + AttachTraceIter + AttachCgroupInet4GetPeername + AttachCgroupInet6GetPeername + AttachCgroupInet4GetSockname + AttachCgroupInet6GetSockname + AttachXDPDevMap + AttachCgroupInetSockRelease + AttachXDPCPUMap + AttachSkLookup + AttachXDP +) + +// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command +type AttachFlags uint32 + +// PinType determines whether a map is pinned into a BPFFS. +type PinType int + +// Valid pin types. +// +// Mirrors enum libbpf_pin_type. +const ( + PinNone PinType = iota + // Pin an object by using its name as the filename. + PinByName +) + +// LoadPinOptions control how a pinned object is loaded. +type LoadPinOptions struct { + // Request a read-only or write-only object. The default is a read-write + // object. Only one of the flags may be set. + ReadOnly bool + WriteOnly bool + + // Raw flags for the syscall. Other fields of this struct take precedence. + Flags uint32 +} + +// Marshal returns a value suitable for BPF_OBJ_GET syscall file_flags parameter. +func (lpo *LoadPinOptions) Marshal() uint32 { + if lpo == nil { + return 0 + } + + flags := lpo.Flags + if lpo.ReadOnly { + flags |= unix.BPF_F_RDONLY + } + if lpo.WriteOnly { + flags |= unix.BPF_F_WRONLY + } + return flags +} + +// BatchOptions batch map operations options +// +// Mirrors libbpf struct bpf_map_batch_opts +// Currently BPF_F_FLAG is the only supported +// flag (for ElemFlags). +type BatchOptions struct { + ElemFlags uint64 + Flags uint64 +} diff -Nru containerd-1.2.6/vendor/github.com/cilium/ebpf/types_string.go containerd-1.5.9/vendor/github.com/cilium/ebpf/types_string.go --- containerd-1.2.6/vendor/github.com/cilium/ebpf/types_string.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cilium/ebpf/types_string.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,172 @@ +// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType"; DO NOT EDIT. + +package ebpf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[UnspecifiedMap-0] + _ = x[Hash-1] + _ = x[Array-2] + _ = x[ProgramArray-3] + _ = x[PerfEventArray-4] + _ = x[PerCPUHash-5] + _ = x[PerCPUArray-6] + _ = x[StackTrace-7] + _ = x[CGroupArray-8] + _ = x[LRUHash-9] + _ = x[LRUCPUHash-10] + _ = x[LPMTrie-11] + _ = x[ArrayOfMaps-12] + _ = x[HashOfMaps-13] + _ = x[DevMap-14] + _ = x[SockMap-15] + _ = x[CPUMap-16] + _ = x[XSKMap-17] + _ = x[SockHash-18] + _ = x[CGroupStorage-19] + _ = x[ReusePortSockArray-20] + _ = x[PerCPUCGroupStorage-21] + _ = x[Queue-22] + _ = x[Stack-23] + _ = x[SkStorage-24] + _ = x[DevMapHash-25] + _ = x[StructOpts-26] + _ = x[RingBuf-27] + _ = x[InodeStorage-28] + _ = x[TaskStorage-29] +} + +const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOptsRingBufInodeStorageTaskStorage" + +var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 258, 265, 277, 288} + +func (i MapType) String() string { + if i >= MapType(len(_MapType_index)-1) { + return "MapType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _MapType_name[_MapType_index[i]:_MapType_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[UnspecifiedProgram-0] + _ = x[SocketFilter-1] + _ = x[Kprobe-2] + _ = x[SchedCLS-3] + _ = x[SchedACT-4] + _ = x[TracePoint-5] + _ = x[XDP-6] + _ = x[PerfEvent-7] + _ = x[CGroupSKB-8] + _ = x[CGroupSock-9] + _ = x[LWTIn-10] + _ = x[LWTOut-11] + _ = x[LWTXmit-12] + _ = x[SockOps-13] + _ = x[SkSKB-14] + _ = x[CGroupDevice-15] + _ = x[SkMsg-16] + _ = x[RawTracepoint-17] + _ = x[CGroupSockAddr-18] + _ = x[LWTSeg6Local-19] + _ = x[LircMode2-20] + _ = x[SkReuseport-21] + _ = x[FlowDissector-22] + _ = x[CGroupSysctl-23] + _ = x[RawTracepointWritable-24] + _ = x[CGroupSockopt-25] + _ = x[Tracing-26] + _ = x[StructOps-27] + _ = x[Extension-28] + _ = x[LSM-29] + _ = x[SkLookup-30] +} + +const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracingStructOpsExtensionLSMSkLookup" + +var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265, 274, 283, 286, 294} + +func (i ProgramType) String() string { + if i >= ProgramType(len(_ProgramType_index)-1) { + return "ProgramType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _ProgramType_name[_ProgramType_index[i]:_ProgramType_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AttachNone-0] + _ = x[AttachCGroupInetIngress-0] + _ = x[AttachCGroupInetEgress-1] + _ = x[AttachCGroupInetSockCreate-2] + _ = x[AttachCGroupSockOps-3] + _ = x[AttachSkSKBStreamParser-4] + _ = x[AttachSkSKBStreamVerdict-5] + _ = x[AttachCGroupDevice-6] + _ = x[AttachSkMsgVerdict-7] + _ = x[AttachCGroupInet4Bind-8] + _ = x[AttachCGroupInet6Bind-9] + _ = x[AttachCGroupInet4Connect-10] + _ = x[AttachCGroupInet6Connect-11] + _ = x[AttachCGroupInet4PostBind-12] + _ = x[AttachCGroupInet6PostBind-13] + _ = x[AttachCGroupUDP4Sendmsg-14] + _ = x[AttachCGroupUDP6Sendmsg-15] + _ = x[AttachLircMode2-16] + _ = x[AttachFlowDissector-17] + _ = x[AttachCGroupSysctl-18] + _ = x[AttachCGroupUDP4Recvmsg-19] + _ = x[AttachCGroupUDP6Recvmsg-20] + _ = x[AttachCGroupGetsockopt-21] + _ = x[AttachCGroupSetsockopt-22] + _ = x[AttachTraceRawTp-23] + _ = x[AttachTraceFEntry-24] + _ = x[AttachTraceFExit-25] + _ = x[AttachModifyReturn-26] + _ = x[AttachLSMMac-27] + _ = x[AttachTraceIter-28] + _ = x[AttachCgroupInet4GetPeername-29] + _ = x[AttachCgroupInet6GetPeername-30] + _ = x[AttachCgroupInet4GetSockname-31] + _ = x[AttachCgroupInet6GetSockname-32] + _ = x[AttachXDPDevMap-33] + _ = x[AttachCgroupInetSockRelease-34] + _ = x[AttachXDPCPUMap-35] + _ = x[AttachSkLookup-36] + _ = x[AttachXDP-37] +} + +const _AttachType_name = "AttachNoneAttachCGroupInetEgressAttachCGroupInetSockCreateAttachCGroupSockOpsAttachSkSKBStreamParserAttachSkSKBStreamVerdictAttachCGroupDeviceAttachSkMsgVerdictAttachCGroupInet4BindAttachCGroupInet6BindAttachCGroupInet4ConnectAttachCGroupInet6ConnectAttachCGroupInet4PostBindAttachCGroupInet6PostBindAttachCGroupUDP4SendmsgAttachCGroupUDP6SendmsgAttachLircMode2AttachFlowDissectorAttachCGroupSysctlAttachCGroupUDP4RecvmsgAttachCGroupUDP6RecvmsgAttachCGroupGetsockoptAttachCGroupSetsockoptAttachTraceRawTpAttachTraceFEntryAttachTraceFExitAttachModifyReturnAttachLSMMacAttachTraceIterAttachCgroupInet4GetPeernameAttachCgroupInet6GetPeernameAttachCgroupInet4GetSocknameAttachCgroupInet6GetSocknameAttachXDPDevMapAttachCgroupInetSockReleaseAttachXDPCPUMapAttachSkLookupAttachXDP" + +var _AttachType_index = [...]uint16{0, 10, 32, 58, 77, 100, 124, 142, 160, 181, 202, 226, 250, 275, 300, 323, 346, 361, 380, 398, 421, 444, 466, 488, 504, 521, 537, 555, 567, 582, 610, 638, 666, 694, 709, 736, 751, 765, 774} + +func (i AttachType) String() string { + if i >= AttachType(len(_AttachType_index)-1) { + return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[PinNone-0] + _ = x[PinByName-1] +} + +const _PinType_name = "PinNonePinByName" + +var _PinType_index = [...]uint8{0, 7, 16} + +func (i PinType) String() string { + if i < 0 || i >= PinType(len(_PinType_index)-1) { + return "PinType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _PinType_name[_PinType_index[i]:_PinType_index[i+1]] +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/aufs.go containerd-1.5.9/vendor/github.com/containerd/aufs/aufs.go --- containerd-1.2.6/vendor/github.com/containerd/aufs/aufs.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/aufs.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package aufs import ( @@ -16,27 +32,12 @@ "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/continuity/fs" "github.com/pkg/errors" ) -func init() { - plugin.Register(&plugin.Registration{ - Type: plugin.SnapshotPlugin, - ID: "aufs", - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) - ic.Meta.Exports["root"] = ic.Root - return New(ic.Root) - }, - }) - -} - var ( dirperm sync.Once dirpermEnabled bool @@ -99,8 +100,7 @@ // Usage returns the resources taken by the snapshot identified by key. // -// For active snapshots, this will scan the usage of the overlay "diff" (aka -// "upper") directory and may take some time. +// For active snapshots, this will scan the usage of directory and may take some time. // // For committed snapshots, the value is returned from the metadata database. func (o *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { @@ -229,13 +229,13 @@ } // Walk the committed snapshots. -func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (o *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { return err } defer t.Rollback() - return storage.WalkInfo(ctx, fn) + return storage.WalkInfo(ctx, fn, filters...) } func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) ([]mount.Mount, error) { @@ -318,8 +318,7 @@ func (o *snapshotter) mounts(s storage.Snapshot) []mount.Mount { if len(s.ParentIDs) == 0 { - // if we only have one layer/no parents then just return a bind mount as overlay - // will not work + // if we only have one layer/no parents then just return a bind mount roFlag := "rw" if s.Kind == snapshots.KindView { roFlag = "ro" @@ -386,10 +385,11 @@ func supported() error { // modprobe the aufs module before checking + var probeError string cmd := exec.Command("modprobe", "aufs") out, err := cmd.CombinedOutput() if err != nil { - return errors.Wrapf(err, "modprobe aufs failed: %q", out) + probeError = fmt.Sprintf(" (modprobe aufs failed: %v %q)", err, out) } f, err := os.Open("/proc/filesystems") @@ -404,7 +404,7 @@ return nil } } - return errors.Errorf("aufs is not supported") + return errors.Errorf("aufs is not supported" + probeError) } // useDirperm checks dirperm1 mount option can be used with the current diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/aufs/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/aufs/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,22 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +issues: + include: + - EXC0002 + +run: + timeout: 2m diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/go.mod containerd-1.5.9/vendor/github.com/containerd/aufs/go.mod --- containerd-1.2.6/vendor/github.com/containerd/aufs/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,10 @@ +module github.com/containerd/aufs + +go 1.13 + +require ( + github.com/containerd/containerd v1.5.0-beta.3 + github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e + github.com/pkg/errors v0.9.1 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/go.sum containerd-1.5.9/vendor/github.com/containerd/aufs/go.sum --- containerd-1.2.6/vendor/github.com/containerd/aufs/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,836 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3 h1:mw6pDQqv38/WGF1cO/jF5t/jyAJ2yi7CmtFLLO5tGFI= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15 h1:Aof83YILRs2Vx3GhHqlvvfyx1asRJKMFIMeVlHsZKtI= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3 h1:hIqwXglcRyu4qbOmm+pBfQ1gf3wl3VziUAZED5ng2v8= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1 h1:PvuK4E3D5S5q6IqsPDCy928FhP0LUIGcmZ/Yhgp5Djw= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/plugin/plugin.go containerd-1.5.9/vendor/github.com/containerd/aufs/plugin/plugin.go --- containerd-1.2.6/vendor/github.com/containerd/aufs/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package plugin + +import ( + "github.com/containerd/aufs" + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/pkg/errors" +) + +// Config represents configuration for the zfs plugin +type Config struct { + // Root directory for the plugin + RootPath string `toml:"root_path"` +} + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.SnapshotPlugin, + ID: "aufs", + Config: &Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) + + // get config + config, ok := ic.Config.(*Config) + if !ok { + return nil, errors.New("invalid aufs configuration") + } + + // use default ic.Root as root path if config doesn't have a valid root path + root := ic.Root + if len(config.RootPath) != 0 { + root = config.RootPath + } + ic.Meta.Exports["root"] = root + + snapshotter, err := aufs.New(root) + if err != nil { + return nil, errors.Wrap(plugin.ErrSkipPlugin, err.Error()) + } + return snapshotter, nil + }, + }) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/aufs/README.md containerd-1.5.9/vendor/github.com/containerd/aufs/README.md --- containerd-1.2.6/vendor/github.com/containerd/aufs/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/aufs/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,8 +1,9 @@ # aufs snapshotter -[![Build Status](https://travis-ci.org/containerd/aufs.svg?branch=master)](https://travis-ci.org/containerd/aufs) - +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/aufs)](https://pkg.go.dev/github.com/containerd/aufs) +[![Build Status](https://github.com/containerd/aufs/workflows/CI/badge.svg)](https://github.com/containerd/aufs/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/containerd/aufs/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/aufs) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/aufs)](https://goreportcard.com/report/github.com/containerd/aufs) AUFS implementation of the snapshot interface for containerd. @@ -21,3 +22,13 @@ _ "github.com/containerd/containerd/snapshot/overlay" ) ``` + +## Project details + +aufs is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.c containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.c --- containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.c 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + #include #include #include diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.go containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.go --- containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - Copyright The containerd Authors + Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,9 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -package btrfs -import "sort" +package btrfs /* #include @@ -31,12 +30,17 @@ import ( "os" "path/filepath" + "sort" "syscall" "unsafe" "github.com/pkg/errors" ) +// maxByteSliceSize is the smallest size that Go supports on various platforms. +// On mipsle, 1<<31-1 overflows the address space. +const maxByteSliceSize = 1 << 30 + // IsSubvolume returns nil if the path is a valid subvolume. An error is // returned if the path does not exist or the path is not a valid subvolume. func IsSubvolume(path string) error { @@ -130,7 +134,7 @@ var ( sh C.struct_btrfs_ioctl_search_header shSize = unsafe.Sizeof(sh) - buf = (*[1<<31 - 1]byte)(unsafe.Pointer(&args.buf[0]))[:C.BTRFS_SEARCH_ARGS_BUFSIZE] + buf = (*[maxByteSliceSize]byte)(unsafe.Pointer(&args.buf[0]))[:C.BTRFS_SEARCH_ARGS_BUFSIZE] ) for i := 0; i < int(args.key.nr_items); i++ { @@ -271,7 +275,7 @@ if len(name) > C.BTRFS_PATH_NAME_MAX { return errors.Errorf("%q too long for subvolume", name) } - nameptr := (*[1<<31 - 1]byte)(unsafe.Pointer(&args.name[0])) + nameptr := (*[maxByteSliceSize]byte)(unsafe.Pointer(&args.name[0]))[:C.BTRFS_PATH_NAME_MAX:C.BTRFS_PATH_NAME_MAX] copy(nameptr[:C.BTRFS_PATH_NAME_MAX], []byte(name)) if err := ioctl(fp.Fd(), C.BTRFS_IOC_SUBVOL_CREATE, uintptr(unsafe.Pointer(&args))); err != nil { @@ -288,7 +292,7 @@ dstfp, err := openSubvolDir(dstdir) if err != nil { - return errors.Wrapf(err, "opening snapshot desination subvolume failed") + return errors.Wrapf(err, "opening snapshot destination subvolume failed") } defer dstfp.Close() @@ -307,7 +311,7 @@ return errors.Errorf("%q too long for subvolume", dstname) } - nameptr := (*[1<<31 - 1]byte)(unsafe.Pointer(name)) + nameptr := (*[maxByteSliceSize]byte)(unsafe.Pointer(name))[:C.BTRFS_SUBVOL_NAME_MAX:C.BTRFS_SUBVOL_NAME_MAX] copy(nameptr[:C.BTRFS_SUBVOL_NAME_MAX], []byte(dstname)) if readonly { @@ -366,7 +370,7 @@ return errors.Errorf("%q too long for subvolume", name) } - nameptr := (*[1<<31 - 1]byte)(unsafe.Pointer(&args.name[0])) + nameptr := (*[maxByteSliceSize]byte)(unsafe.Pointer(&args.name[0]))[:C.BTRFS_SUBVOL_NAME_MAX:C.BTRFS_SUBVOL_NAME_MAX] copy(nameptr[:C.BTRFS_SUBVOL_NAME_MAX], []byte(name)) if err := ioctl(fp.Fd(), C.BTRFS_IOC_SNAP_DESTROY, uintptr(unsafe.Pointer(&args))); err != nil { diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.h containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.h --- containerd-1.2.6/vendor/github.com/containerd/btrfs/btrfs.h 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/btrfs.h 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + #include #include #include diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/doc.go containerd-1.5.9/vendor/github.com/containerd/btrfs/doc.go --- containerd-1.2.6/vendor/github.com/containerd/btrfs/doc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - Copyright The containerd Authors + Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,5 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. */ + // Package btrfs provides bindings for working with btrfs partitions from Go. package btrfs diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/.gitignore containerd-1.5.9/vendor/github.com/containerd/btrfs/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/btrfs/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so +bin/ + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# Support running go modules in vendor mode for local development +/vendor/ diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/go.mod containerd-1.5.9/vendor/github.com/containerd/btrfs/go.mod --- containerd-1.2.6/vendor/github.com/containerd/btrfs/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +module github.com/containerd/btrfs + +go 1.15 + +require github.com/pkg/errors v0.9.1 diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/go.sum containerd-1.5.9/vendor/github.com/containerd/btrfs/go.sum --- containerd-1.2.6/vendor/github.com/containerd/btrfs/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/helpers.go containerd-1.5.9/vendor/github.com/containerd/btrfs/helpers.go --- containerd-1.2.6/vendor/github.com/containerd/btrfs/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - Copyright The containerd Authors + Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ + package btrfs /* @@ -50,7 +51,7 @@ ) func uuidString(uuid *[C.BTRFS_UUID_SIZE]C.u8) string { - b := (*[1<<31 - 1]byte)(unsafe.Pointer(uuid))[:C.BTRFS_UUID_SIZE] + b := (*[maxByteSliceSize]byte)(unsafe.Pointer(uuid))[:C.BTRFS_UUID_SIZE] if bytes.Equal(b, zeros) { return "" diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/info.go containerd-1.5.9/vendor/github.com/containerd/btrfs/info.go --- containerd-1.2.6/vendor/github.com/containerd/btrfs/info.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/info.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - Copyright The containerd Authors + Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ + package btrfs // Info describes metadata about a btrfs subvolume. diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/ioctl.go containerd-1.5.9/vendor/github.com/containerd/btrfs/ioctl.go --- containerd-1.2.6/vendor/github.com/containerd/btrfs/ioctl.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/ioctl.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - Copyright The containerd Authors + Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ + package btrfs import "syscall" diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/Makefile containerd-1.5.9/vendor/github.com/containerd/btrfs/Makefile --- containerd-1.2.6/vendor/github.com/containerd/btrfs/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +.PHONY: clean binaries generate lint vet test +all: vet lint test binaries + +binaries: bin/btrfs-test + +vet: + go vet ./... + +lint: + golint ./... + +test: + go test -v ./... + +bin/%: ./cmd/% *.go + go build -o ./$@ ./$< + +clean: + rm -rf bin/* diff -Nru containerd-1.2.6/vendor/github.com/containerd/btrfs/README.md containerd-1.5.9/vendor/github.com/containerd/btrfs/README.md --- containerd-1.2.6/vendor/github.com/containerd/btrfs/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/btrfs/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,5 +1,8 @@ # go-btrfs -[![GoDoc](https://godoc.org/github.com/containerd/btrfs?status.svg)](https://godoc.org/github.com/containerd/btrfs) [![Build Status](https://travis-ci.org/stevvooe/go-btrfs.svg?branch=master)](https://travis-ci.org/stevvooe/go-btrfs) + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/btrfs)](https://pkg.go.dev/github.com/containerd/btrfs) +[![Build Status](https://github.com/containerd/btrfs/workflows/CI/badge.svg)](https://github.com/containerd/btrfs/actions?query=workflow%3ACI) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/btrfs)](https://goreportcard.com/report/github.com/containerd/btrfs) Native Go bindings for btrfs. @@ -14,7 +17,7 @@ is missing, please don't hesitate to submit a PR. Note that due to struct alignment issues, this isn't yet fully native. -Preferrably, this could be resolved, so contributions in this direction are +Preferably, this could be resolved, so contributions in this direction are greatly appreciated. ## Applying License Header to New Files @@ -30,9 +33,14 @@ The above will add the appropriate licenses to Go files. New templates will need to be added if other kinds of files are added. Please consult the -documentation at https://github.com/ +documentation at https://github.com/kunalkushwaha/ltag + +## Project details -# License +btrfs is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) -The copyright to this repository is held by the The containerd Authors and the -codebase is released under the [Apache 2.0 license](LICENSE). +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/blkio.go containerd-1.5.9/vendor/github.com/containerd/cgroups/blkio.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/blkio.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/blkio.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,23 +20,38 @@ "bufio" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" "strings" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) -func NewBlkio(root string) *blkioController { - return &blkioController{ - root: filepath.Join(root, string(Blkio)), +// NewBlkio returns a Blkio controller given the root folder of cgroups. +// It may optionally accept other configuration options, such as ProcRoot(path) +func NewBlkio(root string, options ...func(controller *blkioController)) *blkioController { + ctrl := &blkioController{ + root: filepath.Join(root, string(Blkio)), + procRoot: "/proc", + } + for _, opt := range options { + opt(ctrl) + } + return ctrl +} + +// ProcRoot overrides the default location of the "/proc" filesystem +func ProcRoot(path string) func(controller *blkioController) { + return func(c *blkioController) { + c.procRoot = path } } type blkioController struct { - root string + root string + procRoot string } func (b *blkioController) Name() Name { @@ -56,8 +71,8 @@ } for _, t := range createBlkioSettings(resources.BlockIO) { if t.value != nil { - if err := ioutil.WriteFile( - filepath.Join(b.Path(path), fmt.Sprintf("blkio.%s", t.name)), + if err := retryingWriteFile( + filepath.Join(b.Path(path), "blkio."+t.name), t.format(t.value), defaultFilePerm, ); err != nil { @@ -72,56 +87,50 @@ return b.Create(path, resources) } -func (b *blkioController) Stat(path string, stats *Metrics) error { - stats.Blkio = &BlkIOStat{} - settings := []blkioStatSettings{ - { - name: "throttle.io_serviced", - entry: &stats.Blkio.IoServicedRecursive, - }, - { - name: "throttle.io_service_bytes", - entry: &stats.Blkio.IoServiceBytesRecursive, - }, - } +func (b *blkioController) Stat(path string, stats *v1.Metrics) error { + stats.Blkio = &v1.BlkIOStat{} + + var settings []blkioStatSettings + // Try to read CFQ stats available on all CFQ enabled kernels first - if _, err := os.Lstat(filepath.Join(b.Path(path), fmt.Sprintf("blkio.io_serviced_recursive"))); err == nil { - settings = append(settings, - blkioStatSettings{ + if _, err := os.Lstat(filepath.Join(b.Path(path), "blkio.io_serviced_recursive")); err == nil { + settings = []blkioStatSettings{ + { name: "sectors_recursive", entry: &stats.Blkio.SectorsRecursive, }, - blkioStatSettings{ + { name: "io_service_bytes_recursive", entry: &stats.Blkio.IoServiceBytesRecursive, }, - blkioStatSettings{ + { name: "io_serviced_recursive", entry: &stats.Blkio.IoServicedRecursive, }, - blkioStatSettings{ + { name: "io_queued_recursive", entry: &stats.Blkio.IoQueuedRecursive, }, - blkioStatSettings{ + { name: "io_service_time_recursive", entry: &stats.Blkio.IoServiceTimeRecursive, }, - blkioStatSettings{ + { name: "io_wait_time_recursive", entry: &stats.Blkio.IoWaitTimeRecursive, }, - blkioStatSettings{ + { name: "io_merged_recursive", entry: &stats.Blkio.IoMergedRecursive, }, - blkioStatSettings{ + { name: "time_recursive", entry: &stats.Blkio.IoTimeRecursive, }, - ) + } } - f, err := os.Open("/proc/diskstats") + + f, err := os.Open(filepath.Join(b.procRoot, "diskstats")) if err != nil { return err } @@ -132,6 +141,29 @@ return err } + var size int + for _, t := range settings { + if err := b.readEntry(devices, path, t.name, t.entry); err != nil { + return err + } + size += len(*t.entry) + } + if size > 0 { + return nil + } + + // Even the kernel is compiled with the CFQ scheduler, the cgroup may not use + // block devices with the CFQ scheduler. If so, we should fallback to throttle.* files. + settings = []blkioStatSettings{ + { + name: "throttle.io_serviced", + entry: &stats.Blkio.IoServicedRecursive, + }, + { + name: "throttle.io_service_bytes", + entry: &stats.Blkio.IoServiceBytesRecursive, + }, + } for _, t := range settings { if err := b.readEntry(devices, path, t.name, t.entry); err != nil { return err @@ -140,17 +172,14 @@ return nil } -func (b *blkioController) readEntry(devices map[deviceKey]string, path, name string, entry *[]*BlkIOEntry) error { - f, err := os.Open(filepath.Join(b.Path(path), fmt.Sprintf("blkio.%s", name))) +func (b *blkioController) readEntry(devices map[deviceKey]string, path, name string, entry *[]*v1.BlkIOEntry) error { + f, err := os.Open(filepath.Join(b.Path(path), "blkio."+name)) if err != nil { return err } defer f.Close() sc := bufio.NewScanner(f) for sc.Scan() { - if err := sc.Err(); err != nil { - return err - } // format: dev type amount fields := strings.FieldsFunc(sc.Text(), splitBlkIOStatLine) if len(fields) < 3 { @@ -158,7 +187,7 @@ // skip total line continue } else { - return fmt.Errorf("Invalid line found while parsing %s: %s", path, sc.Text()) + return fmt.Errorf("invalid line found while parsing %s: %s", path, sc.Text()) } } major, err := strconv.ParseUint(fields[0], 10, 64) @@ -179,7 +208,7 @@ if err != nil { return err } - *entry = append(*entry, &BlkIOEntry{ + *entry = append(*entry, &v1.BlkIOEntry{ Device: devices[deviceKey{major, minor}], Major: major, Minor: minor, @@ -187,7 +216,7 @@ Value: v, }) } - return nil + return sc.Err() } func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings { @@ -267,7 +296,7 @@ type blkioStatSettings struct { name string - entry *[]*BlkIOEntry + entry *[]*v1.BlkIOEntry } func uintf(v interface{}) []byte { @@ -327,11 +356,3 @@ } return devices, s.Err() } - -func major(devNumber uint64) uint64 { - return (devNumber >> 8) & 0xfff -} - -func minor(devNumber uint64) uint64 { - return (devNumber & 0xff) | ((devNumber >> 12) & 0xfff00) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/cgroup.go containerd-1.5.9/vendor/github.com/containerd/cgroups/cgroup.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/cgroup.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/cgroup.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,13 +18,13 @@ import ( "fmt" - "io/ioutil" "os" "path/filepath" "strconv" "strings" "sync" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -66,6 +66,7 @@ } // Load will load an existing cgroup and allow it to be controlled +// All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) { config := newInitConfig() for _, o := range opts { @@ -167,7 +168,7 @@ if err != nil { return err } - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(s.Path(p), cgroupProcs), []byte(strconv.Itoa(process.Pid)), defaultFilePerm, @@ -197,7 +198,7 @@ if err != nil { return err } - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(s.Path(p), cgroupTasks), []byte(strconv.Itoa(process.Pid)), defaultFilePerm, @@ -215,7 +216,7 @@ if c.err != nil { return c.err } - var errors []string + var errs []string for _, s := range c.subsystems { if d, ok := s.(deleter); ok { sp, err := c.path(s.Name()) @@ -223,7 +224,7 @@ return err } if err := d.Delete(sp); err != nil { - errors = append(errors, string(s.Name())) + errs = append(errs, string(s.Name())) } continue } @@ -234,19 +235,19 @@ } path := p.Path(sp) if err := remove(path); err != nil { - errors = append(errors, path) + errs = append(errs, path) } } } - if len(errors) > 0 { - return fmt.Errorf("cgroups: unable to remove paths %s", strings.Join(errors, ", ")) + if len(errs) > 0 { + return fmt.Errorf("cgroups: unable to remove paths %s", strings.Join(errs, ", ")) } c.err = ErrCgroupDeleted return nil } // Stat returns the current metrics for the cgroup -func (c *cgroup) Stat(handlers ...ErrorHandler) (*Metrics, error) { +func (c *cgroup) Stat(handlers ...ErrorHandler) (*v1.Metrics, error) { c.mu.Lock() defer c.mu.Unlock() if c.err != nil { @@ -256,10 +257,10 @@ handlers = append(handlers, errPassthrough) } var ( - stats = &Metrics{ - CPU: &CPUStat{ - Throttling: &Throttle{}, - Usage: &CPUUsage{}, + stats = &v1.Metrics{ + CPU: &v1.CPUStat{ + Throttling: &v1.Throttle{}, + Usage: &v1.CPUUsage{}, }, } wg = &sync.WaitGroup{} @@ -456,7 +457,26 @@ if err != nil { return 0, err } - return s.(*memoryController).OOMEventFD(sp) + return s.(*memoryController).memoryEvent(sp, OOMEvent()) +} + +// RegisterMemoryEvent allows the ability to register for all v1 memory cgroups +// notifications. +func (c *cgroup) RegisterMemoryEvent(event MemoryEvent) (uintptr, error) { + c.mu.Lock() + defer c.mu.Unlock() + if c.err != nil { + return 0, c.err + } + s := c.getSubsystem(Memory) + if s == nil { + return 0, ErrMemoryNotSupported + } + sp, err := c.path(Memory) + if err != nil { + return 0, err + } + return s.(*memoryController).memoryEvent(sp, event) } // State returns the state of the cgroup and its processes @@ -497,6 +517,9 @@ } for _, p := range processes { if err := destination.Add(p); err != nil { + if strings.Contains(err.Error(), "no such process") { + continue + } return err } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/control.go containerd-1.5.9/vendor/github.com/containerd/cgroups/control.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/control.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/control.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,6 +19,7 @@ import ( "os" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -68,7 +69,7 @@ // subsystems are moved one at a time MoveTo(Cgroup) error // Stat returns the stats for all subsystems in the cgroup - Stat(...ErrorHandler) (*Metrics, error) + Stat(...ErrorHandler) (*v1.Metrics, error) // Update updates all the subsystems with the provided resource changes Update(resources *specs.LinuxResources) error // Processes returns all the processes in a select subsystem for the cgroup @@ -81,6 +82,9 @@ Thaw() error // OOMEventFD returns the memory subsystem's event fd for OOM events OOMEventFD() (uintptr, error) + // RegisterMemoryEvent returns the memory subsystems event fd for whatever memory event was + // registered for. Can alternatively register for the oom event with this method. + RegisterMemoryEvent(MemoryEvent) (uintptr, error) // State returns the cgroups current state State() State // Subsystems returns all the subsystems in the cgroup diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/cpuacct.go containerd-1.5.9/vendor/github.com/containerd/cgroups/cpuacct.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/cpuacct.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/cpuacct.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,6 +22,8 @@ "path/filepath" "strconv" "strings" + + v1 "github.com/containerd/cgroups/stats/v1" ) const nanosecondsInSecond = 1000000000 @@ -46,7 +48,7 @@ return filepath.Join(c.root, path) } -func (c *cpuacctController) Stat(path string, stats *Metrics) error { +func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error { user, kernel, err := c.getUsage(path) if err != nil { return err diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/cpu.go containerd-1.5.9/vendor/github.com/containerd/cgroups/cpu.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/cpu.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/cpu.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,12 +18,11 @@ import ( "bufio" - "fmt" - "io/ioutil" "os" "path/filepath" "strconv" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -83,8 +82,8 @@ value = []byte(strconv.FormatInt(*t.ivalue, 10)) } if value != nil { - if err := ioutil.WriteFile( - filepath.Join(c.Path(path), fmt.Sprintf("cpu.%s", t.name)), + if err := retryingWriteFile( + filepath.Join(c.Path(path), "cpu."+t.name), value, defaultFilePerm, ); err != nil { @@ -100,7 +99,7 @@ return c.Create(path, resources) } -func (c *cpuController) Stat(path string, stats *Metrics) error { +func (c *cpuController) Stat(path string, stats *v1.Metrics) error { f, err := os.Open(filepath.Join(c.Path(path), "cpu.stat")) if err != nil { return err @@ -109,9 +108,6 @@ // get or create the cpu field because cpuacct can also set values on this struct sc := bufio.NewScanner(f) for sc.Scan() { - if err := sc.Err(); err != nil { - return err - } key, v, err := parseKV(sc.Text()) if err != nil { return err @@ -125,5 +121,5 @@ stats.CPU.Throttling.ThrottledTime = v } } - return nil + return sc.Err() } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/cpuset.go containerd-1.5.9/vendor/github.com/containerd/cgroups/cpuset.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/cpuset.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/cpuset.go 2022-01-05 17:30:58.000000000 +0000 @@ -26,7 +26,7 @@ specs "github.com/opencontainers/runtime-spec/specs-go" ) -func NewCputset(root string) *cpusetController { +func NewCpuset(root string) *cpusetController { return &cpusetController{ root: filepath.Join(root, string(Cpuset)), } @@ -69,8 +69,8 @@ }, } { if t.value != "" { - if err := ioutil.WriteFile( - filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)), + if err := retryingWriteFile( + filepath.Join(c.Path(path), "cpuset."+t.name), []byte(t.value), defaultFilePerm, ); err != nil { @@ -134,7 +134,7 @@ return err } if isEmpty(currentCpus) { - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(current, "cpuset.cpus"), parentCpus, defaultFilePerm, @@ -143,7 +143,7 @@ } } if isEmpty(currentMems) { - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(current, "cpuset.mems"), parentMems, defaultFilePerm, diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/devices.go containerd-1.5.9/vendor/github.com/containerd/cgroups/devices.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/devices.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/devices.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,7 +18,6 @@ import ( "fmt" - "io/ioutil" "os" "path/filepath" @@ -61,7 +60,7 @@ if device.Type == "" { device.Type = "a" } - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(d.Path(path), file), []byte(deviceString(device)), defaultFilePerm, diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/freezer.go containerd-1.5.9/vendor/github.com/containerd/cgroups/freezer.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/freezer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/freezer.go 2022-01-05 17:30:58.000000000 +0000 @@ -50,7 +50,7 @@ } func (f *freezerController) changeState(path string, state State) error { - return ioutil.WriteFile( + return retryingWriteFile( filepath.Join(f.root, path, "freezer.state"), []byte(strings.ToUpper(string(state))), defaultFilePerm, diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/.gitignore containerd-1.5.9/vendor/github.com/containerd/cgroups/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/cgroups/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +example/example +cmd/cgctl/cgctl diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/go.mod containerd-1.5.9/vendor/github.com/containerd/cgroups/go.mod --- containerd-1.2.6/vendor/github.com/containerd/cgroups/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +module github.com/containerd/cgroups + +go 1.13 + +require ( + github.com/cilium/ebpf v0.4.0 + github.com/coreos/go-systemd/v22 v22.1.0 + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/docker/go-units v0.4.0 + github.com/godbus/dbus/v5 v5.0.3 + github.com/gogo/protobuf v1.3.2 + github.com/opencontainers/runtime-spec v1.0.2 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + github.com/stretchr/testify v1.6.1 + github.com/urfave/cli v1.22.2 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/go.sum containerd-1.5.9/vendor/github.com/containerd/cgroups/go.sum --- containerd-1.2.6/vendor/github.com/containerd/cgroups/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,82 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/cilium/ebpf v0.4.0 h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/hierarchy.go containerd-1.5.9/vendor/github.com/containerd/cgroups/hierarchy.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/hierarchy.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/hierarchy.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,5 +16,5 @@ package cgroups -// Hierarchy enableds both unified and split hierarchy for cgroups +// Hierarchy enables both unified and split hierarchy for cgroups type Hierarchy func() ([]Subsystem, error) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/hugetlb.go containerd-1.5.9/vendor/github.com/containerd/cgroups/hugetlb.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/hugetlb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/hugetlb.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,12 +17,12 @@ package cgroups import ( - "io/ioutil" "os" "path/filepath" "strconv" "strings" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -56,7 +56,7 @@ return err } for _, limit := range resources.HugepageLimits { - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(h.Path(path), strings.Join([]string{"hugetlb", limit.Pagesize, "limit_in_bytes"}, ".")), []byte(strconv.FormatUint(limit.Limit, 10)), defaultFilePerm, @@ -67,7 +67,7 @@ return nil } -func (h *hugetlbController) Stat(path string, stats *Metrics) error { +func (h *hugetlbController) Stat(path string, stats *v1.Metrics) error { for _, size := range h.sizes { s, err := h.readSizeStat(path, size) if err != nil { @@ -78,8 +78,8 @@ return nil } -func (h *hugetlbController) readSizeStat(path, size string) (*HugetlbStat, error) { - s := HugetlbStat{ +func (h *hugetlbController) readSizeStat(path, size string) (*v1.HugetlbStat, error) { + s := v1.HugetlbStat{ Pagesize: size, } for _, t := range []struct { diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/Makefile containerd-1.5.9/vendor/github.com/containerd/cgroups/Makefile --- containerd-1.2.6/vendor/github.com/containerd/cgroups/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,24 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +PACKAGES=$(shell go list ./... | grep -v /vendor/) + +all: cgutil + go build -v + +cgutil: + cd cmd/cgctl && go build -v + +proto: + protobuild --quiet ${PACKAGES} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/memory.go containerd-1.5.9/vendor/github.com/containerd/cgroups/memory.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/memory.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/memory.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,26 +20,175 @@ "bufio" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" "strings" - "syscall" + v1 "github.com/containerd/cgroups/stats/v1" + specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" +) - specs "github.com/opencontainers/runtime-spec/specs-go" +// MemoryEvent is an interface that V1 memory Cgroup notifications implement. Arg returns the +// file name whose fd should be written to "cgroups.event_control". EventFile returns the name of +// the file that supports the notification api e.g. "memory.usage_in_bytes". +type MemoryEvent interface { + Arg() string + EventFile() string +} + +type memoryThresholdEvent struct { + threshold uint64 + swap bool +} + +// MemoryThresholdEvent returns a new memory threshold event to be used with RegisterMemoryEvent. +// If swap is true, the event will be registered using memory.memsw.usage_in_bytes +func MemoryThresholdEvent(threshold uint64, swap bool) MemoryEvent { + return &memoryThresholdEvent{ + threshold, + swap, + } +} + +func (m *memoryThresholdEvent) Arg() string { + return strconv.FormatUint(m.threshold, 10) +} + +func (m *memoryThresholdEvent) EventFile() string { + if m.swap { + return "memory.memsw.usage_in_bytes" + } + return "memory.usage_in_bytes" +} + +type oomEvent struct{} + +// OOMEvent returns a new oom event to be used with RegisterMemoryEvent. +func OOMEvent() MemoryEvent { + return &oomEvent{} +} + +func (oom *oomEvent) Arg() string { + return "" +} + +func (oom *oomEvent) EventFile() string { + return "memory.oom_control" +} + +type memoryPressureEvent struct { + pressureLevel MemoryPressureLevel + hierarchy EventNotificationMode +} + +// MemoryPressureEvent returns a new memory pressure event to be used with RegisterMemoryEvent. +func MemoryPressureEvent(pressureLevel MemoryPressureLevel, hierarchy EventNotificationMode) MemoryEvent { + return &memoryPressureEvent{ + pressureLevel, + hierarchy, + } +} + +func (m *memoryPressureEvent) Arg() string { + return string(m.pressureLevel) + "," + string(m.hierarchy) +} + +func (m *memoryPressureEvent) EventFile() string { + return "memory.pressure_level" +} + +// MemoryPressureLevel corresponds to the memory pressure levels defined +// for memory cgroups. +type MemoryPressureLevel string + +// The three memory pressure levels are as follows. +// - The "low" level means that the system is reclaiming memory for new +// allocations. Monitoring this reclaiming activity might be useful for +// maintaining cache level. Upon notification, the program (typically +// "Activity Manager") might analyze vmstat and act in advance (i.e. +// prematurely shutdown unimportant services). +// - The "medium" level means that the system is experiencing medium memory +// pressure, the system might be making swap, paging out active file caches, +// etc. Upon this event applications may decide to further analyze +// vmstat/zoneinfo/memcg or internal memory usage statistics and free any +// resources that can be easily reconstructed or re-read from a disk. +// - The "critical" level means that the system is actively thrashing, it is +// about to out of memory (OOM) or even the in-kernel OOM killer is on its +// way to trigger. Applications should do whatever they can to help the +// system. It might be too late to consult with vmstat or any other +// statistics, so it is advisable to take an immediate action. +// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11 +const ( + LowPressure MemoryPressureLevel = "low" + MediumPressure MemoryPressureLevel = "medium" + CriticalPressure MemoryPressureLevel = "critical" +) + +// EventNotificationMode corresponds to the notification modes +// for the memory cgroups pressure level notifications. +type EventNotificationMode string + +// There are three optional modes that specify different propagation behavior: +// - "default": this is the default behavior specified above. This mode is the +// same as omitting the optional mode parameter, preserved by backwards +// compatibility. +// - "hierarchy": events always propagate up to the root, similar to the default +// behavior, except that propagation continues regardless of whether there are +// event listeners at each level, with the "hierarchy" mode. In the above +// example, groups A, B, and C will receive notification of memory pressure. +// - "local": events are pass-through, i.e. they only receive notifications when +// memory pressure is experienced in the memcg for which the notification is +// registered. In the above example, group C will receive notification if +// registered for "local" notification and the group experiences memory +// pressure. However, group B will never receive notification, regardless if +// there is an event listener for group C or not, if group B is registered for +// local notification. +// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11 +const ( + DefaultMode EventNotificationMode = "default" + LocalMode EventNotificationMode = "local" + HierarchyMode EventNotificationMode = "hierarchy" ) -func NewMemory(root string) *memoryController { - return &memoryController{ - root: filepath.Join(root, string(Memory)), +// NewMemory returns a Memory controller given the root folder of cgroups. +// It may optionally accept other configuration options, such as IgnoreModules(...) +func NewMemory(root string, options ...func(*memoryController)) *memoryController { + mc := &memoryController{ + root: filepath.Join(root, string(Memory)), + ignored: map[string]struct{}{}, + } + for _, opt := range options { + opt(mc) + } + return mc +} + +// IgnoreModules configure the memory controller to not read memory metrics for some +// module names (e.g. passing "memsw" would avoid all the memory.memsw.* entries) +func IgnoreModules(names ...string) func(*memoryController) { + return func(mc *memoryController) { + for _, name := range names { + mc.ignored[name] = struct{}{} + } + } +} + +// OptionalSwap allows the memory controller to not fail if cgroups is not accounting +// Swap memory (there are no memory.memsw.* entries) +func OptionalSwap() func(*memoryController) { + return func(mc *memoryController) { + _, err := os.Stat(filepath.Join(mc.root, "memory.memsw.usage_in_bytes")) + if os.IsNotExist(err) { + mc.ignored["memsw"] = struct{}{} + } } } type memoryController struct { - root string + root string + ignored map[string]struct{} } func (m *memoryController) Name() Name { @@ -57,21 +206,6 @@ if resources.Memory == nil { return nil } - if resources.Memory.Kernel != nil { - // Check if kernel memory is enabled - // We have to limit the kernel memory here as it won't be accounted at all - // until a limit is set on the cgroup and limit cannot be set once the - // cgroup has children, or if there are already tasks in the cgroup. - for _, i := range []int64{1, -1} { - if err := ioutil.WriteFile( - filepath.Join(m.Path(path), "memory.kmem.limit_in_bytes"), - []byte(strconv.FormatInt(i, 10)), - defaultFilePerm, - ); err != nil { - return checkEBUSY(err) - } - } - } return m.set(path, getMemorySettings(resources)) } @@ -97,24 +231,34 @@ return m.set(path, settings) } -func (m *memoryController) Stat(path string, stats *Metrics) error { - f, err := os.Open(filepath.Join(m.Path(path), "memory.stat")) +func (m *memoryController) Stat(path string, stats *v1.Metrics) error { + fMemStat, err := os.Open(filepath.Join(m.Path(path), "memory.stat")) if err != nil { return err } - defer f.Close() - stats.Memory = &MemoryStat{ - Usage: &MemoryEntry{}, - Swap: &MemoryEntry{}, - Kernel: &MemoryEntry{}, - KernelTCP: &MemoryEntry{}, + defer fMemStat.Close() + stats.Memory = &v1.MemoryStat{ + Usage: &v1.MemoryEntry{}, + Swap: &v1.MemoryEntry{}, + Kernel: &v1.MemoryEntry{}, + KernelTCP: &v1.MemoryEntry{}, } - if err := m.parseStats(f, stats.Memory); err != nil { + if err := m.parseStats(fMemStat, stats.Memory); err != nil { + return err + } + + fMemOomControl, err := os.Open(filepath.Join(m.Path(path), "memory.oom_control")) + if err != nil { + return err + } + defer fMemOomControl.Close() + stats.MemoryOomControl = &v1.MemoryOomControl{} + if err := m.parseOomControlStats(fMemOomControl, stats.MemoryOomControl); err != nil { return err } for _, t := range []struct { module string - entry *MemoryEntry + entry *v1.MemoryEntry }{ { module: "", @@ -133,6 +277,9 @@ entry: stats.Memory.KernelTCP, }, } { + if _, ok := m.ignored[t.module]; ok { + continue + } for _, tt := range []struct { name string value *uint64 @@ -169,44 +316,13 @@ return nil } -func (m *memoryController) OOMEventFD(path string) (uintptr, error) { - root := m.Path(path) - f, err := os.Open(filepath.Join(root, "memory.oom_control")) - if err != nil { - return 0, err - } - defer f.Close() - fd, _, serr := unix.RawSyscall(unix.SYS_EVENTFD2, 0, unix.EFD_CLOEXEC, 0) - if serr != 0 { - return 0, serr - } - if err := writeEventFD(root, f.Fd(), fd); err != nil { - unix.Close(int(fd)) - return 0, err - } - return fd, nil -} - -func writeEventFD(root string, cfd, efd uintptr) error { - f, err := os.OpenFile(filepath.Join(root, "cgroup.event_control"), os.O_WRONLY, 0) - if err != nil { - return err - } - _, err = f.WriteString(fmt.Sprintf("%d %d", efd, cfd)) - f.Close() - return err -} - -func (m *memoryController) parseStats(r io.Reader, stat *MemoryStat) error { +func (m *memoryController) parseStats(r io.Reader, stat *v1.MemoryStat) error { var ( raw = make(map[string]uint64) sc = bufio.NewScanner(r) line int ) for sc.Scan() { - if err := sc.Err(); err != nil { - return err - } key, v, err := parseKV(sc.Text()) if err != nil { return fmt.Errorf("%d: %v", line, err) @@ -214,6 +330,9 @@ raw[key] = v line++ } + if err := sc.Err(); err != nil { + return err + } stat.Cache = raw["cache"] stat.RSS = raw["rss"] stat.RSSHuge = raw["rss_huge"] @@ -249,11 +368,34 @@ return nil } +func (m *memoryController) parseOomControlStats(r io.Reader, stat *v1.MemoryOomControl) error { + var ( + raw = make(map[string]uint64) + sc = bufio.NewScanner(r) + line int + ) + for sc.Scan() { + key, v, err := parseKV(sc.Text()) + if err != nil { + return fmt.Errorf("%d: %v", line, err) + } + raw[key] = v + line++ + } + if err := sc.Err(); err != nil { + return err + } + stat.OomKillDisable = raw["oom_kill_disable"] + stat.UnderOom = raw["under_oom"] + stat.OomKill = raw["oom_kill"] + return nil +} + func (m *memoryController) set(path string, settings []memorySettings) error { for _, t := range settings { if t.value != nil { - if err := ioutil.WriteFile( - filepath.Join(m.Path(path), fmt.Sprintf("memory.%s", t.name)), + if err := retryingWriteFile( + filepath.Join(m.Path(path), "memory."+t.name), []byte(strconv.FormatInt(*t.value, 10)), defaultFilePerm, ); err != nil { @@ -282,6 +424,10 @@ value: mem.Limit, }, { + name: "soft_limit_in_bytes", + value: mem.Reservation, + }, + { name: "memsw.limit_in_bytes", value: mem.Swap, }, @@ -304,18 +450,6 @@ } } -func checkEBUSY(err error) error { - if pathErr, ok := err.(*os.PathError); ok { - if errNo, ok := pathErr.Err.(syscall.Errno); ok { - if errNo == unix.EBUSY { - return fmt.Errorf( - "failed to set memory.kmem.limit_in_bytes, because either tasks have already joined this cgroup or it has children") - } - } - } - return err -} - func getOomControlValue(mem *specs.LinuxMemory) *int64 { if mem.DisableOOMKiller != nil && *mem.DisableOOMKiller { i := int64(1) @@ -323,3 +457,24 @@ } return nil } + +func (m *memoryController) memoryEvent(path string, event MemoryEvent) (uintptr, error) { + root := m.Path(path) + efd, err := unix.Eventfd(0, unix.EFD_CLOEXEC) + if err != nil { + return 0, err + } + evtFile, err := os.Open(filepath.Join(root, event.EventFile())) + if err != nil { + unix.Close(efd) + return 0, err + } + defer evtFile.Close() + data := fmt.Sprintf("%d %d %s", efd, evtFile.Fd(), event.Arg()) + evctlPath := filepath.Join(root, "cgroup.event_control") + if err := retryingWriteFile(evctlPath, []byte(data), 0700); err != nil { + unix.Close(efd) + return 0, err + } + return uintptr(efd), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/metrics.pb.go containerd-1.5.9/vendor/github.com/containerd/cgroups/metrics.pb.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/metrics.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/metrics.pb.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,4288 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: github.com/containerd/cgroups/metrics.proto -// DO NOT EDIT! - -/* - Package cgroups is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/cgroups/metrics.proto - - It has these top-level messages: - Metrics - HugetlbStat - PidsStat - CPUStat - CPUUsage - Throttle - MemoryStat - MemoryEntry - BlkIOStat - BlkIOEntry - RdmaStat - RdmaEntry -*/ -package cgroups - -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 Metrics struct { - Hugetlb []*HugetlbStat `protobuf:"bytes,1,rep,name=hugetlb" json:"hugetlb,omitempty"` - Pids *PidsStat `protobuf:"bytes,2,opt,name=pids" json:"pids,omitempty"` - CPU *CPUStat `protobuf:"bytes,3,opt,name=cpu" json:"cpu,omitempty"` - Memory *MemoryStat `protobuf:"bytes,4,opt,name=memory" json:"memory,omitempty"` - Blkio *BlkIOStat `protobuf:"bytes,5,opt,name=blkio" json:"blkio,omitempty"` - Rdma *RdmaStat `protobuf:"bytes,6,opt,name=rdma" json:"rdma,omitempty"` -} - -func (m *Metrics) Reset() { *m = Metrics{} } -func (*Metrics) ProtoMessage() {} -func (*Metrics) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{0} } - -type HugetlbStat struct { - Usage uint64 `protobuf:"varint,1,opt,name=usage,proto3" json:"usage,omitempty"` - Max uint64 `protobuf:"varint,2,opt,name=max,proto3" json:"max,omitempty"` - Failcnt uint64 `protobuf:"varint,3,opt,name=failcnt,proto3" json:"failcnt,omitempty"` - Pagesize string `protobuf:"bytes,4,opt,name=pagesize,proto3" json:"pagesize,omitempty"` -} - -func (m *HugetlbStat) Reset() { *m = HugetlbStat{} } -func (*HugetlbStat) ProtoMessage() {} -func (*HugetlbStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{1} } - -type PidsStat struct { - Current uint64 `protobuf:"varint,1,opt,name=current,proto3" json:"current,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` -} - -func (m *PidsStat) Reset() { *m = PidsStat{} } -func (*PidsStat) ProtoMessage() {} -func (*PidsStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{2} } - -type CPUStat struct { - Usage *CPUUsage `protobuf:"bytes,1,opt,name=usage" json:"usage,omitempty"` - Throttling *Throttle `protobuf:"bytes,2,opt,name=throttling" json:"throttling,omitempty"` -} - -func (m *CPUStat) Reset() { *m = CPUStat{} } -func (*CPUStat) ProtoMessage() {} -func (*CPUStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{3} } - -type CPUUsage struct { - // values in nanoseconds - Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"` - Kernel uint64 `protobuf:"varint,2,opt,name=kernel,proto3" json:"kernel,omitempty"` - User uint64 `protobuf:"varint,3,opt,name=user,proto3" json:"user,omitempty"` - PerCPU []uint64 `protobuf:"varint,4,rep,packed,name=per_cpu,json=perCpu" json:"per_cpu,omitempty"` -} - -func (m *CPUUsage) Reset() { *m = CPUUsage{} } -func (*CPUUsage) ProtoMessage() {} -func (*CPUUsage) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{4} } - -type Throttle struct { - Periods uint64 `protobuf:"varint,1,opt,name=periods,proto3" json:"periods,omitempty"` - ThrottledPeriods uint64 `protobuf:"varint,2,opt,name=throttled_periods,json=throttledPeriods,proto3" json:"throttled_periods,omitempty"` - ThrottledTime uint64 `protobuf:"varint,3,opt,name=throttled_time,json=throttledTime,proto3" json:"throttled_time,omitempty"` -} - -func (m *Throttle) Reset() { *m = Throttle{} } -func (*Throttle) ProtoMessage() {} -func (*Throttle) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{5} } - -type MemoryStat struct { - Cache uint64 `protobuf:"varint,1,opt,name=cache,proto3" json:"cache,omitempty"` - RSS uint64 `protobuf:"varint,2,opt,name=rss,proto3" json:"rss,omitempty"` - RSSHuge uint64 `protobuf:"varint,3,opt,name=rss_huge,json=rssHuge,proto3" json:"rss_huge,omitempty"` - MappedFile uint64 `protobuf:"varint,4,opt,name=mapped_file,json=mappedFile,proto3" json:"mapped_file,omitempty"` - Dirty uint64 `protobuf:"varint,5,opt,name=dirty,proto3" json:"dirty,omitempty"` - Writeback uint64 `protobuf:"varint,6,opt,name=writeback,proto3" json:"writeback,omitempty"` - PgPgIn uint64 `protobuf:"varint,7,opt,name=pg_pg_in,json=pgPgIn,proto3" json:"pg_pg_in,omitempty"` - PgPgOut uint64 `protobuf:"varint,8,opt,name=pg_pg_out,json=pgPgOut,proto3" json:"pg_pg_out,omitempty"` - PgFault uint64 `protobuf:"varint,9,opt,name=pg_fault,json=pgFault,proto3" json:"pg_fault,omitempty"` - PgMajFault uint64 `protobuf:"varint,10,opt,name=pg_maj_fault,json=pgMajFault,proto3" json:"pg_maj_fault,omitempty"` - InactiveAnon uint64 `protobuf:"varint,11,opt,name=inactive_anon,json=inactiveAnon,proto3" json:"inactive_anon,omitempty"` - ActiveAnon uint64 `protobuf:"varint,12,opt,name=active_anon,json=activeAnon,proto3" json:"active_anon,omitempty"` - InactiveFile uint64 `protobuf:"varint,13,opt,name=inactive_file,json=inactiveFile,proto3" json:"inactive_file,omitempty"` - ActiveFile uint64 `protobuf:"varint,14,opt,name=active_file,json=activeFile,proto3" json:"active_file,omitempty"` - Unevictable uint64 `protobuf:"varint,15,opt,name=unevictable,proto3" json:"unevictable,omitempty"` - HierarchicalMemoryLimit uint64 `protobuf:"varint,16,opt,name=hierarchical_memory_limit,json=hierarchicalMemoryLimit,proto3" json:"hierarchical_memory_limit,omitempty"` - HierarchicalSwapLimit uint64 `protobuf:"varint,17,opt,name=hierarchical_swap_limit,json=hierarchicalSwapLimit,proto3" json:"hierarchical_swap_limit,omitempty"` - TotalCache uint64 `protobuf:"varint,18,opt,name=total_cache,json=totalCache,proto3" json:"total_cache,omitempty"` - TotalRSS uint64 `protobuf:"varint,19,opt,name=total_rss,json=totalRss,proto3" json:"total_rss,omitempty"` - TotalRSSHuge uint64 `protobuf:"varint,20,opt,name=total_rss_huge,json=totalRssHuge,proto3" json:"total_rss_huge,omitempty"` - TotalMappedFile uint64 `protobuf:"varint,21,opt,name=total_mapped_file,json=totalMappedFile,proto3" json:"total_mapped_file,omitempty"` - TotalDirty uint64 `protobuf:"varint,22,opt,name=total_dirty,json=totalDirty,proto3" json:"total_dirty,omitempty"` - TotalWriteback uint64 `protobuf:"varint,23,opt,name=total_writeback,json=totalWriteback,proto3" json:"total_writeback,omitempty"` - TotalPgPgIn uint64 `protobuf:"varint,24,opt,name=total_pg_pg_in,json=totalPgPgIn,proto3" json:"total_pg_pg_in,omitempty"` - TotalPgPgOut uint64 `protobuf:"varint,25,opt,name=total_pg_pg_out,json=totalPgPgOut,proto3" json:"total_pg_pg_out,omitempty"` - TotalPgFault uint64 `protobuf:"varint,26,opt,name=total_pg_fault,json=totalPgFault,proto3" json:"total_pg_fault,omitempty"` - TotalPgMajFault uint64 `protobuf:"varint,27,opt,name=total_pg_maj_fault,json=totalPgMajFault,proto3" json:"total_pg_maj_fault,omitempty"` - TotalInactiveAnon uint64 `protobuf:"varint,28,opt,name=total_inactive_anon,json=totalInactiveAnon,proto3" json:"total_inactive_anon,omitempty"` - TotalActiveAnon uint64 `protobuf:"varint,29,opt,name=total_active_anon,json=totalActiveAnon,proto3" json:"total_active_anon,omitempty"` - TotalInactiveFile uint64 `protobuf:"varint,30,opt,name=total_inactive_file,json=totalInactiveFile,proto3" json:"total_inactive_file,omitempty"` - TotalActiveFile uint64 `protobuf:"varint,31,opt,name=total_active_file,json=totalActiveFile,proto3" json:"total_active_file,omitempty"` - TotalUnevictable uint64 `protobuf:"varint,32,opt,name=total_unevictable,json=totalUnevictable,proto3" json:"total_unevictable,omitempty"` - Usage *MemoryEntry `protobuf:"bytes,33,opt,name=usage" json:"usage,omitempty"` - Swap *MemoryEntry `protobuf:"bytes,34,opt,name=swap" json:"swap,omitempty"` - Kernel *MemoryEntry `protobuf:"bytes,35,opt,name=kernel" json:"kernel,omitempty"` - KernelTCP *MemoryEntry `protobuf:"bytes,36,opt,name=kernel_tcp,json=kernelTcp" json:"kernel_tcp,omitempty"` -} - -func (m *MemoryStat) Reset() { *m = MemoryStat{} } -func (*MemoryStat) ProtoMessage() {} -func (*MemoryStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{6} } - -type MemoryEntry struct { - Limit uint64 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` - Usage uint64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"` - Max uint64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` - Failcnt uint64 `protobuf:"varint,4,opt,name=failcnt,proto3" json:"failcnt,omitempty"` -} - -func (m *MemoryEntry) Reset() { *m = MemoryEntry{} } -func (*MemoryEntry) ProtoMessage() {} -func (*MemoryEntry) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{7} } - -type BlkIOStat struct { - IoServiceBytesRecursive []*BlkIOEntry `protobuf:"bytes,1,rep,name=io_service_bytes_recursive,json=ioServiceBytesRecursive" json:"io_service_bytes_recursive,omitempty"` - IoServicedRecursive []*BlkIOEntry `protobuf:"bytes,2,rep,name=io_serviced_recursive,json=ioServicedRecursive" json:"io_serviced_recursive,omitempty"` - IoQueuedRecursive []*BlkIOEntry `protobuf:"bytes,3,rep,name=io_queued_recursive,json=ioQueuedRecursive" json:"io_queued_recursive,omitempty"` - IoServiceTimeRecursive []*BlkIOEntry `protobuf:"bytes,4,rep,name=io_service_time_recursive,json=ioServiceTimeRecursive" json:"io_service_time_recursive,omitempty"` - IoWaitTimeRecursive []*BlkIOEntry `protobuf:"bytes,5,rep,name=io_wait_time_recursive,json=ioWaitTimeRecursive" json:"io_wait_time_recursive,omitempty"` - IoMergedRecursive []*BlkIOEntry `protobuf:"bytes,6,rep,name=io_merged_recursive,json=ioMergedRecursive" json:"io_merged_recursive,omitempty"` - IoTimeRecursive []*BlkIOEntry `protobuf:"bytes,7,rep,name=io_time_recursive,json=ioTimeRecursive" json:"io_time_recursive,omitempty"` - SectorsRecursive []*BlkIOEntry `protobuf:"bytes,8,rep,name=sectors_recursive,json=sectorsRecursive" json:"sectors_recursive,omitempty"` -} - -func (m *BlkIOStat) Reset() { *m = BlkIOStat{} } -func (*BlkIOStat) ProtoMessage() {} -func (*BlkIOStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{8} } - -type BlkIOEntry struct { - Op string `protobuf:"bytes,1,opt,name=op,proto3" json:"op,omitempty"` - Device string `protobuf:"bytes,2,opt,name=device,proto3" json:"device,omitempty"` - Major uint64 `protobuf:"varint,3,opt,name=major,proto3" json:"major,omitempty"` - Minor uint64 `protobuf:"varint,4,opt,name=minor,proto3" json:"minor,omitempty"` - Value uint64 `protobuf:"varint,5,opt,name=value,proto3" json:"value,omitempty"` -} - -func (m *BlkIOEntry) Reset() { *m = BlkIOEntry{} } -func (*BlkIOEntry) ProtoMessage() {} -func (*BlkIOEntry) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{9} } - -type RdmaStat struct { - Current []*RdmaEntry `protobuf:"bytes,1,rep,name=current" json:"current,omitempty"` - Limit []*RdmaEntry `protobuf:"bytes,2,rep,name=limit" json:"limit,omitempty"` -} - -func (m *RdmaStat) Reset() { *m = RdmaStat{} } -func (*RdmaStat) ProtoMessage() {} -func (*RdmaStat) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{10} } - -type RdmaEntry struct { - Device string `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` - HcaHandles uint32 `protobuf:"varint,2,opt,name=hca_handles,json=hcaHandles,proto3" json:"hca_handles,omitempty"` - HcaObjects uint32 `protobuf:"varint,3,opt,name=hca_objects,json=hcaObjects,proto3" json:"hca_objects,omitempty"` -} - -func (m *RdmaEntry) Reset() { *m = RdmaEntry{} } -func (*RdmaEntry) ProtoMessage() {} -func (*RdmaEntry) Descriptor() ([]byte, []int) { return fileDescriptorMetrics, []int{11} } - -func init() { - proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v1.Metrics") - proto.RegisterType((*HugetlbStat)(nil), "io.containerd.cgroups.v1.HugetlbStat") - proto.RegisterType((*PidsStat)(nil), "io.containerd.cgroups.v1.PidsStat") - proto.RegisterType((*CPUStat)(nil), "io.containerd.cgroups.v1.CPUStat") - proto.RegisterType((*CPUUsage)(nil), "io.containerd.cgroups.v1.CPUUsage") - proto.RegisterType((*Throttle)(nil), "io.containerd.cgroups.v1.Throttle") - proto.RegisterType((*MemoryStat)(nil), "io.containerd.cgroups.v1.MemoryStat") - proto.RegisterType((*MemoryEntry)(nil), "io.containerd.cgroups.v1.MemoryEntry") - proto.RegisterType((*BlkIOStat)(nil), "io.containerd.cgroups.v1.BlkIOStat") - proto.RegisterType((*BlkIOEntry)(nil), "io.containerd.cgroups.v1.BlkIOEntry") - proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v1.RdmaStat") - proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v1.RdmaEntry") -} -func (m *Metrics) 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 *Metrics) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Hugetlb) > 0 { - for _, msg := range m.Hugetlb { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if m.Pids != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Pids.Size())) - n1, err := m.Pids.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n1 - } - if m.CPU != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.CPU.Size())) - n2, err := m.CPU.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 - } - if m.Memory != nil { - dAtA[i] = 0x22 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Memory.Size())) - n3, err := m.Memory.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n3 - } - if m.Blkio != nil { - dAtA[i] = 0x2a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Blkio.Size())) - n4, err := m.Blkio.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n4 - } - if m.Rdma != nil { - dAtA[i] = 0x32 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Rdma.Size())) - n5, err := m.Rdma.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n5 - } - return i, nil -} - -func (m *HugetlbStat) 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 *HugetlbStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Usage != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Usage)) - } - if m.Max != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) - } - if m.Failcnt != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Failcnt)) - } - if len(m.Pagesize) > 0 { - dAtA[i] = 0x22 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(len(m.Pagesize))) - i += copy(dAtA[i:], m.Pagesize) - } - return i, nil -} - -func (m *PidsStat) 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 *PidsStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Current != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Current)) - } - if m.Limit != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Limit)) - } - return i, nil -} - -func (m *CPUStat) 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 *CPUStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Usage != nil { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size())) - n5, err := m.Usage.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n5 - } - if m.Throttling != nil { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Throttling.Size())) - n6, err := m.Throttling.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n6 - } - return i, nil -} - -func (m *CPUUsage) 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 *CPUUsage) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Total != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Total)) - } - if m.Kernel != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel)) - } - if m.User != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.User)) - } - if len(m.PerCPU) > 0 { - dAtA8 := make([]byte, len(m.PerCPU)*10) - var j7 int - for _, num := range m.PerCPU { - for num >= 1<<7 { - dAtA8[j7] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j7++ - } - dAtA8[j7] = uint8(num) - j7++ - } - dAtA[i] = 0x22 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(j7)) - i += copy(dAtA[i:], dAtA8[:j7]) - } - return i, nil -} - -func (m *Throttle) 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 *Throttle) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Periods != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Periods)) - } - if m.ThrottledPeriods != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.ThrottledPeriods)) - } - if m.ThrottledTime != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.ThrottledTime)) - } - return i, nil -} - -func (m *MemoryStat) 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 *MemoryStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.Cache != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Cache)) - } - if m.RSS != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.RSS)) - } - if m.RSSHuge != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.RSSHuge)) - } - if m.MappedFile != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.MappedFile)) - } - if m.Dirty != 0 { - dAtA[i] = 0x28 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Dirty)) - } - if m.Writeback != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Writeback)) - } - if m.PgPgIn != 0 { - dAtA[i] = 0x38 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.PgPgIn)) - } - if m.PgPgOut != 0 { - dAtA[i] = 0x40 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.PgPgOut)) - } - if m.PgFault != 0 { - dAtA[i] = 0x48 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.PgFault)) - } - if m.PgMajFault != 0 { - dAtA[i] = 0x50 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.PgMajFault)) - } - if m.InactiveAnon != 0 { - dAtA[i] = 0x58 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveAnon)) - } - if m.ActiveAnon != 0 { - dAtA[i] = 0x60 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveAnon)) - } - if m.InactiveFile != 0 { - dAtA[i] = 0x68 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveFile)) - } - if m.ActiveFile != 0 { - dAtA[i] = 0x70 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveFile)) - } - if m.Unevictable != 0 { - dAtA[i] = 0x78 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Unevictable)) - } - if m.HierarchicalMemoryLimit != 0 { - dAtA[i] = 0x80 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.HierarchicalMemoryLimit)) - } - if m.HierarchicalSwapLimit != 0 { - dAtA[i] = 0x88 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.HierarchicalSwapLimit)) - } - if m.TotalCache != 0 { - dAtA[i] = 0x90 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalCache)) - } - if m.TotalRSS != 0 { - dAtA[i] = 0x98 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalRSS)) - } - if m.TotalRSSHuge != 0 { - dAtA[i] = 0xa0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalRSSHuge)) - } - if m.TotalMappedFile != 0 { - dAtA[i] = 0xa8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalMappedFile)) - } - if m.TotalDirty != 0 { - dAtA[i] = 0xb0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalDirty)) - } - if m.TotalWriteback != 0 { - dAtA[i] = 0xb8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalWriteback)) - } - if m.TotalPgPgIn != 0 { - dAtA[i] = 0xc0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgPgIn)) - } - if m.TotalPgPgOut != 0 { - dAtA[i] = 0xc8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgPgOut)) - } - if m.TotalPgFault != 0 { - dAtA[i] = 0xd0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgFault)) - } - if m.TotalPgMajFault != 0 { - dAtA[i] = 0xd8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgMajFault)) - } - if m.TotalInactiveAnon != 0 { - dAtA[i] = 0xe0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalInactiveAnon)) - } - if m.TotalActiveAnon != 0 { - dAtA[i] = 0xe8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalActiveAnon)) - } - if m.TotalInactiveFile != 0 { - dAtA[i] = 0xf0 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalInactiveFile)) - } - if m.TotalActiveFile != 0 { - dAtA[i] = 0xf8 - i++ - dAtA[i] = 0x1 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalActiveFile)) - } - if m.TotalUnevictable != 0 { - dAtA[i] = 0x80 - i++ - dAtA[i] = 0x2 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.TotalUnevictable)) - } - if m.Usage != nil { - dAtA[i] = 0x8a - i++ - dAtA[i] = 0x2 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Usage.Size())) - n9, err := m.Usage.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n9 - } - if m.Swap != nil { - dAtA[i] = 0x92 - i++ - dAtA[i] = 0x2 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Swap.Size())) - n10, err := m.Swap.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n10 - } - if m.Kernel != nil { - dAtA[i] = 0x9a - i++ - dAtA[i] = 0x2 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel.Size())) - n11, err := m.Kernel.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n11 - } - if m.KernelTCP != nil { - dAtA[i] = 0xa2 - i++ - dAtA[i] = 0x2 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.KernelTCP.Size())) - n12, err := m.KernelTCP.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n12 - } - return i, nil -} - -func (m *MemoryEntry) 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 *MemoryEntry) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - - if m.Limit != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Limit)) - } - if m.Usage != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Usage)) - } - if m.Max != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) - } - if m.Failcnt != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Failcnt)) - } - return i, nil -} - -func (m *BlkIOStat) 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 *BlkIOStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.IoServiceBytesRecursive) > 0 { - for _, msg := range m.IoServiceBytesRecursive { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoServicedRecursive) > 0 { - for _, msg := range m.IoServicedRecursive { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoQueuedRecursive) > 0 { - for _, msg := range m.IoQueuedRecursive { - dAtA[i] = 0x1a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoServiceTimeRecursive) > 0 { - for _, msg := range m.IoServiceTimeRecursive { - dAtA[i] = 0x22 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoWaitTimeRecursive) > 0 { - for _, msg := range m.IoWaitTimeRecursive { - dAtA[i] = 0x2a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoMergedRecursive) > 0 { - for _, msg := range m.IoMergedRecursive { - dAtA[i] = 0x32 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.IoTimeRecursive) > 0 { - for _, msg := range m.IoTimeRecursive { - dAtA[i] = 0x3a - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.SectorsRecursive) > 0 { - for _, msg := range m.SectorsRecursive { - dAtA[i] = 0x42 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - return i, nil -} - -func (m *BlkIOEntry) 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 *BlkIOEntry) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Op) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(len(m.Op))) - i += copy(dAtA[i:], m.Op) - } - if len(m.Device) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(len(m.Device))) - i += copy(dAtA[i:], m.Device) - } - if m.Major != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Major)) - } - if m.Minor != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Minor)) - } - if m.Value != 0 { - dAtA[i] = 0x28 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.Value)) - } - return i, nil -} - -func (m *RdmaStat) 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 *RdmaStat) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Current) > 0 { - for _, msg := range m.Current { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - if len(m.Limit) > 0 { - for _, msg := range m.Limit { - dAtA[i] = 0x12 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(msg.Size())) - n, err := msg.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n - } - } - return i, nil -} - -func (m *RdmaEntry) 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 *RdmaEntry) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Device) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintMetrics(dAtA, i, uint64(len(m.Device))) - i += copy(dAtA[i:], m.Device) - } - if m.HcaHandles != 0 { - dAtA[i] = 0x10 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.HcaHandles)) - } - if m.HcaObjects != 0 { - dAtA[i] = 0x18 - i++ - i = encodeVarintMetrics(dAtA, i, uint64(m.HcaObjects)) - } - return i, nil -} - -func encodeFixed64Metrics(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 encodeFixed32Metrics(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 encodeVarintMetrics(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 *Metrics) Size() (n int) { - var l int - _ = l - if len(m.Hugetlb) > 0 { - for _, e := range m.Hugetlb { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if m.Pids != nil { - l = m.Pids.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - if m.CPU != nil { - l = m.CPU.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - if m.Memory != nil { - l = m.Memory.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - if m.Blkio != nil { - l = m.Blkio.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - if m.Rdma != nil { - l = m.Rdma.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - return n -} - -func (m *HugetlbStat) Size() (n int) { - var l int - _ = l - if m.Usage != 0 { - n += 1 + sovMetrics(uint64(m.Usage)) - } - if m.Max != 0 { - n += 1 + sovMetrics(uint64(m.Max)) - } - if m.Failcnt != 0 { - n += 1 + sovMetrics(uint64(m.Failcnt)) - } - l = len(m.Pagesize) - if l > 0 { - n += 1 + l + sovMetrics(uint64(l)) - } - return n -} - -func (m *PidsStat) Size() (n int) { - var l int - _ = l - if m.Current != 0 { - n += 1 + sovMetrics(uint64(m.Current)) - } - if m.Limit != 0 { - n += 1 + sovMetrics(uint64(m.Limit)) - } - return n -} - -func (m *CPUStat) Size() (n int) { - var l int - _ = l - if m.Usage != nil { - l = m.Usage.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - if m.Throttling != nil { - l = m.Throttling.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - return n -} - -func (m *CPUUsage) Size() (n int) { - var l int - _ = l - if m.Total != 0 { - n += 1 + sovMetrics(uint64(m.Total)) - } - if m.Kernel != 0 { - n += 1 + sovMetrics(uint64(m.Kernel)) - } - if m.User != 0 { - n += 1 + sovMetrics(uint64(m.User)) - } - if len(m.PerCPU) > 0 { - l = 0 - for _, e := range m.PerCPU { - l += sovMetrics(uint64(e)) - } - n += 1 + sovMetrics(uint64(l)) + l - } - return n -} - -func (m *Throttle) Size() (n int) { - var l int - _ = l - if m.Periods != 0 { - n += 1 + sovMetrics(uint64(m.Periods)) - } - if m.ThrottledPeriods != 0 { - n += 1 + sovMetrics(uint64(m.ThrottledPeriods)) - } - if m.ThrottledTime != 0 { - n += 1 + sovMetrics(uint64(m.ThrottledTime)) - } - return n -} - -func (m *MemoryStat) Size() (n int) { - var l int - _ = l - if m.Cache != 0 { - n += 1 + sovMetrics(uint64(m.Cache)) - } - if m.RSS != 0 { - n += 1 + sovMetrics(uint64(m.RSS)) - } - if m.RSSHuge != 0 { - n += 1 + sovMetrics(uint64(m.RSSHuge)) - } - if m.MappedFile != 0 { - n += 1 + sovMetrics(uint64(m.MappedFile)) - } - if m.Dirty != 0 { - n += 1 + sovMetrics(uint64(m.Dirty)) - } - if m.Writeback != 0 { - n += 1 + sovMetrics(uint64(m.Writeback)) - } - if m.PgPgIn != 0 { - n += 1 + sovMetrics(uint64(m.PgPgIn)) - } - if m.PgPgOut != 0 { - n += 1 + sovMetrics(uint64(m.PgPgOut)) - } - if m.PgFault != 0 { - n += 1 + sovMetrics(uint64(m.PgFault)) - } - if m.PgMajFault != 0 { - n += 1 + sovMetrics(uint64(m.PgMajFault)) - } - if m.InactiveAnon != 0 { - n += 1 + sovMetrics(uint64(m.InactiveAnon)) - } - if m.ActiveAnon != 0 { - n += 1 + sovMetrics(uint64(m.ActiveAnon)) - } - if m.InactiveFile != 0 { - n += 1 + sovMetrics(uint64(m.InactiveFile)) - } - if m.ActiveFile != 0 { - n += 1 + sovMetrics(uint64(m.ActiveFile)) - } - if m.Unevictable != 0 { - n += 1 + sovMetrics(uint64(m.Unevictable)) - } - if m.HierarchicalMemoryLimit != 0 { - n += 2 + sovMetrics(uint64(m.HierarchicalMemoryLimit)) - } - if m.HierarchicalSwapLimit != 0 { - n += 2 + sovMetrics(uint64(m.HierarchicalSwapLimit)) - } - if m.TotalCache != 0 { - n += 2 + sovMetrics(uint64(m.TotalCache)) - } - if m.TotalRSS != 0 { - n += 2 + sovMetrics(uint64(m.TotalRSS)) - } - if m.TotalRSSHuge != 0 { - n += 2 + sovMetrics(uint64(m.TotalRSSHuge)) - } - if m.TotalMappedFile != 0 { - n += 2 + sovMetrics(uint64(m.TotalMappedFile)) - } - if m.TotalDirty != 0 { - n += 2 + sovMetrics(uint64(m.TotalDirty)) - } - if m.TotalWriteback != 0 { - n += 2 + sovMetrics(uint64(m.TotalWriteback)) - } - if m.TotalPgPgIn != 0 { - n += 2 + sovMetrics(uint64(m.TotalPgPgIn)) - } - if m.TotalPgPgOut != 0 { - n += 2 + sovMetrics(uint64(m.TotalPgPgOut)) - } - if m.TotalPgFault != 0 { - n += 2 + sovMetrics(uint64(m.TotalPgFault)) - } - if m.TotalPgMajFault != 0 { - n += 2 + sovMetrics(uint64(m.TotalPgMajFault)) - } - if m.TotalInactiveAnon != 0 { - n += 2 + sovMetrics(uint64(m.TotalInactiveAnon)) - } - if m.TotalActiveAnon != 0 { - n += 2 + sovMetrics(uint64(m.TotalActiveAnon)) - } - if m.TotalInactiveFile != 0 { - n += 2 + sovMetrics(uint64(m.TotalInactiveFile)) - } - if m.TotalActiveFile != 0 { - n += 2 + sovMetrics(uint64(m.TotalActiveFile)) - } - if m.TotalUnevictable != 0 { - n += 2 + sovMetrics(uint64(m.TotalUnevictable)) - } - if m.Usage != nil { - l = m.Usage.Size() - n += 2 + l + sovMetrics(uint64(l)) - } - if m.Swap != nil { - l = m.Swap.Size() - n += 2 + l + sovMetrics(uint64(l)) - } - if m.Kernel != nil { - l = m.Kernel.Size() - n += 2 + l + sovMetrics(uint64(l)) - } - if m.KernelTCP != nil { - l = m.KernelTCP.Size() - n += 2 + l + sovMetrics(uint64(l)) - } - return n -} - -func (m *MemoryEntry) Size() (n int) { - var l int - _ = l - if m.Limit != 0 { - n += 1 + sovMetrics(uint64(m.Limit)) - } - if m.Usage != 0 { - n += 1 + sovMetrics(uint64(m.Usage)) - } - if m.Max != 0 { - n += 1 + sovMetrics(uint64(m.Max)) - } - if m.Failcnt != 0 { - n += 1 + sovMetrics(uint64(m.Failcnt)) - } - return n -} - -func (m *BlkIOStat) Size() (n int) { - var l int - _ = l - if len(m.IoServiceBytesRecursive) > 0 { - for _, e := range m.IoServiceBytesRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoServicedRecursive) > 0 { - for _, e := range m.IoServicedRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoQueuedRecursive) > 0 { - for _, e := range m.IoQueuedRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoServiceTimeRecursive) > 0 { - for _, e := range m.IoServiceTimeRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoWaitTimeRecursive) > 0 { - for _, e := range m.IoWaitTimeRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoMergedRecursive) > 0 { - for _, e := range m.IoMergedRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.IoTimeRecursive) > 0 { - for _, e := range m.IoTimeRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.SectorsRecursive) > 0 { - for _, e := range m.SectorsRecursive { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - return n -} - -func (m *BlkIOEntry) Size() (n int) { - var l int - _ = l - l = len(m.Op) - if l > 0 { - n += 1 + l + sovMetrics(uint64(l)) - } - l = len(m.Device) - if l > 0 { - n += 1 + l + sovMetrics(uint64(l)) - } - if m.Major != 0 { - n += 1 + sovMetrics(uint64(m.Major)) - } - if m.Minor != 0 { - n += 1 + sovMetrics(uint64(m.Minor)) - } - if m.Value != 0 { - n += 1 + sovMetrics(uint64(m.Value)) - } - return n -} - -func (m *RdmaStat) Size() (n int) { - var l int - _ = l - if len(m.Current) > 0 { - for _, e := range m.Current { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - if len(m.Limit) > 0 { - for _, e := range m.Limit { - l = e.Size() - n += 1 + l + sovMetrics(uint64(l)) - } - } - return n -} - -func (m *RdmaEntry) Size() (n int) { - var l int - _ = l - l = len(m.Device) - if l > 0 { - n += 1 + l + sovMetrics(uint64(l)) - } - if m.HcaHandles != 0 { - n += 1 + sovMetrics(uint64(m.HcaHandles)) - } - if m.HcaObjects != 0 { - n += 1 + sovMetrics(uint64(m.HcaObjects)) - } - return n -} - -func sovMetrics(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} -func sozMetrics(x uint64) (n int) { - return sovMetrics(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *Metrics) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Metrics{`, - `Hugetlb:` + strings.Replace(fmt.Sprintf("%v", this.Hugetlb), "HugetlbStat", "HugetlbStat", 1) + `,`, - `Pids:` + strings.Replace(fmt.Sprintf("%v", this.Pids), "PidsStat", "PidsStat", 1) + `,`, - `CPU:` + strings.Replace(fmt.Sprintf("%v", this.CPU), "CPUStat", "CPUStat", 1) + `,`, - `Memory:` + strings.Replace(fmt.Sprintf("%v", this.Memory), "MemoryStat", "MemoryStat", 1) + `,`, - `Blkio:` + strings.Replace(fmt.Sprintf("%v", this.Blkio), "BlkIOStat", "BlkIOStat", 1) + `,`, - `Rdma:` + strings.Replace(fmt.Sprintf("%v", this.Rdma), "RdmaStat", "RdmaStat", 1) + `,`, - `}`, - }, "") - return s -} -func (this *HugetlbStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&HugetlbStat{`, - `Usage:` + fmt.Sprintf("%v", this.Usage) + `,`, - `Max:` + fmt.Sprintf("%v", this.Max) + `,`, - `Failcnt:` + fmt.Sprintf("%v", this.Failcnt) + `,`, - `Pagesize:` + fmt.Sprintf("%v", this.Pagesize) + `,`, - `}`, - }, "") - return s -} -func (this *PidsStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&PidsStat{`, - `Current:` + fmt.Sprintf("%v", this.Current) + `,`, - `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, - `}`, - }, "") - return s -} -func (this *CPUStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&CPUStat{`, - `Usage:` + strings.Replace(fmt.Sprintf("%v", this.Usage), "CPUUsage", "CPUUsage", 1) + `,`, - `Throttling:` + strings.Replace(fmt.Sprintf("%v", this.Throttling), "Throttle", "Throttle", 1) + `,`, - `}`, - }, "") - return s -} -func (this *CPUUsage) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&CPUUsage{`, - `Total:` + fmt.Sprintf("%v", this.Total) + `,`, - `Kernel:` + fmt.Sprintf("%v", this.Kernel) + `,`, - `User:` + fmt.Sprintf("%v", this.User) + `,`, - `PerCPU:` + fmt.Sprintf("%v", this.PerCPU) + `,`, - `}`, - }, "") - return s -} -func (this *Throttle) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Throttle{`, - `Periods:` + fmt.Sprintf("%v", this.Periods) + `,`, - `ThrottledPeriods:` + fmt.Sprintf("%v", this.ThrottledPeriods) + `,`, - `ThrottledTime:` + fmt.Sprintf("%v", this.ThrottledTime) + `,`, - `}`, - }, "") - return s -} -func (this *MemoryStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&MemoryStat{`, - `Cache:` + fmt.Sprintf("%v", this.Cache) + `,`, - `RSS:` + fmt.Sprintf("%v", this.RSS) + `,`, - `RSSHuge:` + fmt.Sprintf("%v", this.RSSHuge) + `,`, - `MappedFile:` + fmt.Sprintf("%v", this.MappedFile) + `,`, - `Dirty:` + fmt.Sprintf("%v", this.Dirty) + `,`, - `Writeback:` + fmt.Sprintf("%v", this.Writeback) + `,`, - `PgPgIn:` + fmt.Sprintf("%v", this.PgPgIn) + `,`, - `PgPgOut:` + fmt.Sprintf("%v", this.PgPgOut) + `,`, - `PgFault:` + fmt.Sprintf("%v", this.PgFault) + `,`, - `PgMajFault:` + fmt.Sprintf("%v", this.PgMajFault) + `,`, - `InactiveAnon:` + fmt.Sprintf("%v", this.InactiveAnon) + `,`, - `ActiveAnon:` + fmt.Sprintf("%v", this.ActiveAnon) + `,`, - `InactiveFile:` + fmt.Sprintf("%v", this.InactiveFile) + `,`, - `ActiveFile:` + fmt.Sprintf("%v", this.ActiveFile) + `,`, - `Unevictable:` + fmt.Sprintf("%v", this.Unevictable) + `,`, - `HierarchicalMemoryLimit:` + fmt.Sprintf("%v", this.HierarchicalMemoryLimit) + `,`, - `HierarchicalSwapLimit:` + fmt.Sprintf("%v", this.HierarchicalSwapLimit) + `,`, - `TotalCache:` + fmt.Sprintf("%v", this.TotalCache) + `,`, - `TotalRSS:` + fmt.Sprintf("%v", this.TotalRSS) + `,`, - `TotalRSSHuge:` + fmt.Sprintf("%v", this.TotalRSSHuge) + `,`, - `TotalMappedFile:` + fmt.Sprintf("%v", this.TotalMappedFile) + `,`, - `TotalDirty:` + fmt.Sprintf("%v", this.TotalDirty) + `,`, - `TotalWriteback:` + fmt.Sprintf("%v", this.TotalWriteback) + `,`, - `TotalPgPgIn:` + fmt.Sprintf("%v", this.TotalPgPgIn) + `,`, - `TotalPgPgOut:` + fmt.Sprintf("%v", this.TotalPgPgOut) + `,`, - `TotalPgFault:` + fmt.Sprintf("%v", this.TotalPgFault) + `,`, - `TotalPgMajFault:` + fmt.Sprintf("%v", this.TotalPgMajFault) + `,`, - `TotalInactiveAnon:` + fmt.Sprintf("%v", this.TotalInactiveAnon) + `,`, - `TotalActiveAnon:` + fmt.Sprintf("%v", this.TotalActiveAnon) + `,`, - `TotalInactiveFile:` + fmt.Sprintf("%v", this.TotalInactiveFile) + `,`, - `TotalActiveFile:` + fmt.Sprintf("%v", this.TotalActiveFile) + `,`, - `TotalUnevictable:` + fmt.Sprintf("%v", this.TotalUnevictable) + `,`, - `Usage:` + strings.Replace(fmt.Sprintf("%v", this.Usage), "MemoryEntry", "MemoryEntry", 1) + `,`, - `Swap:` + strings.Replace(fmt.Sprintf("%v", this.Swap), "MemoryEntry", "MemoryEntry", 1) + `,`, - `Kernel:` + strings.Replace(fmt.Sprintf("%v", this.Kernel), "MemoryEntry", "MemoryEntry", 1) + `,`, - `KernelTCP:` + strings.Replace(fmt.Sprintf("%v", this.KernelTCP), "MemoryEntry", "MemoryEntry", 1) + `,`, - `}`, - }, "") - return s -} -func (this *MemoryEntry) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&MemoryEntry{`, - `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, - `Usage:` + fmt.Sprintf("%v", this.Usage) + `,`, - `Max:` + fmt.Sprintf("%v", this.Max) + `,`, - `Failcnt:` + fmt.Sprintf("%v", this.Failcnt) + `,`, - `}`, - }, "") - return s -} -func (this *BlkIOStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&BlkIOStat{`, - `IoServiceBytesRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoServiceBytesRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoServicedRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoServicedRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoQueuedRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoQueuedRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoServiceTimeRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoServiceTimeRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoWaitTimeRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoWaitTimeRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoMergedRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoMergedRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `IoTimeRecursive:` + strings.Replace(fmt.Sprintf("%v", this.IoTimeRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `SectorsRecursive:` + strings.Replace(fmt.Sprintf("%v", this.SectorsRecursive), "BlkIOEntry", "BlkIOEntry", 1) + `,`, - `}`, - }, "") - return s -} -func (this *BlkIOEntry) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&BlkIOEntry{`, - `Op:` + fmt.Sprintf("%v", this.Op) + `,`, - `Device:` + fmt.Sprintf("%v", this.Device) + `,`, - `Major:` + fmt.Sprintf("%v", this.Major) + `,`, - `Minor:` + fmt.Sprintf("%v", this.Minor) + `,`, - `Value:` + fmt.Sprintf("%v", this.Value) + `,`, - `}`, - }, "") - return s -} -func (this *RdmaStat) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&RdmaStat{`, - `Current:` + strings.Replace(fmt.Sprintf("%v", this.Current), "RdmaEntry", "RdmaEntry", 1) + `,`, - `Limit:` + strings.Replace(fmt.Sprintf("%v", this.Limit), "RdmaEntry", "RdmaEntry", 1) + `,`, - `}`, - }, "") - return s -} -func (this *RdmaEntry) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&RdmaEntry{`, - `Device:` + fmt.Sprintf("%v", this.Device) + `,`, - `HcaHandles:` + fmt.Sprintf("%v", this.HcaHandles) + `,`, - `HcaObjects:` + fmt.Sprintf("%v", this.HcaObjects) + `,`, - `}`, - }, "") - return s -} -func valueToStringMetrics(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} -func (m *Metrics) 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 ErrIntOverflowMetrics - } - 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: Metrics: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Metrics: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hugetlb", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Hugetlb = append(m.Hugetlb, &HugetlbStat{}) - if err := m.Hugetlb[len(m.Hugetlb)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pids", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Pids == nil { - m.Pids = &PidsStat{} - } - if err := m.Pids.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CPU", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.CPU == nil { - m.CPU = &CPUStat{} - } - if err := m.CPU.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Memory", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Memory == nil { - m.Memory = &MemoryStat{} - } - if err := m.Memory.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Blkio", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Blkio == nil { - m.Blkio = &BlkIOStat{} - } - if err := m.Blkio.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Rdma", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Rdma == nil { - m.Rdma = &RdmaStat{} - } - if err := m.Rdma.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *HugetlbStat) 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 ErrIntOverflowMetrics - } - 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: HugetlbStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: HugetlbStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) - } - m.Usage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Usage |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) - } - m.Max = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Max |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Failcnt", wireType) - } - m.Failcnt = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Failcnt |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagesize", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - 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 ErrInvalidLengthMetrics - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Pagesize = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *PidsStat) 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 ErrIntOverflowMetrics - } - 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: PidsStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PidsStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) - } - m.Current = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Current |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) - } - m.Limit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Limit |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CPUStat) 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 ErrIntOverflowMetrics - } - 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: CPUStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CPUStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Usage == nil { - m.Usage = &CPUUsage{} - } - if err := m.Usage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Throttling", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Throttling == nil { - m.Throttling = &Throttle{} - } - if err := m.Throttling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CPUUsage) 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 ErrIntOverflowMetrics - } - 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: CPUUsage: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CPUUsage: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) - } - m.Total = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Total |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Kernel", wireType) - } - m.Kernel = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Kernel |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field User", wireType) - } - m.User = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.User |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType == 0 { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - m.PerCPU = append(m.PerCPU, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + packedLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - for iNdEx < postIndex { - var v uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - m.PerCPU = append(m.PerCPU, v) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field PerCPU", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Throttle) 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 ErrIntOverflowMetrics - } - 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: Throttle: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Throttle: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Periods", wireType) - } - m.Periods = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Periods |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ThrottledPeriods", wireType) - } - m.ThrottledPeriods = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ThrottledPeriods |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ThrottledTime", wireType) - } - m.ThrottledTime = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ThrottledTime |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MemoryStat) 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 ErrIntOverflowMetrics - } - 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: MemoryStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MemoryStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Cache", wireType) - } - m.Cache = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Cache |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RSS", wireType) - } - m.RSS = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RSS |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RSSHuge", wireType) - } - m.RSSHuge = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RSSHuge |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field MappedFile", wireType) - } - m.MappedFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.MappedFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Dirty", wireType) - } - m.Dirty = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Dirty |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Writeback", wireType) - } - m.Writeback = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Writeback |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PgPgIn", wireType) - } - m.PgPgIn = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PgPgIn |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PgPgOut", wireType) - } - m.PgPgOut = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PgPgOut |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PgFault", wireType) - } - m.PgFault = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PgFault |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PgMajFault", wireType) - } - m.PgMajFault = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PgMajFault |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field InactiveAnon", wireType) - } - m.InactiveAnon = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.InactiveAnon |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ActiveAnon", wireType) - } - m.ActiveAnon = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ActiveAnon |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 13: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field InactiveFile", wireType) - } - m.InactiveFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.InactiveFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 14: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ActiveFile", wireType) - } - m.ActiveFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ActiveFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 15: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Unevictable", wireType) - } - m.Unevictable = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Unevictable |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 16: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HierarchicalMemoryLimit", wireType) - } - m.HierarchicalMemoryLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.HierarchicalMemoryLimit |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 17: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HierarchicalSwapLimit", wireType) - } - m.HierarchicalSwapLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.HierarchicalSwapLimit |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 18: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalCache", wireType) - } - m.TotalCache = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalCache |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 19: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalRSS", wireType) - } - m.TotalRSS = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalRSS |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 20: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalRSSHuge", wireType) - } - m.TotalRSSHuge = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalRSSHuge |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 21: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalMappedFile", wireType) - } - m.TotalMappedFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalMappedFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 22: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalDirty", wireType) - } - m.TotalDirty = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalDirty |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 23: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalWriteback", wireType) - } - m.TotalWriteback = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalWriteback |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 24: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalPgPgIn", wireType) - } - m.TotalPgPgIn = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalPgPgIn |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 25: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalPgPgOut", wireType) - } - m.TotalPgPgOut = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalPgPgOut |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 26: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalPgFault", wireType) - } - m.TotalPgFault = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalPgFault |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 27: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalPgMajFault", wireType) - } - m.TotalPgMajFault = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalPgMajFault |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 28: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalInactiveAnon", wireType) - } - m.TotalInactiveAnon = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalInactiveAnon |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 29: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveAnon", wireType) - } - m.TotalActiveAnon = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalActiveAnon |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 30: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalInactiveFile", wireType) - } - m.TotalInactiveFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalInactiveFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 31: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveFile", wireType) - } - m.TotalActiveFile = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalActiveFile |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 32: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalUnevictable", wireType) - } - m.TotalUnevictable = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TotalUnevictable |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 33: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Usage == nil { - m.Usage = &MemoryEntry{} - } - if err := m.Usage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 34: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Swap", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Swap == nil { - m.Swap = &MemoryEntry{} - } - if err := m.Swap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 35: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Kernel", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Kernel == nil { - m.Kernel = &MemoryEntry{} - } - if err := m.Kernel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 36: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field KernelTCP", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.KernelTCP == nil { - m.KernelTCP = &MemoryEntry{} - } - if err := m.KernelTCP.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MemoryEntry) 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 ErrIntOverflowMetrics - } - 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: MemoryEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MemoryEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) - } - m.Limit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Limit |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) - } - m.Usage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Usage |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) - } - m.Max = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Max |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Failcnt", wireType) - } - m.Failcnt = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Failcnt |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BlkIOStat) 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 ErrIntOverflowMetrics - } - 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: BlkIOStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BlkIOStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoServiceBytesRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoServiceBytesRecursive = append(m.IoServiceBytesRecursive, &BlkIOEntry{}) - if err := m.IoServiceBytesRecursive[len(m.IoServiceBytesRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoServicedRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoServicedRecursive = append(m.IoServicedRecursive, &BlkIOEntry{}) - if err := m.IoServicedRecursive[len(m.IoServicedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoQueuedRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoQueuedRecursive = append(m.IoQueuedRecursive, &BlkIOEntry{}) - if err := m.IoQueuedRecursive[len(m.IoQueuedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoServiceTimeRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoServiceTimeRecursive = append(m.IoServiceTimeRecursive, &BlkIOEntry{}) - if err := m.IoServiceTimeRecursive[len(m.IoServiceTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoWaitTimeRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoWaitTimeRecursive = append(m.IoWaitTimeRecursive, &BlkIOEntry{}) - if err := m.IoWaitTimeRecursive[len(m.IoWaitTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoMergedRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoMergedRecursive = append(m.IoMergedRecursive, &BlkIOEntry{}) - if err := m.IoMergedRecursive[len(m.IoMergedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IoTimeRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IoTimeRecursive = append(m.IoTimeRecursive, &BlkIOEntry{}) - if err := m.IoTimeRecursive[len(m.IoTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SectorsRecursive", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SectorsRecursive = append(m.SectorsRecursive, &BlkIOEntry{}) - if err := m.SectorsRecursive[len(m.SectorsRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BlkIOEntry) 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 ErrIntOverflowMetrics - } - 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: BlkIOEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BlkIOEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Op", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - 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 ErrInvalidLengthMetrics - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Op = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - 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 ErrInvalidLengthMetrics - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Device = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Major", wireType) - } - m.Major = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Major |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Minor", wireType) - } - m.Minor = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Minor |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) - } - m.Value = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Value |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RdmaStat) 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 ErrIntOverflowMetrics - } - 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: RdmaStat: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RdmaStat: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Current = append(m.Current, &RdmaEntry{}) - if err := m.Current[len(m.Current)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthMetrics - } - postIndex := iNdEx + msglen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Limit = append(m.Limit, &RdmaEntry{}) - if err := m.Limit[len(m.Limit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RdmaEntry) 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 ErrIntOverflowMetrics - } - 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: RdmaEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RdmaEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - 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 ErrInvalidLengthMetrics - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Device = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HcaHandles", wireType) - } - m.HcaHandles = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.HcaHandles |= (uint32(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HcaObjects", wireType) - } - m.HcaObjects = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMetrics - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.HcaObjects |= (uint32(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipMetrics(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthMetrics - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} - -func skipMetrics(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, ErrIntOverflowMetrics - } - 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, ErrIntOverflowMetrics - } - 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, ErrIntOverflowMetrics - } - 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, ErrInvalidLengthMetrics - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowMetrics - } - 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 := skipMetrics(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 ( - ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow") -) - -func init() { proto.RegisterFile("github.com/containerd/cgroups/metrics.proto", fileDescriptorMetrics) } - -var fileDescriptorMetrics = []byte{ - // 1325 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4d, 0x6f, 0x1b, 0xb7, - 0x16, 0x8d, 0xac, 0xb1, 0x3e, 0xae, 0x6c, 0xc7, 0xa6, 0x13, 0x67, 0xec, 0x97, 0x27, 0x29, 0xb2, - 0xfd, 0x9e, 0x5b, 0x03, 0x32, 0x9a, 0x02, 0x41, 0x93, 0xa6, 0x28, 0x22, 0xb7, 0x41, 0x83, 0xd6, - 0x88, 0x32, 0xb2, 0x91, 0x76, 0x35, 0x18, 0x8d, 0x98, 0x31, 0xe3, 0xd1, 0x70, 0xc2, 0xe1, 0xc8, - 0x71, 0x57, 0xdd, 0xf5, 0x37, 0xf5, 0x1f, 0x64, 0xd9, 0x4d, 0x81, 0x76, 0x63, 0x34, 0xfa, 0x25, - 0x05, 0x2f, 0xe7, 0x4b, 0x49, 0xdc, 0x40, 0xbb, 0xb9, 0xbc, 0xe7, 0x1c, 0x5e, 0x5e, 0x1e, 0x8a, - 0x14, 0xec, 0x7b, 0x4c, 0x9e, 0xc6, 0xc3, 0xae, 0xcb, 0xc7, 0x07, 0x2e, 0x0f, 0xa4, 0xc3, 0x02, - 0x2a, 0x46, 0x07, 0xae, 0x27, 0x78, 0x1c, 0x46, 0x07, 0x63, 0x2a, 0x05, 0x73, 0xa3, 0x6e, 0x28, - 0xb8, 0xe4, 0xc4, 0x64, 0xbc, 0x9b, 0x83, 0xba, 0x09, 0xa8, 0x3b, 0xf9, 0x6c, 0xeb, 0x86, 0xc7, - 0x3d, 0x8e, 0xa0, 0x03, 0xf5, 0xa5, 0xf1, 0x9d, 0xdf, 0x16, 0xa0, 0x7a, 0xa4, 0x15, 0xc8, 0xd7, - 0x50, 0x3d, 0x8d, 0x3d, 0x2a, 0xfd, 0xa1, 0x59, 0x6a, 0x97, 0xf7, 0x1a, 0x77, 0x77, 0xbb, 0x57, - 0xa9, 0x75, 0xbf, 0xd3, 0xc0, 0x81, 0x74, 0xa4, 0x95, 0xb2, 0xc8, 0x3d, 0x30, 0x42, 0x36, 0x8a, - 0xcc, 0x85, 0x76, 0x69, 0xaf, 0x71, 0xb7, 0x73, 0x35, 0xbb, 0xcf, 0x46, 0x11, 0x52, 0x11, 0x4f, - 0x1e, 0x42, 0xd9, 0x0d, 0x63, 0xb3, 0x8c, 0xb4, 0x3b, 0x57, 0xd3, 0x0e, 0xfb, 0x27, 0x8a, 0xd5, - 0xab, 0x4e, 0x2f, 0x5b, 0xe5, 0xc3, 0xfe, 0x89, 0xa5, 0x68, 0xe4, 0x21, 0x54, 0xc6, 0x74, 0xcc, - 0xc5, 0x85, 0x69, 0xa0, 0xc0, 0xce, 0xd5, 0x02, 0x47, 0x88, 0xc3, 0x99, 0x13, 0x0e, 0xb9, 0x0f, - 0x8b, 0x43, 0xff, 0x8c, 0x71, 0x73, 0x11, 0xc9, 0xdb, 0x57, 0x93, 0x7b, 0xfe, 0xd9, 0x93, 0xa7, - 0xc8, 0xd5, 0x8c, 0xce, 0x19, 0x34, 0x0a, 0x6d, 0x20, 0x37, 0x60, 0x31, 0x8e, 0x1c, 0x8f, 0x9a, - 0xa5, 0x76, 0x69, 0xcf, 0xb0, 0x74, 0x40, 0x56, 0xa1, 0x3c, 0x76, 0x5e, 0x63, 0x4b, 0x0c, 0x4b, - 0x7d, 0x12, 0x13, 0xaa, 0x2f, 0x1c, 0xe6, 0xbb, 0x81, 0xc4, 0x15, 0x1b, 0x56, 0x1a, 0x92, 0x2d, - 0xa8, 0x85, 0x8e, 0x47, 0x23, 0xf6, 0x33, 0xc5, 0xb5, 0xd4, 0xad, 0x2c, 0xee, 0x3c, 0x80, 0x5a, - 0xda, 0x35, 0xa5, 0xe0, 0xc6, 0x42, 0xd0, 0x40, 0x26, 0x73, 0xa5, 0xa1, 0xaa, 0xc1, 0x67, 0x63, - 0x26, 0x93, 0xf9, 0x74, 0xd0, 0xf9, 0xb5, 0x04, 0xd5, 0xa4, 0x77, 0xe4, 0x8b, 0x62, 0x95, 0xff, - 0xba, 0x49, 0x87, 0xfd, 0x93, 0x13, 0x85, 0x4c, 0x57, 0xd2, 0x03, 0x90, 0xa7, 0x82, 0x4b, 0xe9, - 0xb3, 0xc0, 0xfb, 0xf8, 0x1e, 0x1f, 0x6b, 0x2c, 0xb5, 0x0a, 0xac, 0xce, 0x2b, 0xa8, 0xa5, 0xb2, - 0xaa, 0x56, 0xc9, 0xa5, 0xe3, 0xa7, 0xfd, 0xc2, 0x80, 0x6c, 0x40, 0xe5, 0x8c, 0x8a, 0x80, 0xfa, - 0xc9, 0x12, 0x92, 0x88, 0x10, 0x30, 0xe2, 0x88, 0x8a, 0xa4, 0x65, 0xf8, 0x4d, 0xb6, 0xa1, 0x1a, - 0x52, 0x61, 0x2b, 0xef, 0x18, 0xed, 0xf2, 0x9e, 0xd1, 0x83, 0xe9, 0x65, 0xab, 0xd2, 0xa7, 0x42, - 0x79, 0xa3, 0x12, 0x52, 0x71, 0x18, 0xc6, 0x9d, 0xd7, 0x50, 0x4b, 0x4b, 0x51, 0x8d, 0x0b, 0xa9, - 0x60, 0x7c, 0x14, 0xa5, 0x8d, 0x4b, 0x42, 0xb2, 0x0f, 0x6b, 0x49, 0x99, 0x74, 0x64, 0xa7, 0x18, - 0x5d, 0xc1, 0x6a, 0x96, 0xe8, 0x27, 0xe0, 0x5d, 0x58, 0xc9, 0xc1, 0x92, 0x8d, 0x69, 0x52, 0xd5, - 0x72, 0x36, 0x7a, 0xcc, 0xc6, 0xb4, 0xf3, 0x57, 0x03, 0x20, 0x77, 0x9c, 0x5a, 0xaf, 0xeb, 0xb8, - 0xa7, 0x99, 0x3f, 0x30, 0x20, 0x9b, 0x50, 0x16, 0x51, 0x32, 0x95, 0x36, 0xb6, 0x35, 0x18, 0x58, - 0x6a, 0x8c, 0xfc, 0x0f, 0x6a, 0x22, 0x8a, 0x6c, 0x75, 0xba, 0xf4, 0x04, 0xbd, 0xc6, 0xf4, 0xb2, - 0x55, 0xb5, 0x06, 0x03, 0x65, 0x3b, 0xab, 0x2a, 0xa2, 0x48, 0x7d, 0x90, 0x16, 0x34, 0xc6, 0x4e, - 0x18, 0xd2, 0x91, 0xfd, 0x82, 0xf9, 0xda, 0x39, 0x86, 0x05, 0x7a, 0xe8, 0x31, 0xf3, 0xb1, 0xd3, - 0x23, 0x26, 0xe4, 0x05, 0x7a, 0xdc, 0xb0, 0x74, 0x40, 0x6e, 0x43, 0xfd, 0x5c, 0x30, 0x49, 0x87, - 0x8e, 0x7b, 0x66, 0x56, 0x30, 0x93, 0x0f, 0x10, 0x13, 0x6a, 0xa1, 0x67, 0x87, 0x9e, 0xcd, 0x02, - 0xb3, 0xaa, 0x77, 0x22, 0xf4, 0xfa, 0xde, 0x93, 0x80, 0x6c, 0x41, 0x5d, 0x67, 0x78, 0x2c, 0xcd, - 0x5a, 0xd2, 0x46, 0xaf, 0xef, 0x3d, 0x8d, 0x25, 0xd9, 0x44, 0xd6, 0x0b, 0x27, 0xf6, 0xa5, 0x59, - 0x4f, 0x53, 0x8f, 0x55, 0x48, 0xda, 0xb0, 0x14, 0x7a, 0xf6, 0xd8, 0x79, 0x99, 0xa4, 0x41, 0x97, - 0x19, 0x7a, 0x47, 0xce, 0x4b, 0x8d, 0xd8, 0x86, 0x65, 0x16, 0x38, 0xae, 0x64, 0x13, 0x6a, 0x3b, - 0x01, 0x0f, 0xcc, 0x06, 0x42, 0x96, 0xd2, 0xc1, 0x47, 0x01, 0x0f, 0xd4, 0x62, 0x8b, 0x90, 0x25, - 0xad, 0x52, 0x00, 0x14, 0x55, 0xb0, 0x1f, 0xcb, 0xb3, 0x2a, 0xd8, 0x91, 0x5c, 0x05, 0x21, 0x2b, - 0x45, 0x15, 0x04, 0xb4, 0xa1, 0x11, 0x07, 0x74, 0xc2, 0x5c, 0xe9, 0x0c, 0x7d, 0x6a, 0x5e, 0x47, - 0x40, 0x71, 0x88, 0x3c, 0x80, 0xcd, 0x53, 0x46, 0x85, 0x23, 0xdc, 0x53, 0xe6, 0x3a, 0xbe, 0xad, - 0x7f, 0x4f, 0x6c, 0x7d, 0xfc, 0x56, 0x11, 0x7f, 0xab, 0x08, 0xd0, 0x4e, 0xf8, 0x41, 0xa5, 0xc9, - 0x3d, 0x98, 0x49, 0xd9, 0xd1, 0xb9, 0x13, 0x26, 0xcc, 0x35, 0x64, 0xde, 0x2c, 0xa6, 0x07, 0xe7, - 0x4e, 0xa8, 0x79, 0x2d, 0x68, 0xe0, 0x29, 0xb1, 0xb5, 0x91, 0x88, 0x2e, 0x1b, 0x87, 0x0e, 0xd1, - 0x4d, 0x9f, 0x40, 0x5d, 0x03, 0x94, 0xa7, 0xd6, 0xd1, 0x33, 0x4b, 0xd3, 0xcb, 0x56, 0xed, 0x58, - 0x0d, 0x2a, 0x63, 0xd5, 0x30, 0x6d, 0x45, 0x11, 0xb9, 0x07, 0x2b, 0x19, 0x54, 0x7b, 0xec, 0x06, - 0xe2, 0x57, 0xa7, 0x97, 0xad, 0xa5, 0x14, 0x8f, 0x46, 0x5b, 0x4a, 0x39, 0xe8, 0xb6, 0x4f, 0x61, - 0x4d, 0xf3, 0x8a, 0x9e, 0xbb, 0x89, 0x95, 0x5c, 0xc7, 0xc4, 0x51, 0x6e, 0xbc, 0xac, 0x5e, 0x6d, - 0xbf, 0x8d, 0x42, 0xbd, 0xdf, 0xa0, 0x07, 0xff, 0x0f, 0x9a, 0x63, 0xe7, 0x4e, 0xbc, 0x85, 0x20, - 0x5d, 0xdb, 0xf3, 0xcc, 0x8e, 0xdb, 0x69, 0xb5, 0x99, 0x29, 0x4d, 0xbd, 0x25, 0x38, 0xda, 0xd7, - 0xce, 0xdc, 0x4d, 0xd5, 0x72, 0x7f, 0x6e, 0xea, 0xcd, 0xcf, 0x50, 0xca, 0xa4, 0x3b, 0x05, 0x2d, - 0xed, 0xc5, 0xad, 0x19, 0x94, 0x76, 0xe3, 0x3e, 0x90, 0x0c, 0x95, 0xbb, 0xf6, 0x3f, 0x85, 0x85, - 0xf6, 0x73, 0xeb, 0x76, 0x61, 0x5d, 0x83, 0x67, 0x0d, 0x7c, 0x1b, 0xd1, 0xba, 0x5f, 0x4f, 0x8a, - 0x2e, 0xce, 0x9a, 0x58, 0x44, 0xff, 0xb7, 0xa0, 0xfd, 0x28, 0xc7, 0xbe, 0xaf, 0x8d, 0x2d, 0x6f, - 0x7e, 0x40, 0x1b, 0x9b, 0xfe, 0xae, 0x36, 0xa2, 0x5b, 0xef, 0x69, 0x23, 0x76, 0x3f, 0xc5, 0x16, - 0xcd, 0xde, 0x4e, 0x7e, 0xf6, 0x54, 0xe2, 0xa4, 0xe0, 0xf8, 0x2f, 0xd3, 0xab, 0xe3, 0x0e, 0xfe, - 0xf6, 0xef, 0x7e, 0xec, 0x9e, 0xfd, 0x36, 0x90, 0xe2, 0x22, 0xbd, 0x3d, 0xee, 0x83, 0xa1, 0x5c, - 0x6e, 0x76, 0xe6, 0xe1, 0x22, 0x85, 0x7c, 0x95, 0x5d, 0x09, 0xdb, 0xf3, 0x90, 0xd3, 0x9b, 0x63, - 0x00, 0xa0, 0xbf, 0x6c, 0xe9, 0x86, 0xe6, 0xce, 0x1c, 0x12, 0xbd, 0xe5, 0xe9, 0x65, 0xab, 0xfe, - 0x3d, 0x92, 0x8f, 0x0f, 0xfb, 0x56, 0x5d, 0xeb, 0x1c, 0xbb, 0x61, 0x87, 0x42, 0xa3, 0x00, 0xcc, - 0xef, 0xdd, 0x52, 0xe1, 0xde, 0xcd, 0x5f, 0x04, 0x0b, 0x1f, 0x78, 0x11, 0x94, 0x3f, 0xf8, 0x22, - 0x30, 0x66, 0x5e, 0x04, 0x9d, 0x3f, 0x16, 0xa1, 0x9e, 0xbd, 0x3b, 0x88, 0x03, 0x5b, 0x8c, 0xdb, - 0x11, 0x15, 0x13, 0xe6, 0x52, 0x7b, 0x78, 0x21, 0x69, 0x64, 0x0b, 0xea, 0xc6, 0x22, 0x62, 0x13, - 0x9a, 0xbc, 0xd9, 0x76, 0x3e, 0xf2, 0x80, 0xd1, 0xbd, 0xb9, 0xc5, 0xf8, 0x40, 0xcb, 0xf4, 0x94, - 0x8a, 0x95, 0x8a, 0x90, 0x1f, 0xe1, 0x66, 0x3e, 0xc5, 0xa8, 0xa0, 0xbe, 0x30, 0x87, 0xfa, 0x7a, - 0xa6, 0x3e, 0xca, 0x95, 0x8f, 0x61, 0x9d, 0x71, 0xfb, 0x55, 0x4c, 0xe3, 0x19, 0xdd, 0xf2, 0x1c, - 0xba, 0x6b, 0x8c, 0x3f, 0x43, 0x7e, 0xae, 0x6a, 0xc3, 0x66, 0xa1, 0x25, 0xea, 0x2e, 0x2e, 0x68, - 0x1b, 0x73, 0x68, 0x6f, 0x64, 0x35, 0xab, 0xbb, 0x3b, 0x9f, 0xe0, 0x27, 0xd8, 0x60, 0xdc, 0x3e, - 0x77, 0x98, 0x7c, 0x57, 0x7d, 0x71, 0xbe, 0x8e, 0x3c, 0x77, 0x98, 0x9c, 0x95, 0xd6, 0x1d, 0x19, - 0x53, 0xe1, 0xcd, 0x74, 0xa4, 0x32, 0x5f, 0x47, 0x8e, 0x90, 0x9f, 0xab, 0xf6, 0x61, 0x8d, 0xf1, - 0x77, 0x6b, 0xad, 0xce, 0xa1, 0x79, 0x9d, 0xf1, 0xd9, 0x3a, 0x9f, 0xc1, 0x5a, 0x44, 0x5d, 0xc9, - 0x45, 0xd1, 0x6d, 0xb5, 0x39, 0x14, 0x57, 0x13, 0x7a, 0x26, 0xd9, 0x99, 0x00, 0xe4, 0x79, 0xb2, - 0x02, 0x0b, 0x3c, 0xc4, 0xa3, 0x53, 0xb7, 0x16, 0x78, 0xa8, 0xde, 0x80, 0x23, 0xf5, 0xb3, 0xa3, - 0x0f, 0x4e, 0xdd, 0x4a, 0x22, 0x75, 0x9e, 0xc6, 0xce, 0x4b, 0x9e, 0x3e, 0x02, 0x75, 0x80, 0xa3, - 0x2c, 0xe0, 0x22, 0x39, 0x3b, 0x3a, 0x50, 0xa3, 0x13, 0xc7, 0x8f, 0x69, 0xfa, 0xe6, 0xc1, 0xa0, - 0x67, 0xbe, 0x79, 0xdb, 0xbc, 0xf6, 0xe7, 0xdb, 0xe6, 0xb5, 0x5f, 0xa6, 0xcd, 0xd2, 0x9b, 0x69, - 0xb3, 0xf4, 0xfb, 0xb4, 0x59, 0xfa, 0x7b, 0xda, 0x2c, 0x0d, 0x2b, 0xf8, 0x7f, 0xe8, 0xf3, 0x7f, - 0x02, 0x00, 0x00, 0xff, 0xff, 0xb2, 0x21, 0x0b, 0xcd, 0x6e, 0x0d, 0x00, 0x00, -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/metrics.proto containerd-1.5.9/vendor/github.com/containerd/cgroups/metrics.proto --- containerd-1.2.6/vendor/github.com/containerd/cgroups/metrics.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/metrics.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -syntax = "proto3"; - -package io.containerd.cgroups.v1; - -import "gogoproto/gogo.proto"; - -message Metrics { - repeated HugetlbStat hugetlb = 1; - PidsStat pids = 2; - CPUStat cpu = 3 [(gogoproto.customname) = "CPU"]; - MemoryStat memory = 4; - BlkIOStat blkio = 5; - RdmaStat rdma = 6; -} - -message HugetlbStat { - uint64 usage = 1; - uint64 max = 2; - uint64 failcnt = 3; - string pagesize = 4; -} - -message PidsStat { - uint64 current = 1; - uint64 limit = 2; -} - -message CPUStat { - CPUUsage usage = 1; - Throttle throttling = 2; -} - -message CPUUsage { - // values in nanoseconds - uint64 total = 1; - uint64 kernel = 2; - uint64 user = 3; - repeated uint64 per_cpu = 4 [(gogoproto.customname) = "PerCPU"]; - -} - -message Throttle { - uint64 periods = 1; - uint64 throttled_periods = 2; - uint64 throttled_time = 3; -} - -message MemoryStat { - uint64 cache = 1; - uint64 rss = 2 [(gogoproto.customname) = "RSS"]; - uint64 rss_huge = 3 [(gogoproto.customname) = "RSSHuge"]; - uint64 mapped_file = 4; - uint64 dirty = 5; - uint64 writeback = 6; - uint64 pg_pg_in = 7; - uint64 pg_pg_out = 8; - uint64 pg_fault = 9; - uint64 pg_maj_fault = 10; - uint64 inactive_anon = 11; - uint64 active_anon = 12; - uint64 inactive_file = 13; - uint64 active_file = 14; - uint64 unevictable = 15; - uint64 hierarchical_memory_limit = 16; - uint64 hierarchical_swap_limit = 17; - uint64 total_cache = 18; - uint64 total_rss = 19 [(gogoproto.customname) = "TotalRSS"]; - uint64 total_rss_huge = 20 [(gogoproto.customname) = "TotalRSSHuge"]; - uint64 total_mapped_file = 21; - uint64 total_dirty = 22; - uint64 total_writeback = 23; - uint64 total_pg_pg_in = 24; - uint64 total_pg_pg_out = 25; - uint64 total_pg_fault = 26; - uint64 total_pg_maj_fault = 27; - uint64 total_inactive_anon = 28; - uint64 total_active_anon = 29; - uint64 total_inactive_file = 30; - uint64 total_active_file = 31; - uint64 total_unevictable = 32; - MemoryEntry usage = 33; - MemoryEntry swap = 34; - MemoryEntry kernel = 35; - MemoryEntry kernel_tcp = 36 [(gogoproto.customname) = "KernelTCP"]; - -} - -message MemoryEntry { - uint64 limit = 1; - uint64 usage = 2; - uint64 max = 3; - uint64 failcnt = 4; -} - -message BlkIOStat { - repeated BlkIOEntry io_service_bytes_recursive = 1; - repeated BlkIOEntry io_serviced_recursive = 2; - repeated BlkIOEntry io_queued_recursive = 3; - repeated BlkIOEntry io_service_time_recursive = 4; - repeated BlkIOEntry io_wait_time_recursive = 5; - repeated BlkIOEntry io_merged_recursive = 6; - repeated BlkIOEntry io_time_recursive = 7; - repeated BlkIOEntry sectors_recursive = 8; -} - -message BlkIOEntry { - string op = 1; - string device = 2; - uint64 major = 3; - uint64 minor = 4; - uint64 value = 5; -} - -message RdmaStat { - repeated RdmaEntry current = 1; - repeated RdmaEntry limit = 2; -} - -message RdmaEntry { - string device = 1; - uint32 hca_handles = 2; - uint32 hca_objects = 3; -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/net_cls.go containerd-1.5.9/vendor/github.com/containerd/cgroups/net_cls.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/net_cls.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/net_cls.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,7 +17,6 @@ package cgroups import ( - "io/ioutil" "os" "path/filepath" "strconv" @@ -48,7 +47,7 @@ return err } if resources.Network != nil && resources.Network.ClassID != nil && *resources.Network.ClassID > 0 { - return ioutil.WriteFile( + return retryingWriteFile( filepath.Join(n.Path(path), "net_cls.classid"), []byte(strconv.FormatUint(uint64(*resources.Network.ClassID), 10)), defaultFilePerm, @@ -56,3 +55,7 @@ } return nil } + +func (n *netclsController) Update(path string, resources *specs.LinuxResources) error { + return n.Create(path, resources) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/net_prio.go containerd-1.5.9/vendor/github.com/containerd/cgroups/net_prio.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/net_prio.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/net_prio.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,7 +18,6 @@ import ( "fmt" - "io/ioutil" "os" "path/filepath" @@ -49,7 +48,7 @@ } if resources.Network != nil { for _, prio := range resources.Network.Priorities { - if err := ioutil.WriteFile( + if err := retryingWriteFile( filepath.Join(n.Path(path), "net_prio.ifpriomap"), formatPrio(prio.Name, prio.Priority), defaultFilePerm, diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/opts.go containerd-1.5.9/vendor/github.com/containerd/cgroups/opts.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -48,12 +48,12 @@ type InitCheck func(Subsystem, Path, error) error // AllowAny allows any subsystem errors to be skipped -func AllowAny(s Subsystem, p Path, err error) error { +func AllowAny(_ Subsystem, _ Path, _ error) error { return ErrIgnoreSubsystem } // RequireDevices requires the device subsystem but no others -func RequireDevices(s Subsystem, p Path, err error) error { +func RequireDevices(s Subsystem, _ Path, _ error) error { if s.Name() == Devices { return ErrDevicesRequired } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/paths.go containerd-1.5.9/vendor/github.com/containerd/cgroups/paths.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/paths.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/paths.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,7 +25,7 @@ type Path func(subsystem Name) (string, error) -func RootPath(subsysem Name) (string, error) { +func RootPath(subsystem Name) (string, error) { return "/", nil } @@ -63,7 +63,7 @@ func existingPath(paths map[string]string, suffix string) Path { // localize the paths based on the root mount dest for nested cgroups for n, p := range paths { - dest, err := getCgroupDestination(string(n)) + dest, err := getCgroupDestination(n) if err != nil { return errorPath(err) } @@ -79,7 +79,7 @@ return func(name Name) (string, error) { root, ok := paths[string(name)] if !ok { - if root, ok = paths[fmt.Sprintf("name=%s", name)]; !ok { + if root, ok = paths["name="+string(name)]; !ok { return "", ErrControllerNotActive } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/pids.go containerd-1.5.9/vendor/github.com/containerd/cgroups/pids.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/pids.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/pids.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,6 +23,7 @@ "strconv" "strings" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -49,7 +50,7 @@ return err } if resources.Pids != nil && resources.Pids.Limit > 0 { - return ioutil.WriteFile( + return retryingWriteFile( filepath.Join(p.Path(path), "pids.max"), []byte(strconv.FormatInt(resources.Pids.Limit, 10)), defaultFilePerm, @@ -62,7 +63,7 @@ return p.Create(path, resources) } -func (p *pidsController) Stat(path string, stats *Metrics) error { +func (p *pidsController) Stat(path string, stats *v1.Metrics) error { current, err := readUint(filepath.Join(p.Path(path), "pids.current")) if err != nil { return err @@ -77,7 +78,7 @@ return err } } - stats.Pids = &PidsStat{ + stats.Pids = &v1.PidsStat{ Current: current, Limit: max, } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/Protobuild.toml containerd-1.5.9/vendor/github.com/containerd/cgroups/Protobuild.toml --- containerd-1.2.6/vendor/github.com/containerd/cgroups/Protobuild.toml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/Protobuild.toml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +version = "unstable" +generator = "gogoctrd" +plugins = ["grpc"] + +# Control protoc include paths. Below are usually some good defaults, but feel +# free to try it without them if it works for your project. +[includes] + # Include paths that will be added before all others. Typically, you want to + # treat the root of the project as an include, but this may not be necessary. + # before = ["."] + + # Paths that should be treated as include roots in relation to the vendor + # directory. These will be calculated with the vendor directory nearest the + # target package. + # vendored = ["github.com/gogo/protobuf"] + packages = ["github.com/gogo/protobuf"] + + # Paths that will be added untouched to the end of the includes. We use + # `/usr/local/include` to pickup the common install location of protobuf. + # This is the default. + after = ["/usr/local/include", "/usr/include"] + +# This section maps protobuf imports to Go packages. These will become +# `-M` directives in the call to the go protobuf generator. +[packages] + "gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto" + "google/protobuf/any.proto" = "github.com/gogo/protobuf/types" + "google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" + "google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types" + "google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types" + +# Aggregrate the API descriptors to lock down API changes. +[[descriptors]] +prefix = "github.com/containerd/cgroups/stats/v1" +target = "stats/v1/metrics.pb.txt" +ignore_files = [ + "google/protobuf/descriptor.proto", + "gogoproto/gogo.proto" +] +[[descriptors]] +prefix = "github.com/containerd/cgroups/v2/stats" +target = "v2/stats/metrics.pb.txt" +ignore_files = [ + "google/protobuf/descriptor.proto", + "gogoproto/gogo.proto" +] diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/rdma.go containerd-1.5.9/vendor/github.com/containerd/cgroups/rdma.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/rdma.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/rdma.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,6 +24,7 @@ "strconv" "strings" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -66,7 +67,7 @@ for device, limit := range resources.Rdma { if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) { - return ioutil.WriteFile( + return retryingWriteFile( filepath.Join(p.Path(path), "rdma.max"), []byte(createCmdString(device, &limit)), defaultFilePerm, @@ -80,7 +81,7 @@ return p.Create(path, resources) } -func parseRdmaKV(raw string, entry *RdmaEntry) { +func parseRdmaKV(raw string, entry *v1.RdmaEntry) { var value uint64 var err error @@ -103,13 +104,13 @@ } } -func toRdmaEntry(strEntries []string) []*RdmaEntry { - var rdmaEntries []*RdmaEntry +func toRdmaEntry(strEntries []string) []*v1.RdmaEntry { + var rdmaEntries []*v1.RdmaEntry for i := range strEntries { parts := strings.Fields(strEntries[i]) switch len(parts) { case 3: - entry := new(RdmaEntry) + entry := new(v1.RdmaEntry) entry.Device = parts[0] parseRdmaKV(parts[1], entry) parseRdmaKV(parts[2], entry) @@ -122,7 +123,7 @@ return rdmaEntries } -func (p *rdmaController) Stat(path string, stats *Metrics) error { +func (p *rdmaController) Stat(path string, stats *v1.Metrics) error { currentData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.current")) if err != nil { @@ -145,7 +146,7 @@ currentEntries := toRdmaEntry(currentPerDevices) maxEntries := toRdmaEntry(maxPerDevices) - stats.Rdma = &RdmaStat{ + stats.Rdma = &v1.RdmaStat{ Current: currentEntries, Limit: maxEntries, } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/README.md containerd-1.5.9/vendor/github.com/containerd/cgroups/README.md --- containerd-1.2.6/vendor/github.com/containerd/cgroups/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,6 @@ # cgroups -[![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups) +[![Build Status](https://github.com/containerd/cgroups/workflows/CI/badge.svg)](https://github.com/containerd/cgroups/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups) [![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups) [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups) @@ -65,7 +65,7 @@ ```go shares = uint64(200) if err := control.Update(&specs.LinuxResources{ - CPU: &specs.CPU{ + CPU: &specs.LinuxCPU{ Shares: &shares, }, }); err != nil { @@ -112,6 +112,31 @@ subCgroup, err := control.New("child", resources) ``` +### Registering for memory events + +This allows you to get notified by an eventfd for v1 memory cgroups events. + +```go +event := cgroups.MemoryThresholdEvent(50 * 1024 * 1024, false) +efd, err := control.RegisterMemoryEvent(event) +``` + +```go +event := cgroups.MemoryPressureEvent(cgroups.MediumPressure, cgroups.DefaultMode) +efd, err := control.RegisterMemoryEvent(event) +``` + +```go +efd, err := control.OOMEventFD() +// or by using RegisterMemoryEvent +event := cgroups.OOMEvent() +efd, err := control.RegisterMemoryEvent(event) +``` + +### Attention + +All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name + ## Project details Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/doc.go containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/doc.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,6125 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/containerd/cgroups/stats/v1/metrics.proto + +package v1 + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Metrics struct { + Hugetlb []*HugetlbStat `protobuf:"bytes,1,rep,name=hugetlb,proto3" json:"hugetlb,omitempty"` + Pids *PidsStat `protobuf:"bytes,2,opt,name=pids,proto3" json:"pids,omitempty"` + CPU *CPUStat `protobuf:"bytes,3,opt,name=cpu,proto3" json:"cpu,omitempty"` + Memory *MemoryStat `protobuf:"bytes,4,opt,name=memory,proto3" json:"memory,omitempty"` + Blkio *BlkIOStat `protobuf:"bytes,5,opt,name=blkio,proto3" json:"blkio,omitempty"` + Rdma *RdmaStat `protobuf:"bytes,6,opt,name=rdma,proto3" json:"rdma,omitempty"` + Network []*NetworkStat `protobuf:"bytes,7,rep,name=network,proto3" json:"network,omitempty"` + CgroupStats *CgroupStats `protobuf:"bytes,8,opt,name=cgroup_stats,json=cgroupStats,proto3" json:"cgroup_stats,omitempty"` + MemoryOomControl *MemoryOomControl `protobuf:"bytes,9,opt,name=memory_oom_control,json=memoryOomControl,proto3" json:"memory_oom_control,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Metrics) Reset() { *m = Metrics{} } +func (*Metrics) ProtoMessage() {} +func (*Metrics) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{0} +} +func (m *Metrics) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Metrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Metrics.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Metrics) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metrics.Merge(m, src) +} +func (m *Metrics) XXX_Size() int { + return m.Size() +} +func (m *Metrics) XXX_DiscardUnknown() { + xxx_messageInfo_Metrics.DiscardUnknown(m) +} + +var xxx_messageInfo_Metrics proto.InternalMessageInfo + +type HugetlbStat struct { + Usage uint64 `protobuf:"varint,1,opt,name=usage,proto3" json:"usage,omitempty"` + Max uint64 `protobuf:"varint,2,opt,name=max,proto3" json:"max,omitempty"` + Failcnt uint64 `protobuf:"varint,3,opt,name=failcnt,proto3" json:"failcnt,omitempty"` + Pagesize string `protobuf:"bytes,4,opt,name=pagesize,proto3" json:"pagesize,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HugetlbStat) Reset() { *m = HugetlbStat{} } +func (*HugetlbStat) ProtoMessage() {} +func (*HugetlbStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{1} +} +func (m *HugetlbStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HugetlbStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HugetlbStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HugetlbStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_HugetlbStat.Merge(m, src) +} +func (m *HugetlbStat) XXX_Size() int { + return m.Size() +} +func (m *HugetlbStat) XXX_DiscardUnknown() { + xxx_messageInfo_HugetlbStat.DiscardUnknown(m) +} + +var xxx_messageInfo_HugetlbStat proto.InternalMessageInfo + +type PidsStat struct { + Current uint64 `protobuf:"varint,1,opt,name=current,proto3" json:"current,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PidsStat) Reset() { *m = PidsStat{} } +func (*PidsStat) ProtoMessage() {} +func (*PidsStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{2} +} +func (m *PidsStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PidsStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PidsStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PidsStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_PidsStat.Merge(m, src) +} +func (m *PidsStat) XXX_Size() int { + return m.Size() +} +func (m *PidsStat) XXX_DiscardUnknown() { + xxx_messageInfo_PidsStat.DiscardUnknown(m) +} + +var xxx_messageInfo_PidsStat proto.InternalMessageInfo + +type CPUStat struct { + Usage *CPUUsage `protobuf:"bytes,1,opt,name=usage,proto3" json:"usage,omitempty"` + Throttling *Throttle `protobuf:"bytes,2,opt,name=throttling,proto3" json:"throttling,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CPUStat) Reset() { *m = CPUStat{} } +func (*CPUStat) ProtoMessage() {} +func (*CPUStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{3} +} +func (m *CPUStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CPUStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CPUStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CPUStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_CPUStat.Merge(m, src) +} +func (m *CPUStat) XXX_Size() int { + return m.Size() +} +func (m *CPUStat) XXX_DiscardUnknown() { + xxx_messageInfo_CPUStat.DiscardUnknown(m) +} + +var xxx_messageInfo_CPUStat proto.InternalMessageInfo + +type CPUUsage struct { + // values in nanoseconds + Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"` + Kernel uint64 `protobuf:"varint,2,opt,name=kernel,proto3" json:"kernel,omitempty"` + User uint64 `protobuf:"varint,3,opt,name=user,proto3" json:"user,omitempty"` + PerCPU []uint64 `protobuf:"varint,4,rep,packed,name=per_cpu,json=perCpu,proto3" json:"per_cpu,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CPUUsage) Reset() { *m = CPUUsage{} } +func (*CPUUsage) ProtoMessage() {} +func (*CPUUsage) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{4} +} +func (m *CPUUsage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CPUUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CPUUsage.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CPUUsage) XXX_Merge(src proto.Message) { + xxx_messageInfo_CPUUsage.Merge(m, src) +} +func (m *CPUUsage) XXX_Size() int { + return m.Size() +} +func (m *CPUUsage) XXX_DiscardUnknown() { + xxx_messageInfo_CPUUsage.DiscardUnknown(m) +} + +var xxx_messageInfo_CPUUsage proto.InternalMessageInfo + +type Throttle struct { + Periods uint64 `protobuf:"varint,1,opt,name=periods,proto3" json:"periods,omitempty"` + ThrottledPeriods uint64 `protobuf:"varint,2,opt,name=throttled_periods,json=throttledPeriods,proto3" json:"throttled_periods,omitempty"` + ThrottledTime uint64 `protobuf:"varint,3,opt,name=throttled_time,json=throttledTime,proto3" json:"throttled_time,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Throttle) Reset() { *m = Throttle{} } +func (*Throttle) ProtoMessage() {} +func (*Throttle) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{5} +} +func (m *Throttle) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Throttle) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Throttle.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Throttle) XXX_Merge(src proto.Message) { + xxx_messageInfo_Throttle.Merge(m, src) +} +func (m *Throttle) XXX_Size() int { + return m.Size() +} +func (m *Throttle) XXX_DiscardUnknown() { + xxx_messageInfo_Throttle.DiscardUnknown(m) +} + +var xxx_messageInfo_Throttle proto.InternalMessageInfo + +type MemoryStat struct { + Cache uint64 `protobuf:"varint,1,opt,name=cache,proto3" json:"cache,omitempty"` + RSS uint64 `protobuf:"varint,2,opt,name=rss,proto3" json:"rss,omitempty"` + RSSHuge uint64 `protobuf:"varint,3,opt,name=rss_huge,json=rssHuge,proto3" json:"rss_huge,omitempty"` + MappedFile uint64 `protobuf:"varint,4,opt,name=mapped_file,json=mappedFile,proto3" json:"mapped_file,omitempty"` + Dirty uint64 `protobuf:"varint,5,opt,name=dirty,proto3" json:"dirty,omitempty"` + Writeback uint64 `protobuf:"varint,6,opt,name=writeback,proto3" json:"writeback,omitempty"` + PgPgIn uint64 `protobuf:"varint,7,opt,name=pg_pg_in,json=pgPgIn,proto3" json:"pg_pg_in,omitempty"` + PgPgOut uint64 `protobuf:"varint,8,opt,name=pg_pg_out,json=pgPgOut,proto3" json:"pg_pg_out,omitempty"` + PgFault uint64 `protobuf:"varint,9,opt,name=pg_fault,json=pgFault,proto3" json:"pg_fault,omitempty"` + PgMajFault uint64 `protobuf:"varint,10,opt,name=pg_maj_fault,json=pgMajFault,proto3" json:"pg_maj_fault,omitempty"` + InactiveAnon uint64 `protobuf:"varint,11,opt,name=inactive_anon,json=inactiveAnon,proto3" json:"inactive_anon,omitempty"` + ActiveAnon uint64 `protobuf:"varint,12,opt,name=active_anon,json=activeAnon,proto3" json:"active_anon,omitempty"` + InactiveFile uint64 `protobuf:"varint,13,opt,name=inactive_file,json=inactiveFile,proto3" json:"inactive_file,omitempty"` + ActiveFile uint64 `protobuf:"varint,14,opt,name=active_file,json=activeFile,proto3" json:"active_file,omitempty"` + Unevictable uint64 `protobuf:"varint,15,opt,name=unevictable,proto3" json:"unevictable,omitempty"` + HierarchicalMemoryLimit uint64 `protobuf:"varint,16,opt,name=hierarchical_memory_limit,json=hierarchicalMemoryLimit,proto3" json:"hierarchical_memory_limit,omitempty"` + HierarchicalSwapLimit uint64 `protobuf:"varint,17,opt,name=hierarchical_swap_limit,json=hierarchicalSwapLimit,proto3" json:"hierarchical_swap_limit,omitempty"` + TotalCache uint64 `protobuf:"varint,18,opt,name=total_cache,json=totalCache,proto3" json:"total_cache,omitempty"` + TotalRSS uint64 `protobuf:"varint,19,opt,name=total_rss,json=totalRss,proto3" json:"total_rss,omitempty"` + TotalRSSHuge uint64 `protobuf:"varint,20,opt,name=total_rss_huge,json=totalRssHuge,proto3" json:"total_rss_huge,omitempty"` + TotalMappedFile uint64 `protobuf:"varint,21,opt,name=total_mapped_file,json=totalMappedFile,proto3" json:"total_mapped_file,omitempty"` + TotalDirty uint64 `protobuf:"varint,22,opt,name=total_dirty,json=totalDirty,proto3" json:"total_dirty,omitempty"` + TotalWriteback uint64 `protobuf:"varint,23,opt,name=total_writeback,json=totalWriteback,proto3" json:"total_writeback,omitempty"` + TotalPgPgIn uint64 `protobuf:"varint,24,opt,name=total_pg_pg_in,json=totalPgPgIn,proto3" json:"total_pg_pg_in,omitempty"` + TotalPgPgOut uint64 `protobuf:"varint,25,opt,name=total_pg_pg_out,json=totalPgPgOut,proto3" json:"total_pg_pg_out,omitempty"` + TotalPgFault uint64 `protobuf:"varint,26,opt,name=total_pg_fault,json=totalPgFault,proto3" json:"total_pg_fault,omitempty"` + TotalPgMajFault uint64 `protobuf:"varint,27,opt,name=total_pg_maj_fault,json=totalPgMajFault,proto3" json:"total_pg_maj_fault,omitempty"` + TotalInactiveAnon uint64 `protobuf:"varint,28,opt,name=total_inactive_anon,json=totalInactiveAnon,proto3" json:"total_inactive_anon,omitempty"` + TotalActiveAnon uint64 `protobuf:"varint,29,opt,name=total_active_anon,json=totalActiveAnon,proto3" json:"total_active_anon,omitempty"` + TotalInactiveFile uint64 `protobuf:"varint,30,opt,name=total_inactive_file,json=totalInactiveFile,proto3" json:"total_inactive_file,omitempty"` + TotalActiveFile uint64 `protobuf:"varint,31,opt,name=total_active_file,json=totalActiveFile,proto3" json:"total_active_file,omitempty"` + TotalUnevictable uint64 `protobuf:"varint,32,opt,name=total_unevictable,json=totalUnevictable,proto3" json:"total_unevictable,omitempty"` + Usage *MemoryEntry `protobuf:"bytes,33,opt,name=usage,proto3" json:"usage,omitempty"` + Swap *MemoryEntry `protobuf:"bytes,34,opt,name=swap,proto3" json:"swap,omitempty"` + Kernel *MemoryEntry `protobuf:"bytes,35,opt,name=kernel,proto3" json:"kernel,omitempty"` + KernelTCP *MemoryEntry `protobuf:"bytes,36,opt,name=kernel_tcp,json=kernelTcp,proto3" json:"kernel_tcp,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryStat) Reset() { *m = MemoryStat{} } +func (*MemoryStat) ProtoMessage() {} +func (*MemoryStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{6} +} +func (m *MemoryStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryStat.Merge(m, src) +} +func (m *MemoryStat) XXX_Size() int { + return m.Size() +} +func (m *MemoryStat) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryStat.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryStat proto.InternalMessageInfo + +type MemoryEntry struct { + Limit uint64 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + Usage uint64 `protobuf:"varint,2,opt,name=usage,proto3" json:"usage,omitempty"` + Max uint64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` + Failcnt uint64 `protobuf:"varint,4,opt,name=failcnt,proto3" json:"failcnt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryEntry) Reset() { *m = MemoryEntry{} } +func (*MemoryEntry) ProtoMessage() {} +func (*MemoryEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{7} +} +func (m *MemoryEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryEntry.Merge(m, src) +} +func (m *MemoryEntry) XXX_Size() int { + return m.Size() +} +func (m *MemoryEntry) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryEntry proto.InternalMessageInfo + +type MemoryOomControl struct { + OomKillDisable uint64 `protobuf:"varint,1,opt,name=oom_kill_disable,json=oomKillDisable,proto3" json:"oom_kill_disable,omitempty"` + UnderOom uint64 `protobuf:"varint,2,opt,name=under_oom,json=underOom,proto3" json:"under_oom,omitempty"` + OomKill uint64 `protobuf:"varint,3,opt,name=oom_kill,json=oomKill,proto3" json:"oom_kill,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryOomControl) Reset() { *m = MemoryOomControl{} } +func (*MemoryOomControl) ProtoMessage() {} +func (*MemoryOomControl) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{8} +} +func (m *MemoryOomControl) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryOomControl) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryOomControl.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryOomControl) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryOomControl.Merge(m, src) +} +func (m *MemoryOomControl) XXX_Size() int { + return m.Size() +} +func (m *MemoryOomControl) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryOomControl.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryOomControl proto.InternalMessageInfo + +type BlkIOStat struct { + IoServiceBytesRecursive []*BlkIOEntry `protobuf:"bytes,1,rep,name=io_service_bytes_recursive,json=ioServiceBytesRecursive,proto3" json:"io_service_bytes_recursive,omitempty"` + IoServicedRecursive []*BlkIOEntry `protobuf:"bytes,2,rep,name=io_serviced_recursive,json=ioServicedRecursive,proto3" json:"io_serviced_recursive,omitempty"` + IoQueuedRecursive []*BlkIOEntry `protobuf:"bytes,3,rep,name=io_queued_recursive,json=ioQueuedRecursive,proto3" json:"io_queued_recursive,omitempty"` + IoServiceTimeRecursive []*BlkIOEntry `protobuf:"bytes,4,rep,name=io_service_time_recursive,json=ioServiceTimeRecursive,proto3" json:"io_service_time_recursive,omitempty"` + IoWaitTimeRecursive []*BlkIOEntry `protobuf:"bytes,5,rep,name=io_wait_time_recursive,json=ioWaitTimeRecursive,proto3" json:"io_wait_time_recursive,omitempty"` + IoMergedRecursive []*BlkIOEntry `protobuf:"bytes,6,rep,name=io_merged_recursive,json=ioMergedRecursive,proto3" json:"io_merged_recursive,omitempty"` + IoTimeRecursive []*BlkIOEntry `protobuf:"bytes,7,rep,name=io_time_recursive,json=ioTimeRecursive,proto3" json:"io_time_recursive,omitempty"` + SectorsRecursive []*BlkIOEntry `protobuf:"bytes,8,rep,name=sectors_recursive,json=sectorsRecursive,proto3" json:"sectors_recursive,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlkIOStat) Reset() { *m = BlkIOStat{} } +func (*BlkIOStat) ProtoMessage() {} +func (*BlkIOStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{9} +} +func (m *BlkIOStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlkIOStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlkIOStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlkIOStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlkIOStat.Merge(m, src) +} +func (m *BlkIOStat) XXX_Size() int { + return m.Size() +} +func (m *BlkIOStat) XXX_DiscardUnknown() { + xxx_messageInfo_BlkIOStat.DiscardUnknown(m) +} + +var xxx_messageInfo_BlkIOStat proto.InternalMessageInfo + +type BlkIOEntry struct { + Op string `protobuf:"bytes,1,opt,name=op,proto3" json:"op,omitempty"` + Device string `protobuf:"bytes,2,opt,name=device,proto3" json:"device,omitempty"` + Major uint64 `protobuf:"varint,3,opt,name=major,proto3" json:"major,omitempty"` + Minor uint64 `protobuf:"varint,4,opt,name=minor,proto3" json:"minor,omitempty"` + Value uint64 `protobuf:"varint,5,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BlkIOEntry) Reset() { *m = BlkIOEntry{} } +func (*BlkIOEntry) ProtoMessage() {} +func (*BlkIOEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{10} +} +func (m *BlkIOEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlkIOEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlkIOEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlkIOEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlkIOEntry.Merge(m, src) +} +func (m *BlkIOEntry) XXX_Size() int { + return m.Size() +} +func (m *BlkIOEntry) XXX_DiscardUnknown() { + xxx_messageInfo_BlkIOEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_BlkIOEntry proto.InternalMessageInfo + +type RdmaStat struct { + Current []*RdmaEntry `protobuf:"bytes,1,rep,name=current,proto3" json:"current,omitempty"` + Limit []*RdmaEntry `protobuf:"bytes,2,rep,name=limit,proto3" json:"limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RdmaStat) Reset() { *m = RdmaStat{} } +func (*RdmaStat) ProtoMessage() {} +func (*RdmaStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{11} +} +func (m *RdmaStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RdmaStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RdmaStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RdmaStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_RdmaStat.Merge(m, src) +} +func (m *RdmaStat) XXX_Size() int { + return m.Size() +} +func (m *RdmaStat) XXX_DiscardUnknown() { + xxx_messageInfo_RdmaStat.DiscardUnknown(m) +} + +var xxx_messageInfo_RdmaStat proto.InternalMessageInfo + +type RdmaEntry struct { + Device string `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` + HcaHandles uint32 `protobuf:"varint,2,opt,name=hca_handles,json=hcaHandles,proto3" json:"hca_handles,omitempty"` + HcaObjects uint32 `protobuf:"varint,3,opt,name=hca_objects,json=hcaObjects,proto3" json:"hca_objects,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RdmaEntry) Reset() { *m = RdmaEntry{} } +func (*RdmaEntry) ProtoMessage() {} +func (*RdmaEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{12} +} +func (m *RdmaEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RdmaEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RdmaEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RdmaEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_RdmaEntry.Merge(m, src) +} +func (m *RdmaEntry) XXX_Size() int { + return m.Size() +} +func (m *RdmaEntry) XXX_DiscardUnknown() { + xxx_messageInfo_RdmaEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_RdmaEntry proto.InternalMessageInfo + +type NetworkStat struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + RxBytes uint64 `protobuf:"varint,2,opt,name=rx_bytes,json=rxBytes,proto3" json:"rx_bytes,omitempty"` + RxPackets uint64 `protobuf:"varint,3,opt,name=rx_packets,json=rxPackets,proto3" json:"rx_packets,omitempty"` + RxErrors uint64 `protobuf:"varint,4,opt,name=rx_errors,json=rxErrors,proto3" json:"rx_errors,omitempty"` + RxDropped uint64 `protobuf:"varint,5,opt,name=rx_dropped,json=rxDropped,proto3" json:"rx_dropped,omitempty"` + TxBytes uint64 `protobuf:"varint,6,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"` + TxPackets uint64 `protobuf:"varint,7,opt,name=tx_packets,json=txPackets,proto3" json:"tx_packets,omitempty"` + TxErrors uint64 `protobuf:"varint,8,opt,name=tx_errors,json=txErrors,proto3" json:"tx_errors,omitempty"` + TxDropped uint64 `protobuf:"varint,9,opt,name=tx_dropped,json=txDropped,proto3" json:"tx_dropped,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NetworkStat) Reset() { *m = NetworkStat{} } +func (*NetworkStat) ProtoMessage() {} +func (*NetworkStat) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{13} +} +func (m *NetworkStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NetworkStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NetworkStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NetworkStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_NetworkStat.Merge(m, src) +} +func (m *NetworkStat) XXX_Size() int { + return m.Size() +} +func (m *NetworkStat) XXX_DiscardUnknown() { + xxx_messageInfo_NetworkStat.DiscardUnknown(m) +} + +var xxx_messageInfo_NetworkStat proto.InternalMessageInfo + +// CgroupStats exports per-cgroup statistics. +type CgroupStats struct { + // number of tasks sleeping + NrSleeping uint64 `protobuf:"varint,1,opt,name=nr_sleeping,json=nrSleeping,proto3" json:"nr_sleeping,omitempty"` + // number of tasks running + NrRunning uint64 `protobuf:"varint,2,opt,name=nr_running,json=nrRunning,proto3" json:"nr_running,omitempty"` + // number of tasks in stopped state + NrStopped uint64 `protobuf:"varint,3,opt,name=nr_stopped,json=nrStopped,proto3" json:"nr_stopped,omitempty"` + // number of tasks in uninterruptible state + NrUninterruptible uint64 `protobuf:"varint,4,opt,name=nr_uninterruptible,json=nrUninterruptible,proto3" json:"nr_uninterruptible,omitempty"` + // number of tasks waiting on IO + NrIoWait uint64 `protobuf:"varint,5,opt,name=nr_io_wait,json=nrIoWait,proto3" json:"nr_io_wait,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CgroupStats) Reset() { *m = CgroupStats{} } +func (*CgroupStats) ProtoMessage() {} +func (*CgroupStats) Descriptor() ([]byte, []int) { + return fileDescriptor_a17b2d87c332bfaa, []int{14} +} +func (m *CgroupStats) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CgroupStats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CgroupStats.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CgroupStats) XXX_Merge(src proto.Message) { + xxx_messageInfo_CgroupStats.Merge(m, src) +} +func (m *CgroupStats) XXX_Size() int { + return m.Size() +} +func (m *CgroupStats) XXX_DiscardUnknown() { + xxx_messageInfo_CgroupStats.DiscardUnknown(m) +} + +var xxx_messageInfo_CgroupStats proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v1.Metrics") + proto.RegisterType((*HugetlbStat)(nil), "io.containerd.cgroups.v1.HugetlbStat") + proto.RegisterType((*PidsStat)(nil), "io.containerd.cgroups.v1.PidsStat") + proto.RegisterType((*CPUStat)(nil), "io.containerd.cgroups.v1.CPUStat") + proto.RegisterType((*CPUUsage)(nil), "io.containerd.cgroups.v1.CPUUsage") + proto.RegisterType((*Throttle)(nil), "io.containerd.cgroups.v1.Throttle") + proto.RegisterType((*MemoryStat)(nil), "io.containerd.cgroups.v1.MemoryStat") + proto.RegisterType((*MemoryEntry)(nil), "io.containerd.cgroups.v1.MemoryEntry") + proto.RegisterType((*MemoryOomControl)(nil), "io.containerd.cgroups.v1.MemoryOomControl") + proto.RegisterType((*BlkIOStat)(nil), "io.containerd.cgroups.v1.BlkIOStat") + proto.RegisterType((*BlkIOEntry)(nil), "io.containerd.cgroups.v1.BlkIOEntry") + proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v1.RdmaStat") + proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v1.RdmaEntry") + proto.RegisterType((*NetworkStat)(nil), "io.containerd.cgroups.v1.NetworkStat") + proto.RegisterType((*CgroupStats)(nil), "io.containerd.cgroups.v1.CgroupStats") +} + +func init() { + proto.RegisterFile("github.com/containerd/cgroups/stats/v1/metrics.proto", fileDescriptor_a17b2d87c332bfaa) +} + +var fileDescriptor_a17b2d87c332bfaa = []byte{ + // 1749 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0xcd, 0x72, 0xe3, 0xc6, + 0x11, 0x36, 0x45, 0x48, 0x24, 0x9a, 0x92, 0x56, 0x9a, 0xfd, 0x83, 0xe4, 0xb5, 0x28, 0x53, 0xbb, + 0x89, 0xe2, 0xad, 0x48, 0x65, 0x27, 0xb5, 0x95, 0x75, 0xec, 0x4a, 0x59, 0x5a, 0xbb, 0x76, 0xcb, + 0x51, 0x44, 0x83, 0x52, 0xd9, 0x39, 0xa1, 0x40, 0x70, 0x16, 0x9c, 0x15, 0x80, 0x81, 0x07, 0x03, + 0x89, 0xca, 0x29, 0x87, 0x54, 0xe5, 0x94, 0x07, 0xca, 0x1b, 0xf8, 0x98, 0x4b, 0x52, 0xc9, 0x45, + 0x15, 0xf3, 0x49, 0x52, 0x33, 0x3d, 0xf8, 0xa1, 0xbc, 0x5a, 0x85, 0x37, 0x76, 0xcf, 0xd7, 0x5f, + 0xf7, 0x34, 0xbe, 0x19, 0x34, 0x08, 0xbf, 0x0e, 0x99, 0x1c, 0xe7, 0xc3, 0xbd, 0x80, 0xc7, 0xfb, + 0x01, 0x4f, 0xa4, 0xcf, 0x12, 0x2a, 0x46, 0xfb, 0x41, 0x28, 0x78, 0x9e, 0x66, 0xfb, 0x99, 0xf4, + 0x65, 0xb6, 0x7f, 0xfe, 0xf1, 0x7e, 0x4c, 0xa5, 0x60, 0x41, 0xb6, 0x97, 0x0a, 0x2e, 0x39, 0x71, + 0x18, 0xdf, 0xab, 0xd0, 0x7b, 0x06, 0xbd, 0x77, 0xfe, 0xf1, 0xe6, 0xbd, 0x90, 0x87, 0x5c, 0x83, + 0xf6, 0xd5, 0x2f, 0xc4, 0xf7, 0xfe, 0x65, 0x41, 0xeb, 0x08, 0x19, 0xc8, 0xef, 0xa0, 0x35, 0xce, + 0x43, 0x2a, 0xa3, 0xa1, 0xd3, 0xd8, 0x6e, 0xee, 0x76, 0x3e, 0x79, 0xb2, 0x77, 0x13, 0xdb, 0xde, + 0x4b, 0x04, 0x0e, 0xa4, 0x2f, 0xdd, 0x22, 0x8a, 0x3c, 0x03, 0x2b, 0x65, 0xa3, 0xcc, 0x59, 0xd8, + 0x6e, 0xec, 0x76, 0x3e, 0xe9, 0xdd, 0x1c, 0xdd, 0x67, 0xa3, 0x4c, 0x87, 0x6a, 0x3c, 0xf9, 0x0c, + 0x9a, 0x41, 0x9a, 0x3b, 0x4d, 0x1d, 0xf6, 0xe1, 0xcd, 0x61, 0x87, 0xfd, 0x53, 0x15, 0x75, 0xd0, + 0x9a, 0x5e, 0x75, 0x9b, 0x87, 0xfd, 0x53, 0x57, 0x85, 0x91, 0xcf, 0x60, 0x29, 0xa6, 0x31, 0x17, + 0x97, 0x8e, 0xa5, 0x09, 0x1e, 0xdf, 0x4c, 0x70, 0xa4, 0x71, 0x3a, 0xb3, 0x89, 0x21, 0xcf, 0x61, + 0x71, 0x18, 0x9d, 0x31, 0xee, 0x2c, 0xea, 0xe0, 0x9d, 0x9b, 0x83, 0x0f, 0xa2, 0xb3, 0x57, 0xc7, + 0x3a, 0x16, 0x23, 0xd4, 0x76, 0xc5, 0x28, 0xf6, 0x9d, 0xa5, 0xdb, 0xb6, 0xeb, 0x8e, 0x62, 0x1f, + 0xb7, 0xab, 0xf0, 0xaa, 0xcf, 0x09, 0x95, 0x17, 0x5c, 0x9c, 0x39, 0xad, 0xdb, 0xfa, 0xfc, 0x07, + 0x04, 0x62, 0x9f, 0x4d, 0x14, 0x79, 0x09, 0xcb, 0x08, 0xf1, 0xb4, 0x0a, 0x9c, 0xb6, 0x2e, 0xe0, + 0x1d, 0x2c, 0x87, 0xfa, 0xa7, 0x22, 0xc9, 0xdc, 0x4e, 0x50, 0x19, 0xe4, 0x3b, 0x20, 0xd8, 0x07, + 0x8f, 0xf3, 0xd8, 0x53, 0xc1, 0x82, 0x47, 0x8e, 0xad, 0xf9, 0x3e, 0xba, 0xad, 0x8f, 0xc7, 0x3c, + 0x3e, 0xc4, 0x08, 0x77, 0x2d, 0xbe, 0xe6, 0xe9, 0x9d, 0x41, 0xa7, 0xa6, 0x11, 0x72, 0x0f, 0x16, + 0xf3, 0xcc, 0x0f, 0xa9, 0xd3, 0xd8, 0x6e, 0xec, 0x5a, 0x2e, 0x1a, 0x64, 0x0d, 0x9a, 0xb1, 0x3f, + 0xd1, 0x7a, 0xb1, 0x5c, 0xf5, 0x93, 0x38, 0xd0, 0x7a, 0xed, 0xb3, 0x28, 0x48, 0xa4, 0x96, 0x83, + 0xe5, 0x16, 0x26, 0xd9, 0x84, 0x76, 0xea, 0x87, 0x34, 0x63, 0x7f, 0xa2, 0xfa, 0x41, 0xdb, 0x6e, + 0x69, 0xf7, 0x3e, 0x85, 0x76, 0x21, 0x29, 0xc5, 0x10, 0xe4, 0x42, 0xd0, 0x44, 0x9a, 0x5c, 0x85, + 0xa9, 0x6a, 0x88, 0x58, 0xcc, 0xa4, 0xc9, 0x87, 0x46, 0xef, 0xaf, 0x0d, 0x68, 0x19, 0x61, 0x91, + 0xdf, 0xd4, 0xab, 0x7c, 0xe7, 0x23, 0x3d, 0xec, 0x9f, 0x9e, 0x2a, 0x64, 0xb1, 0x93, 0x03, 0x00, + 0x39, 0x16, 0x5c, 0xca, 0x88, 0x25, 0xe1, 0xed, 0x07, 0xe0, 0x04, 0xb1, 0xd4, 0xad, 0x45, 0xf5, + 0xbe, 0x87, 0x76, 0x41, 0xab, 0x6a, 0x95, 0x5c, 0xfa, 0x51, 0xd1, 0x2f, 0x6d, 0x90, 0x07, 0xb0, + 0x74, 0x46, 0x45, 0x42, 0x23, 0xb3, 0x05, 0x63, 0x11, 0x02, 0x56, 0x9e, 0x51, 0x61, 0x5a, 0xa6, + 0x7f, 0x93, 0x1d, 0x68, 0xa5, 0x54, 0x78, 0xea, 0x60, 0x59, 0xdb, 0xcd, 0x5d, 0xeb, 0x00, 0xa6, + 0x57, 0xdd, 0xa5, 0x3e, 0x15, 0xea, 0xe0, 0x2c, 0xa5, 0x54, 0x1c, 0xa6, 0x79, 0x6f, 0x02, 0xed, + 0xa2, 0x14, 0xd5, 0xb8, 0x94, 0x0a, 0xc6, 0x47, 0x59, 0xd1, 0x38, 0x63, 0x92, 0xa7, 0xb0, 0x6e, + 0xca, 0xa4, 0x23, 0xaf, 0xc0, 0x60, 0x05, 0x6b, 0xe5, 0x42, 0xdf, 0x80, 0x9f, 0xc0, 0x6a, 0x05, + 0x96, 0x2c, 0xa6, 0xa6, 0xaa, 0x95, 0xd2, 0x7b, 0xc2, 0x62, 0xda, 0xfb, 0x4f, 0x07, 0xa0, 0x3a, + 0x8e, 0x6a, 0xbf, 0x81, 0x1f, 0x8c, 0x4b, 0x7d, 0x68, 0x83, 0x6c, 0x40, 0x53, 0x64, 0x26, 0x15, + 0x9e, 0x7a, 0x77, 0x30, 0x70, 0x95, 0x8f, 0xfc, 0x0c, 0xda, 0x22, 0xcb, 0x3c, 0x75, 0xf5, 0x60, + 0x82, 0x83, 0xce, 0xf4, 0xaa, 0xdb, 0x72, 0x07, 0x03, 0x25, 0x3b, 0xb7, 0x25, 0xb2, 0x4c, 0xfd, + 0x20, 0x5d, 0xe8, 0xc4, 0x7e, 0x9a, 0xd2, 0x91, 0xf7, 0x9a, 0x45, 0xa8, 0x1c, 0xcb, 0x05, 0x74, + 0x7d, 0xc5, 0x22, 0xdd, 0xe9, 0x11, 0x13, 0xf2, 0x52, 0x5f, 0x00, 0x96, 0x8b, 0x06, 0x79, 0x04, + 0xf6, 0x85, 0x60, 0x92, 0x0e, 0xfd, 0xe0, 0x4c, 0x1f, 0x70, 0xcb, 0xad, 0x1c, 0xc4, 0x81, 0x76, + 0x1a, 0x7a, 0x69, 0xe8, 0xb1, 0xc4, 0x69, 0xe1, 0x93, 0x48, 0xc3, 0x7e, 0xf8, 0x2a, 0x21, 0x9b, + 0x60, 0xe3, 0x0a, 0xcf, 0xa5, 0x3e, 0x97, 0xaa, 0x8d, 0x61, 0x3f, 0x3c, 0xce, 0x25, 0xd9, 0xd0, + 0x51, 0xaf, 0xfd, 0x3c, 0x92, 0xfa, 0x88, 0xe9, 0xa5, 0xaf, 0x94, 0x49, 0xb6, 0x61, 0x39, 0x0d, + 0xbd, 0xd8, 0x7f, 0x63, 0x96, 0x01, 0xcb, 0x4c, 0xc3, 0x23, 0xff, 0x0d, 0x22, 0x76, 0x60, 0x85, + 0x25, 0x7e, 0x20, 0xd9, 0x39, 0xf5, 0xfc, 0x84, 0x27, 0x4e, 0x47, 0x43, 0x96, 0x0b, 0xe7, 0x17, + 0x09, 0x4f, 0xd4, 0x66, 0xeb, 0x90, 0x65, 0x64, 0xa9, 0x01, 0xea, 0x2c, 0xba, 0x1f, 0x2b, 0xb3, + 0x2c, 0xba, 0x23, 0x15, 0x8b, 0x86, 0xac, 0xd6, 0x59, 0x34, 0x60, 0x1b, 0x3a, 0x79, 0x42, 0xcf, + 0x59, 0x20, 0xfd, 0x61, 0x44, 0x9d, 0x3b, 0x1a, 0x50, 0x77, 0x91, 0x4f, 0x61, 0x63, 0xcc, 0xa8, + 0xf0, 0x45, 0x30, 0x66, 0x81, 0x1f, 0x79, 0xe6, 0x92, 0xc1, 0xe3, 0xb7, 0xa6, 0xf1, 0x0f, 0xeb, + 0x00, 0x54, 0xc2, 0xef, 0xd5, 0x32, 0x79, 0x06, 0x33, 0x4b, 0x5e, 0x76, 0xe1, 0xa7, 0x26, 0x72, + 0x5d, 0x47, 0xde, 0xaf, 0x2f, 0x0f, 0x2e, 0xfc, 0x14, 0xe3, 0xba, 0xd0, 0xd1, 0xa7, 0xc4, 0x43, + 0x21, 0x11, 0x2c, 0x5b, 0xbb, 0x0e, 0xb5, 0x9a, 0x7e, 0x01, 0x36, 0x02, 0x94, 0xa6, 0xee, 0x6a, + 0xcd, 0x2c, 0x4f, 0xaf, 0xba, 0xed, 0x13, 0xe5, 0x54, 0xc2, 0x6a, 0xeb, 0x65, 0x37, 0xcb, 0xc8, + 0x33, 0x58, 0x2d, 0xa1, 0xa8, 0xb1, 0x7b, 0x1a, 0xbf, 0x36, 0xbd, 0xea, 0x2e, 0x17, 0x78, 0x2d, + 0xb4, 0xe5, 0x22, 0x46, 0xab, 0xed, 0x23, 0x58, 0xc7, 0xb8, 0xba, 0xe6, 0xee, 0xeb, 0x4a, 0xee, + 0xe8, 0x85, 0xa3, 0x4a, 0x78, 0x65, 0xbd, 0x28, 0xbf, 0x07, 0xb5, 0x7a, 0x5f, 0x68, 0x0d, 0xfe, + 0x1c, 0x30, 0xc6, 0xab, 0x94, 0xf8, 0x50, 0x83, 0xb0, 0xb6, 0x6f, 0x4b, 0x39, 0xee, 0x14, 0xd5, + 0x96, 0xa2, 0x74, 0xf0, 0x91, 0x68, 0x6f, 0x1f, 0x95, 0xf9, 0xa4, 0x60, 0xab, 0xf4, 0xb9, 0x81, + 0x0f, 0xbf, 0x44, 0x29, 0x91, 0x3e, 0xae, 0x71, 0xa1, 0x16, 0x37, 0x67, 0x50, 0xa8, 0xc6, 0xa7, + 0x40, 0x4a, 0x54, 0xa5, 0xda, 0xf7, 0x6b, 0x1b, 0xed, 0x57, 0xd2, 0xdd, 0x83, 0xbb, 0x08, 0x9e, + 0x15, 0xf0, 0x23, 0x8d, 0xc6, 0x7e, 0xbd, 0xaa, 0xab, 0xb8, 0x6c, 0x62, 0x1d, 0xfd, 0x41, 0x8d, + 0xfb, 0x8b, 0x0a, 0xfb, 0x53, 0x6e, 0xdd, 0xf2, 0xad, 0xb7, 0x70, 0xeb, 0xa6, 0x5f, 0xe7, 0xd6, + 0xe8, 0xee, 0x4f, 0xb8, 0x35, 0xf6, 0x69, 0x81, 0xad, 0x8b, 0x7d, 0xdb, 0x5c, 0x7b, 0x6a, 0xe1, + 0xb4, 0xa6, 0xf8, 0xdf, 0x16, 0xaf, 0x8e, 0x0f, 0x6f, 0x7b, 0x19, 0xa3, 0xd6, 0xbf, 0x4c, 0xa4, + 0xb8, 0x2c, 0xde, 0x1e, 0xcf, 0xc1, 0x52, 0x2a, 0x77, 0x7a, 0xf3, 0xc4, 0xea, 0x10, 0xf2, 0x79, + 0xf9, 0x4a, 0xd8, 0x99, 0x27, 0xb8, 0x78, 0x73, 0x0c, 0x00, 0xf0, 0x97, 0x27, 0x83, 0xd4, 0x79, + 0x3c, 0x07, 0xc5, 0xc1, 0xca, 0xf4, 0xaa, 0x6b, 0x7f, 0xad, 0x83, 0x4f, 0x0e, 0xfb, 0xae, 0x8d, + 0x3c, 0x27, 0x41, 0xda, 0xa3, 0xd0, 0xa9, 0x01, 0xab, 0xf7, 0x6e, 0xa3, 0xf6, 0xde, 0xad, 0x26, + 0x82, 0x85, 0xb7, 0x4c, 0x04, 0xcd, 0xb7, 0x4e, 0x04, 0xd6, 0xcc, 0x44, 0xd0, 0x93, 0xb0, 0x76, + 0x7d, 0x10, 0x21, 0xbb, 0xb0, 0xa6, 0x26, 0x99, 0x33, 0x16, 0xa9, 0x73, 0x95, 0xe9, 0x47, 0x86, + 0x69, 0x57, 0x39, 0x8f, 0xbf, 0x66, 0x51, 0xf4, 0x02, 0xbd, 0xe4, 0x7d, 0xb0, 0xf3, 0x64, 0x44, + 0x85, 0x9a, 0x7c, 0x4c, 0x0d, 0x6d, 0xed, 0x38, 0xe6, 0xb1, 0xba, 0xaa, 0x0b, 0x9a, 0x62, 0x0e, + 0x31, 0xe1, 0xbd, 0x7f, 0x2e, 0x82, 0x5d, 0x8e, 0x82, 0xc4, 0x87, 0x4d, 0xc6, 0xbd, 0x8c, 0x8a, + 0x73, 0x16, 0x50, 0x6f, 0x78, 0x29, 0x69, 0xe6, 0x09, 0x1a, 0xe4, 0x22, 0x63, 0xe7, 0xd4, 0x8c, + 0xd1, 0x8f, 0x6f, 0x99, 0x29, 0xf1, 0x89, 0x3c, 0x64, 0x7c, 0x80, 0x34, 0x07, 0x8a, 0xc5, 0x2d, + 0x48, 0xc8, 0x77, 0x70, 0xbf, 0x4a, 0x31, 0xaa, 0xb1, 0x2f, 0xcc, 0xc1, 0x7e, 0xb7, 0x64, 0x1f, + 0x55, 0xcc, 0x27, 0x70, 0x97, 0x71, 0xef, 0xfb, 0x9c, 0xe6, 0x33, 0xbc, 0xcd, 0x39, 0x78, 0xd7, + 0x19, 0xff, 0x46, 0xc7, 0x57, 0xac, 0x1e, 0x6c, 0xd4, 0x5a, 0xa2, 0x26, 0x80, 0x1a, 0xb7, 0x35, + 0x07, 0xf7, 0x83, 0xb2, 0x66, 0x35, 0x31, 0x54, 0x09, 0xfe, 0x08, 0x0f, 0x18, 0xf7, 0x2e, 0x7c, + 0x26, 0xaf, 0xb3, 0x2f, 0xce, 0xd7, 0x91, 0x6f, 0x7d, 0x26, 0x67, 0xa9, 0xb1, 0x23, 0x31, 0x15, + 0xe1, 0x4c, 0x47, 0x96, 0xe6, 0xeb, 0xc8, 0x91, 0x8e, 0xaf, 0x58, 0xfb, 0xb0, 0xce, 0xf8, 0xf5, + 0x5a, 0x5b, 0x73, 0x70, 0xde, 0x61, 0x7c, 0xb6, 0xce, 0x6f, 0x60, 0x3d, 0xa3, 0x81, 0xe4, 0xa2, + 0xae, 0xb6, 0xf6, 0x1c, 0x8c, 0x6b, 0x26, 0xbc, 0xa4, 0xec, 0x9d, 0x03, 0x54, 0xeb, 0x64, 0x15, + 0x16, 0x78, 0xaa, 0x4f, 0x8e, 0xed, 0x2e, 0xf0, 0x54, 0x4d, 0x9e, 0x23, 0x75, 0xd9, 0xe1, 0x71, + 0xb5, 0x5d, 0x63, 0xa9, 0x53, 0x1c, 0xfb, 0x6f, 0x78, 0x31, 0x7a, 0xa2, 0xa1, 0xbd, 0x2c, 0xe1, + 0xc2, 0x9c, 0x58, 0x34, 0x94, 0xf7, 0xdc, 0x8f, 0x72, 0x5a, 0x4c, 0x5a, 0xda, 0xe8, 0xfd, 0xa5, + 0x01, 0xed, 0xe2, 0x03, 0x89, 0x7c, 0x5e, 0x1f, 0xde, 0x9b, 0xef, 0xfe, 0x1e, 0x53, 0x41, 0xb8, + 0x99, 0x72, 0xc2, 0x7f, 0x5e, 0x4d, 0xf8, 0xff, 0x77, 0xb0, 0xf9, 0x0c, 0xa0, 0x60, 0x97, 0xbe, + 0xda, 0x6e, 0x1b, 0x33, 0xbb, 0xed, 0x42, 0x67, 0x1c, 0xf8, 0xde, 0xd8, 0x4f, 0x46, 0x11, 0xc5, + 0xb9, 0x74, 0xc5, 0x85, 0x71, 0xe0, 0xbf, 0x44, 0x4f, 0x01, 0xe0, 0xc3, 0x37, 0x34, 0x90, 0x99, + 0x6e, 0x0a, 0x02, 0x8e, 0xd1, 0xd3, 0xfb, 0xdb, 0x02, 0x74, 0x6a, 0xdf, 0x74, 0x6a, 0x72, 0x4f, + 0xfc, 0xb8, 0xc8, 0xa3, 0x7f, 0xab, 0xcb, 0x47, 0x4c, 0xf0, 0x2e, 0x31, 0x17, 0x53, 0x4b, 0x4c, + 0xf4, 0xa5, 0x40, 0x3e, 0x00, 0x10, 0x13, 0x2f, 0xf5, 0x83, 0x33, 0x6a, 0xe8, 0x2d, 0xd7, 0x16, + 0x93, 0x3e, 0x3a, 0xd4, 0x9d, 0x26, 0x26, 0x1e, 0x15, 0x82, 0x8b, 0xcc, 0xf4, 0xbe, 0x2d, 0x26, + 0x5f, 0x6a, 0xdb, 0xc4, 0x8e, 0x04, 0x57, 0x13, 0x88, 0x79, 0x06, 0xb6, 0x98, 0xbc, 0x40, 0x87, + 0xca, 0x2a, 0x8b, 0xac, 0x38, 0xf0, 0xb6, 0x64, 0x95, 0x55, 0x56, 0x59, 0x71, 0xe0, 0xb5, 0x65, + 0x3d, 0xab, 0x2c, 0xb3, 0xe2, 0xcc, 0xdb, 0x96, 0xb5, 0xac, 0xb2, 0xca, 0x6a, 0x17, 0xb1, 0x26, + 0x6b, 0xef, 0xef, 0x0d, 0xe8, 0xd4, 0xbe, 0x4e, 0x55, 0x03, 0x13, 0xe1, 0x65, 0x11, 0xa5, 0xa9, + 0xfa, 0x90, 0xc2, 0xab, 0x1b, 0x12, 0x31, 0x30, 0x1e, 0xc5, 0x97, 0x08, 0x4f, 0xe4, 0x49, 0x52, + 0x7c, 0x68, 0x59, 0xae, 0x9d, 0x08, 0x17, 0x1d, 0x66, 0x39, 0x93, 0x98, 0xae, 0x59, 0x2c, 0x0f, + 0xd0, 0x41, 0x7e, 0x09, 0x24, 0x11, 0x5e, 0x9e, 0xb0, 0x44, 0x52, 0x21, 0xf2, 0x54, 0xb2, 0x61, + 0xf9, 0x51, 0xb0, 0x9e, 0x88, 0xd3, 0xd9, 0x05, 0xf2, 0x48, 0xb3, 0x99, 0xcb, 0xc6, 0xb4, 0xac, + 0x9d, 0x88, 0x57, 0xfa, 0xe6, 0x38, 0x70, 0x7e, 0xf8, 0x71, 0xeb, 0xbd, 0x7f, 0xff, 0xb8, 0xf5, + 0xde, 0x9f, 0xa7, 0x5b, 0x8d, 0x1f, 0xa6, 0x5b, 0x8d, 0x7f, 0x4c, 0xb7, 0x1a, 0xff, 0x9d, 0x6e, + 0x35, 0x86, 0x4b, 0xfa, 0xcf, 0x95, 0x5f, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x4e, 0x24, + 0x22, 0xc4, 0x11, 0x00, 0x00, +} + +func (m *Metrics) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Metrics) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Metrics) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.MemoryOomControl != nil { + { + size, err := m.MemoryOomControl.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + if m.CgroupStats != nil { + { + size, err := m.CgroupStats.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if len(m.Network) > 0 { + for iNdEx := len(m.Network) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Network[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if m.Rdma != nil { + { + size, err := m.Rdma.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.Blkio != nil { + { + size, err := m.Blkio.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.Memory != nil { + { + size, err := m.Memory.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.CPU != nil { + { + size, err := m.CPU.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Pids != nil { + { + size, err := m.Pids.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Hugetlb) > 0 { + for iNdEx := len(m.Hugetlb) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Hugetlb[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *HugetlbStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HugetlbStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HugetlbStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Pagesize) > 0 { + i -= len(m.Pagesize) + copy(dAtA[i:], m.Pagesize) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Pagesize))) + i-- + dAtA[i] = 0x22 + } + if m.Failcnt != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Failcnt)) + i-- + dAtA[i] = 0x18 + } + if m.Max != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) + i-- + dAtA[i] = 0x10 + } + if m.Usage != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Usage)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *PidsStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PidsStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PidsStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Limit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x10 + } + if m.Current != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Current)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *CPUStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CPUStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CPUStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Throttling != nil { + { + size, err := m.Throttling.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Usage != nil { + { + size, err := m.Usage.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CPUUsage) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CPUUsage) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CPUUsage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.PerCPU) > 0 { + dAtA11 := make([]byte, len(m.PerCPU)*10) + var j10 int + for _, num := range m.PerCPU { + for num >= 1<<7 { + dAtA11[j10] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j10++ + } + dAtA11[j10] = uint8(num) + j10++ + } + i -= j10 + copy(dAtA[i:], dAtA11[:j10]) + i = encodeVarintMetrics(dAtA, i, uint64(j10)) + i-- + dAtA[i] = 0x22 + } + if m.User != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.User)) + i-- + dAtA[i] = 0x18 + } + if m.Kernel != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Kernel)) + i-- + dAtA[i] = 0x10 + } + if m.Total != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Total)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Throttle) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Throttle) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Throttle) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ThrottledTime != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ThrottledTime)) + i-- + dAtA[i] = 0x18 + } + if m.ThrottledPeriods != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ThrottledPeriods)) + i-- + dAtA[i] = 0x10 + } + if m.Periods != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Periods)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MemoryStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MemoryStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.KernelTCP != nil { + { + size, err := m.KernelTCP.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0xa2 + } + if m.Kernel != nil { + { + size, err := m.Kernel.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x9a + } + if m.Swap != nil { + { + size, err := m.Swap.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x92 + } + if m.Usage != nil { + { + size, err := m.Usage.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x8a + } + if m.TotalUnevictable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalUnevictable)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x80 + } + if m.TotalActiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalActiveFile)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xf8 + } + if m.TotalInactiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalInactiveFile)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xf0 + } + if m.TotalActiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalActiveAnon)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xe8 + } + if m.TotalInactiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalInactiveAnon)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xe0 + } + if m.TotalPgMajFault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgMajFault)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd8 + } + if m.TotalPgFault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgFault)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd0 + } + if m.TotalPgPgOut != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgPgOut)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc8 + } + if m.TotalPgPgIn != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalPgPgIn)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc0 + } + if m.TotalWriteback != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalWriteback)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb8 + } + if m.TotalDirty != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalDirty)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb0 + } + if m.TotalMappedFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalMappedFile)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa8 + } + if m.TotalRSSHuge != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalRSSHuge)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.TotalRSS != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalRSS)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } + if m.TotalCache != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TotalCache)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x90 + } + if m.HierarchicalSwapLimit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HierarchicalSwapLimit)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.HierarchicalMemoryLimit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HierarchicalMemoryLimit)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if m.Unevictable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Unevictable)) + i-- + dAtA[i] = 0x78 + } + if m.ActiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveFile)) + i-- + dAtA[i] = 0x70 + } + if m.InactiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveFile)) + i-- + dAtA[i] = 0x68 + } + if m.ActiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveAnon)) + i-- + dAtA[i] = 0x60 + } + if m.InactiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveAnon)) + i-- + dAtA[i] = 0x58 + } + if m.PgMajFault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.PgMajFault)) + i-- + dAtA[i] = 0x50 + } + if m.PgFault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.PgFault)) + i-- + dAtA[i] = 0x48 + } + if m.PgPgOut != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.PgPgOut)) + i-- + dAtA[i] = 0x40 + } + if m.PgPgIn != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.PgPgIn)) + i-- + dAtA[i] = 0x38 + } + if m.Writeback != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Writeback)) + i-- + dAtA[i] = 0x30 + } + if m.Dirty != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Dirty)) + i-- + dAtA[i] = 0x28 + } + if m.MappedFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.MappedFile)) + i-- + dAtA[i] = 0x20 + } + if m.RSSHuge != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RSSHuge)) + i-- + dAtA[i] = 0x18 + } + if m.RSS != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RSS)) + i-- + dAtA[i] = 0x10 + } + if m.Cache != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Cache)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MemoryEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MemoryEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Failcnt != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Failcnt)) + i-- + dAtA[i] = 0x20 + } + if m.Max != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) + i-- + dAtA[i] = 0x18 + } + if m.Usage != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Usage)) + i-- + dAtA[i] = 0x10 + } + if m.Limit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MemoryOomControl) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryOomControl) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MemoryOomControl) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.OomKill != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.OomKill)) + i-- + dAtA[i] = 0x18 + } + if m.UnderOom != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.UnderOom)) + i-- + dAtA[i] = 0x10 + } + if m.OomKillDisable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.OomKillDisable)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *BlkIOStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlkIOStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlkIOStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.SectorsRecursive) > 0 { + for iNdEx := len(m.SectorsRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SectorsRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.IoTimeRecursive) > 0 { + for iNdEx := len(m.IoTimeRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoTimeRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if len(m.IoMergedRecursive) > 0 { + for iNdEx := len(m.IoMergedRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoMergedRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.IoWaitTimeRecursive) > 0 { + for iNdEx := len(m.IoWaitTimeRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoWaitTimeRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.IoServiceTimeRecursive) > 0 { + for iNdEx := len(m.IoServiceTimeRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoServiceTimeRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.IoQueuedRecursive) > 0 { + for iNdEx := len(m.IoQueuedRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoQueuedRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.IoServicedRecursive) > 0 { + for iNdEx := len(m.IoServicedRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoServicedRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.IoServiceBytesRecursive) > 0 { + for iNdEx := len(m.IoServiceBytesRecursive) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IoServiceBytesRecursive[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *BlkIOEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlkIOEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlkIOEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Value != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x28 + } + if m.Minor != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Minor)) + i-- + dAtA[i] = 0x20 + } + if m.Major != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Major)) + i-- + dAtA[i] = 0x18 + } + if len(m.Device) > 0 { + i -= len(m.Device) + copy(dAtA[i:], m.Device) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Device))) + i-- + dAtA[i] = 0x12 + } + if len(m.Op) > 0 { + i -= len(m.Op) + copy(dAtA[i:], m.Op) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Op))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RdmaStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RdmaStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RdmaStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Limit) > 0 { + for iNdEx := len(m.Limit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Limit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Current) > 0 { + for iNdEx := len(m.Current) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Current[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RdmaEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RdmaEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RdmaEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.HcaObjects != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HcaObjects)) + i-- + dAtA[i] = 0x18 + } + if m.HcaHandles != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HcaHandles)) + i-- + dAtA[i] = 0x10 + } + if len(m.Device) > 0 { + i -= len(m.Device) + copy(dAtA[i:], m.Device) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Device))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *NetworkStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NetworkStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NetworkStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.TxDropped != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TxDropped)) + i-- + dAtA[i] = 0x48 + } + if m.TxErrors != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TxErrors)) + i-- + dAtA[i] = 0x40 + } + if m.TxPackets != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TxPackets)) + i-- + dAtA[i] = 0x38 + } + if m.TxBytes != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.TxBytes)) + i-- + dAtA[i] = 0x30 + } + if m.RxDropped != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RxDropped)) + i-- + dAtA[i] = 0x28 + } + if m.RxErrors != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RxErrors)) + i-- + dAtA[i] = 0x20 + } + if m.RxPackets != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RxPackets)) + i-- + dAtA[i] = 0x18 + } + if m.RxBytes != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.RxBytes)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CgroupStats) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CgroupStats) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CgroupStats) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.NrIoWait != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrIoWait)) + i-- + dAtA[i] = 0x28 + } + if m.NrUninterruptible != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrUninterruptible)) + i-- + dAtA[i] = 0x20 + } + if m.NrStopped != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrStopped)) + i-- + dAtA[i] = 0x18 + } + if m.NrRunning != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrRunning)) + i-- + dAtA[i] = 0x10 + } + if m.NrSleeping != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrSleeping)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int { + offset -= sovMetrics(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Metrics) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Hugetlb) > 0 { + for _, e := range m.Hugetlb { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.Pids != nil { + l = m.Pids.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.CPU != nil { + l = m.CPU.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Memory != nil { + l = m.Memory.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Blkio != nil { + l = m.Blkio.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Rdma != nil { + l = m.Rdma.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if len(m.Network) > 0 { + for _, e := range m.Network { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.CgroupStats != nil { + l = m.CgroupStats.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.MemoryOomControl != nil { + l = m.MemoryOomControl.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *HugetlbStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Usage != 0 { + n += 1 + sovMetrics(uint64(m.Usage)) + } + if m.Max != 0 { + n += 1 + sovMetrics(uint64(m.Max)) + } + if m.Failcnt != 0 { + n += 1 + sovMetrics(uint64(m.Failcnt)) + } + l = len(m.Pagesize) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *PidsStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Current != 0 { + n += 1 + sovMetrics(uint64(m.Current)) + } + if m.Limit != 0 { + n += 1 + sovMetrics(uint64(m.Limit)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CPUStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Usage != nil { + l = m.Usage.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Throttling != nil { + l = m.Throttling.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CPUUsage) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Total != 0 { + n += 1 + sovMetrics(uint64(m.Total)) + } + if m.Kernel != 0 { + n += 1 + sovMetrics(uint64(m.Kernel)) + } + if m.User != 0 { + n += 1 + sovMetrics(uint64(m.User)) + } + if len(m.PerCPU) > 0 { + l = 0 + for _, e := range m.PerCPU { + l += sovMetrics(uint64(e)) + } + n += 1 + sovMetrics(uint64(l)) + l + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Throttle) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Periods != 0 { + n += 1 + sovMetrics(uint64(m.Periods)) + } + if m.ThrottledPeriods != 0 { + n += 1 + sovMetrics(uint64(m.ThrottledPeriods)) + } + if m.ThrottledTime != 0 { + n += 1 + sovMetrics(uint64(m.ThrottledTime)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *MemoryStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Cache != 0 { + n += 1 + sovMetrics(uint64(m.Cache)) + } + if m.RSS != 0 { + n += 1 + sovMetrics(uint64(m.RSS)) + } + if m.RSSHuge != 0 { + n += 1 + sovMetrics(uint64(m.RSSHuge)) + } + if m.MappedFile != 0 { + n += 1 + sovMetrics(uint64(m.MappedFile)) + } + if m.Dirty != 0 { + n += 1 + sovMetrics(uint64(m.Dirty)) + } + if m.Writeback != 0 { + n += 1 + sovMetrics(uint64(m.Writeback)) + } + if m.PgPgIn != 0 { + n += 1 + sovMetrics(uint64(m.PgPgIn)) + } + if m.PgPgOut != 0 { + n += 1 + sovMetrics(uint64(m.PgPgOut)) + } + if m.PgFault != 0 { + n += 1 + sovMetrics(uint64(m.PgFault)) + } + if m.PgMajFault != 0 { + n += 1 + sovMetrics(uint64(m.PgMajFault)) + } + if m.InactiveAnon != 0 { + n += 1 + sovMetrics(uint64(m.InactiveAnon)) + } + if m.ActiveAnon != 0 { + n += 1 + sovMetrics(uint64(m.ActiveAnon)) + } + if m.InactiveFile != 0 { + n += 1 + sovMetrics(uint64(m.InactiveFile)) + } + if m.ActiveFile != 0 { + n += 1 + sovMetrics(uint64(m.ActiveFile)) + } + if m.Unevictable != 0 { + n += 1 + sovMetrics(uint64(m.Unevictable)) + } + if m.HierarchicalMemoryLimit != 0 { + n += 2 + sovMetrics(uint64(m.HierarchicalMemoryLimit)) + } + if m.HierarchicalSwapLimit != 0 { + n += 2 + sovMetrics(uint64(m.HierarchicalSwapLimit)) + } + if m.TotalCache != 0 { + n += 2 + sovMetrics(uint64(m.TotalCache)) + } + if m.TotalRSS != 0 { + n += 2 + sovMetrics(uint64(m.TotalRSS)) + } + if m.TotalRSSHuge != 0 { + n += 2 + sovMetrics(uint64(m.TotalRSSHuge)) + } + if m.TotalMappedFile != 0 { + n += 2 + sovMetrics(uint64(m.TotalMappedFile)) + } + if m.TotalDirty != 0 { + n += 2 + sovMetrics(uint64(m.TotalDirty)) + } + if m.TotalWriteback != 0 { + n += 2 + sovMetrics(uint64(m.TotalWriteback)) + } + if m.TotalPgPgIn != 0 { + n += 2 + sovMetrics(uint64(m.TotalPgPgIn)) + } + if m.TotalPgPgOut != 0 { + n += 2 + sovMetrics(uint64(m.TotalPgPgOut)) + } + if m.TotalPgFault != 0 { + n += 2 + sovMetrics(uint64(m.TotalPgFault)) + } + if m.TotalPgMajFault != 0 { + n += 2 + sovMetrics(uint64(m.TotalPgMajFault)) + } + if m.TotalInactiveAnon != 0 { + n += 2 + sovMetrics(uint64(m.TotalInactiveAnon)) + } + if m.TotalActiveAnon != 0 { + n += 2 + sovMetrics(uint64(m.TotalActiveAnon)) + } + if m.TotalInactiveFile != 0 { + n += 2 + sovMetrics(uint64(m.TotalInactiveFile)) + } + if m.TotalActiveFile != 0 { + n += 2 + sovMetrics(uint64(m.TotalActiveFile)) + } + if m.TotalUnevictable != 0 { + n += 2 + sovMetrics(uint64(m.TotalUnevictable)) + } + if m.Usage != nil { + l = m.Usage.Size() + n += 2 + l + sovMetrics(uint64(l)) + } + if m.Swap != nil { + l = m.Swap.Size() + n += 2 + l + sovMetrics(uint64(l)) + } + if m.Kernel != nil { + l = m.Kernel.Size() + n += 2 + l + sovMetrics(uint64(l)) + } + if m.KernelTCP != nil { + l = m.KernelTCP.Size() + n += 2 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *MemoryEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Limit != 0 { + n += 1 + sovMetrics(uint64(m.Limit)) + } + if m.Usage != 0 { + n += 1 + sovMetrics(uint64(m.Usage)) + } + if m.Max != 0 { + n += 1 + sovMetrics(uint64(m.Max)) + } + if m.Failcnt != 0 { + n += 1 + sovMetrics(uint64(m.Failcnt)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *MemoryOomControl) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.OomKillDisable != 0 { + n += 1 + sovMetrics(uint64(m.OomKillDisable)) + } + if m.UnderOom != 0 { + n += 1 + sovMetrics(uint64(m.UnderOom)) + } + if m.OomKill != 0 { + n += 1 + sovMetrics(uint64(m.OomKill)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *BlkIOStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IoServiceBytesRecursive) > 0 { + for _, e := range m.IoServiceBytesRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoServicedRecursive) > 0 { + for _, e := range m.IoServicedRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoQueuedRecursive) > 0 { + for _, e := range m.IoQueuedRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoServiceTimeRecursive) > 0 { + for _, e := range m.IoServiceTimeRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoWaitTimeRecursive) > 0 { + for _, e := range m.IoWaitTimeRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoMergedRecursive) > 0 { + for _, e := range m.IoMergedRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.IoTimeRecursive) > 0 { + for _, e := range m.IoTimeRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.SectorsRecursive) > 0 { + for _, e := range m.SectorsRecursive { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *BlkIOEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Op) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + l = len(m.Device) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Major != 0 { + n += 1 + sovMetrics(uint64(m.Major)) + } + if m.Minor != 0 { + n += 1 + sovMetrics(uint64(m.Minor)) + } + if m.Value != 0 { + n += 1 + sovMetrics(uint64(m.Value)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RdmaStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Current) > 0 { + for _, e := range m.Current { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.Limit) > 0 { + for _, e := range m.Limit { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RdmaEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Device) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.HcaHandles != 0 { + n += 1 + sovMetrics(uint64(m.HcaHandles)) + } + if m.HcaObjects != 0 { + n += 1 + sovMetrics(uint64(m.HcaObjects)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *NetworkStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.RxBytes != 0 { + n += 1 + sovMetrics(uint64(m.RxBytes)) + } + if m.RxPackets != 0 { + n += 1 + sovMetrics(uint64(m.RxPackets)) + } + if m.RxErrors != 0 { + n += 1 + sovMetrics(uint64(m.RxErrors)) + } + if m.RxDropped != 0 { + n += 1 + sovMetrics(uint64(m.RxDropped)) + } + if m.TxBytes != 0 { + n += 1 + sovMetrics(uint64(m.TxBytes)) + } + if m.TxPackets != 0 { + n += 1 + sovMetrics(uint64(m.TxPackets)) + } + if m.TxErrors != 0 { + n += 1 + sovMetrics(uint64(m.TxErrors)) + } + if m.TxDropped != 0 { + n += 1 + sovMetrics(uint64(m.TxDropped)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CgroupStats) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NrSleeping != 0 { + n += 1 + sovMetrics(uint64(m.NrSleeping)) + } + if m.NrRunning != 0 { + n += 1 + sovMetrics(uint64(m.NrRunning)) + } + if m.NrStopped != 0 { + n += 1 + sovMetrics(uint64(m.NrStopped)) + } + if m.NrUninterruptible != 0 { + n += 1 + sovMetrics(uint64(m.NrUninterruptible)) + } + if m.NrIoWait != 0 { + n += 1 + sovMetrics(uint64(m.NrIoWait)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovMetrics(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMetrics(x uint64) (n int) { + return sovMetrics(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Metrics) String() string { + if this == nil { + return "nil" + } + repeatedStringForHugetlb := "[]*HugetlbStat{" + for _, f := range this.Hugetlb { + repeatedStringForHugetlb += strings.Replace(f.String(), "HugetlbStat", "HugetlbStat", 1) + "," + } + repeatedStringForHugetlb += "}" + repeatedStringForNetwork := "[]*NetworkStat{" + for _, f := range this.Network { + repeatedStringForNetwork += strings.Replace(f.String(), "NetworkStat", "NetworkStat", 1) + "," + } + repeatedStringForNetwork += "}" + s := strings.Join([]string{`&Metrics{`, + `Hugetlb:` + repeatedStringForHugetlb + `,`, + `Pids:` + strings.Replace(this.Pids.String(), "PidsStat", "PidsStat", 1) + `,`, + `CPU:` + strings.Replace(this.CPU.String(), "CPUStat", "CPUStat", 1) + `,`, + `Memory:` + strings.Replace(this.Memory.String(), "MemoryStat", "MemoryStat", 1) + `,`, + `Blkio:` + strings.Replace(this.Blkio.String(), "BlkIOStat", "BlkIOStat", 1) + `,`, + `Rdma:` + strings.Replace(this.Rdma.String(), "RdmaStat", "RdmaStat", 1) + `,`, + `Network:` + repeatedStringForNetwork + `,`, + `CgroupStats:` + strings.Replace(this.CgroupStats.String(), "CgroupStats", "CgroupStats", 1) + `,`, + `MemoryOomControl:` + strings.Replace(this.MemoryOomControl.String(), "MemoryOomControl", "MemoryOomControl", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *HugetlbStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&HugetlbStat{`, + `Usage:` + fmt.Sprintf("%v", this.Usage) + `,`, + `Max:` + fmt.Sprintf("%v", this.Max) + `,`, + `Failcnt:` + fmt.Sprintf("%v", this.Failcnt) + `,`, + `Pagesize:` + fmt.Sprintf("%v", this.Pagesize) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *PidsStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PidsStat{`, + `Current:` + fmt.Sprintf("%v", this.Current) + `,`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CPUStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CPUStat{`, + `Usage:` + strings.Replace(this.Usage.String(), "CPUUsage", "CPUUsage", 1) + `,`, + `Throttling:` + strings.Replace(this.Throttling.String(), "Throttle", "Throttle", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CPUUsage) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CPUUsage{`, + `Total:` + fmt.Sprintf("%v", this.Total) + `,`, + `Kernel:` + fmt.Sprintf("%v", this.Kernel) + `,`, + `User:` + fmt.Sprintf("%v", this.User) + `,`, + `PerCPU:` + fmt.Sprintf("%v", this.PerCPU) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *Throttle) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Throttle{`, + `Periods:` + fmt.Sprintf("%v", this.Periods) + `,`, + `ThrottledPeriods:` + fmt.Sprintf("%v", this.ThrottledPeriods) + `,`, + `ThrottledTime:` + fmt.Sprintf("%v", this.ThrottledTime) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *MemoryStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryStat{`, + `Cache:` + fmt.Sprintf("%v", this.Cache) + `,`, + `RSS:` + fmt.Sprintf("%v", this.RSS) + `,`, + `RSSHuge:` + fmt.Sprintf("%v", this.RSSHuge) + `,`, + `MappedFile:` + fmt.Sprintf("%v", this.MappedFile) + `,`, + `Dirty:` + fmt.Sprintf("%v", this.Dirty) + `,`, + `Writeback:` + fmt.Sprintf("%v", this.Writeback) + `,`, + `PgPgIn:` + fmt.Sprintf("%v", this.PgPgIn) + `,`, + `PgPgOut:` + fmt.Sprintf("%v", this.PgPgOut) + `,`, + `PgFault:` + fmt.Sprintf("%v", this.PgFault) + `,`, + `PgMajFault:` + fmt.Sprintf("%v", this.PgMajFault) + `,`, + `InactiveAnon:` + fmt.Sprintf("%v", this.InactiveAnon) + `,`, + `ActiveAnon:` + fmt.Sprintf("%v", this.ActiveAnon) + `,`, + `InactiveFile:` + fmt.Sprintf("%v", this.InactiveFile) + `,`, + `ActiveFile:` + fmt.Sprintf("%v", this.ActiveFile) + `,`, + `Unevictable:` + fmt.Sprintf("%v", this.Unevictable) + `,`, + `HierarchicalMemoryLimit:` + fmt.Sprintf("%v", this.HierarchicalMemoryLimit) + `,`, + `HierarchicalSwapLimit:` + fmt.Sprintf("%v", this.HierarchicalSwapLimit) + `,`, + `TotalCache:` + fmt.Sprintf("%v", this.TotalCache) + `,`, + `TotalRSS:` + fmt.Sprintf("%v", this.TotalRSS) + `,`, + `TotalRSSHuge:` + fmt.Sprintf("%v", this.TotalRSSHuge) + `,`, + `TotalMappedFile:` + fmt.Sprintf("%v", this.TotalMappedFile) + `,`, + `TotalDirty:` + fmt.Sprintf("%v", this.TotalDirty) + `,`, + `TotalWriteback:` + fmt.Sprintf("%v", this.TotalWriteback) + `,`, + `TotalPgPgIn:` + fmt.Sprintf("%v", this.TotalPgPgIn) + `,`, + `TotalPgPgOut:` + fmt.Sprintf("%v", this.TotalPgPgOut) + `,`, + `TotalPgFault:` + fmt.Sprintf("%v", this.TotalPgFault) + `,`, + `TotalPgMajFault:` + fmt.Sprintf("%v", this.TotalPgMajFault) + `,`, + `TotalInactiveAnon:` + fmt.Sprintf("%v", this.TotalInactiveAnon) + `,`, + `TotalActiveAnon:` + fmt.Sprintf("%v", this.TotalActiveAnon) + `,`, + `TotalInactiveFile:` + fmt.Sprintf("%v", this.TotalInactiveFile) + `,`, + `TotalActiveFile:` + fmt.Sprintf("%v", this.TotalActiveFile) + `,`, + `TotalUnevictable:` + fmt.Sprintf("%v", this.TotalUnevictable) + `,`, + `Usage:` + strings.Replace(this.Usage.String(), "MemoryEntry", "MemoryEntry", 1) + `,`, + `Swap:` + strings.Replace(this.Swap.String(), "MemoryEntry", "MemoryEntry", 1) + `,`, + `Kernel:` + strings.Replace(this.Kernel.String(), "MemoryEntry", "MemoryEntry", 1) + `,`, + `KernelTCP:` + strings.Replace(this.KernelTCP.String(), "MemoryEntry", "MemoryEntry", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *MemoryEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryEntry{`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `Usage:` + fmt.Sprintf("%v", this.Usage) + `,`, + `Max:` + fmt.Sprintf("%v", this.Max) + `,`, + `Failcnt:` + fmt.Sprintf("%v", this.Failcnt) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *MemoryOomControl) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryOomControl{`, + `OomKillDisable:` + fmt.Sprintf("%v", this.OomKillDisable) + `,`, + `UnderOom:` + fmt.Sprintf("%v", this.UnderOom) + `,`, + `OomKill:` + fmt.Sprintf("%v", this.OomKill) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *BlkIOStat) String() string { + if this == nil { + return "nil" + } + repeatedStringForIoServiceBytesRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoServiceBytesRecursive { + repeatedStringForIoServiceBytesRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoServiceBytesRecursive += "}" + repeatedStringForIoServicedRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoServicedRecursive { + repeatedStringForIoServicedRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoServicedRecursive += "}" + repeatedStringForIoQueuedRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoQueuedRecursive { + repeatedStringForIoQueuedRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoQueuedRecursive += "}" + repeatedStringForIoServiceTimeRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoServiceTimeRecursive { + repeatedStringForIoServiceTimeRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoServiceTimeRecursive += "}" + repeatedStringForIoWaitTimeRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoWaitTimeRecursive { + repeatedStringForIoWaitTimeRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoWaitTimeRecursive += "}" + repeatedStringForIoMergedRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoMergedRecursive { + repeatedStringForIoMergedRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoMergedRecursive += "}" + repeatedStringForIoTimeRecursive := "[]*BlkIOEntry{" + for _, f := range this.IoTimeRecursive { + repeatedStringForIoTimeRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForIoTimeRecursive += "}" + repeatedStringForSectorsRecursive := "[]*BlkIOEntry{" + for _, f := range this.SectorsRecursive { + repeatedStringForSectorsRecursive += strings.Replace(f.String(), "BlkIOEntry", "BlkIOEntry", 1) + "," + } + repeatedStringForSectorsRecursive += "}" + s := strings.Join([]string{`&BlkIOStat{`, + `IoServiceBytesRecursive:` + repeatedStringForIoServiceBytesRecursive + `,`, + `IoServicedRecursive:` + repeatedStringForIoServicedRecursive + `,`, + `IoQueuedRecursive:` + repeatedStringForIoQueuedRecursive + `,`, + `IoServiceTimeRecursive:` + repeatedStringForIoServiceTimeRecursive + `,`, + `IoWaitTimeRecursive:` + repeatedStringForIoWaitTimeRecursive + `,`, + `IoMergedRecursive:` + repeatedStringForIoMergedRecursive + `,`, + `IoTimeRecursive:` + repeatedStringForIoTimeRecursive + `,`, + `SectorsRecursive:` + repeatedStringForSectorsRecursive + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *BlkIOEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&BlkIOEntry{`, + `Op:` + fmt.Sprintf("%v", this.Op) + `,`, + `Device:` + fmt.Sprintf("%v", this.Device) + `,`, + `Major:` + fmt.Sprintf("%v", this.Major) + `,`, + `Minor:` + fmt.Sprintf("%v", this.Minor) + `,`, + `Value:` + fmt.Sprintf("%v", this.Value) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *RdmaStat) String() string { + if this == nil { + return "nil" + } + repeatedStringForCurrent := "[]*RdmaEntry{" + for _, f := range this.Current { + repeatedStringForCurrent += strings.Replace(f.String(), "RdmaEntry", "RdmaEntry", 1) + "," + } + repeatedStringForCurrent += "}" + repeatedStringForLimit := "[]*RdmaEntry{" + for _, f := range this.Limit { + repeatedStringForLimit += strings.Replace(f.String(), "RdmaEntry", "RdmaEntry", 1) + "," + } + repeatedStringForLimit += "}" + s := strings.Join([]string{`&RdmaStat{`, + `Current:` + repeatedStringForCurrent + `,`, + `Limit:` + repeatedStringForLimit + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *RdmaEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RdmaEntry{`, + `Device:` + fmt.Sprintf("%v", this.Device) + `,`, + `HcaHandles:` + fmt.Sprintf("%v", this.HcaHandles) + `,`, + `HcaObjects:` + fmt.Sprintf("%v", this.HcaObjects) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *NetworkStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&NetworkStat{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `RxBytes:` + fmt.Sprintf("%v", this.RxBytes) + `,`, + `RxPackets:` + fmt.Sprintf("%v", this.RxPackets) + `,`, + `RxErrors:` + fmt.Sprintf("%v", this.RxErrors) + `,`, + `RxDropped:` + fmt.Sprintf("%v", this.RxDropped) + `,`, + `TxBytes:` + fmt.Sprintf("%v", this.TxBytes) + `,`, + `TxPackets:` + fmt.Sprintf("%v", this.TxPackets) + `,`, + `TxErrors:` + fmt.Sprintf("%v", this.TxErrors) + `,`, + `TxDropped:` + fmt.Sprintf("%v", this.TxDropped) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CgroupStats) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CgroupStats{`, + `NrSleeping:` + fmt.Sprintf("%v", this.NrSleeping) + `,`, + `NrRunning:` + fmt.Sprintf("%v", this.NrRunning) + `,`, + `NrStopped:` + fmt.Sprintf("%v", this.NrStopped) + `,`, + `NrUninterruptible:` + fmt.Sprintf("%v", this.NrUninterruptible) + `,`, + `NrIoWait:` + fmt.Sprintf("%v", this.NrIoWait) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func valueToStringMetrics(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Metrics) 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 ErrIntOverflowMetrics + } + 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: Metrics: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Metrics: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hugetlb", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hugetlb = append(m.Hugetlb, &HugetlbStat{}) + if err := m.Hugetlb[len(m.Hugetlb)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pids", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pids == nil { + m.Pids = &PidsStat{} + } + if err := m.Pids.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CPU", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CPU == nil { + m.CPU = &CPUStat{} + } + if err := m.CPU.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memory", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Memory == nil { + m.Memory = &MemoryStat{} + } + if err := m.Memory.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blkio", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Blkio == nil { + m.Blkio = &BlkIOStat{} + } + if err := m.Blkio.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rdma", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Rdma == nil { + m.Rdma = &RdmaStat{} + } + if err := m.Rdma.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Network = append(m.Network, &NetworkStat{}) + if err := m.Network[len(m.Network)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CgroupStats", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CgroupStats == nil { + m.CgroupStats = &CgroupStats{} + } + if err := m.CgroupStats.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MemoryOomControl", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MemoryOomControl == nil { + m.MemoryOomControl = &MemoryOomControl{} + } + if err := m.MemoryOomControl.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HugetlbStat) 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 ErrIntOverflowMetrics + } + 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: HugetlbStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HugetlbStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + m.Usage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Usage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) + } + m.Max = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Max |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Failcnt", wireType) + } + m.Failcnt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Failcnt |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagesize", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pagesize = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PidsStat) 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 ErrIntOverflowMetrics + } + 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: PidsStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PidsStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + m.Current = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Current |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CPUStat) 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 ErrIntOverflowMetrics + } + 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: CPUStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CPUStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Usage == nil { + m.Usage = &CPUUsage{} + } + if err := m.Usage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Throttling", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Throttling == nil { + m.Throttling = &Throttle{} + } + if err := m.Throttling.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CPUUsage) 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 ErrIntOverflowMetrics + } + 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: CPUUsage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CPUUsage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + m.Total = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Total |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Kernel", wireType) + } + m.Kernel = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Kernel |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field User", wireType) + } + m.User = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.User |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.PerCPU = append(m.PerCPU, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.PerCPU) == 0 { + m.PerCPU = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.PerCPU = append(m.PerCPU, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field PerCPU", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Throttle) 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 ErrIntOverflowMetrics + } + 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: Throttle: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Throttle: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Periods", wireType) + } + m.Periods = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Periods |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThrottledPeriods", wireType) + } + m.ThrottledPeriods = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThrottledPeriods |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThrottledTime", wireType) + } + m.ThrottledTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThrottledTime |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MemoryStat) 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 ErrIntOverflowMetrics + } + 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: MemoryStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Cache", wireType) + } + m.Cache = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Cache |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RSS", wireType) + } + m.RSS = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RSS |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RSSHuge", wireType) + } + m.RSSHuge = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RSSHuge |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MappedFile", wireType) + } + m.MappedFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MappedFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Dirty", wireType) + } + m.Dirty = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Dirty |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Writeback", wireType) + } + m.Writeback = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Writeback |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PgPgIn", wireType) + } + m.PgPgIn = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PgPgIn |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PgPgOut", wireType) + } + m.PgPgOut = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PgPgOut |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PgFault", wireType) + } + m.PgFault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PgFault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PgMajFault", wireType) + } + m.PgMajFault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PgMajFault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InactiveAnon", wireType) + } + m.InactiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InactiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveAnon", wireType) + } + m.ActiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ActiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InactiveFile", wireType) + } + m.InactiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InactiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveFile", wireType) + } + m.ActiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ActiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Unevictable", wireType) + } + m.Unevictable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Unevictable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HierarchicalMemoryLimit", wireType) + } + m.HierarchicalMemoryLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HierarchicalMemoryLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HierarchicalSwapLimit", wireType) + } + m.HierarchicalSwapLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HierarchicalSwapLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 18: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalCache", wireType) + } + m.TotalCache = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalCache |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalRSS", wireType) + } + m.TotalRSS = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalRSS |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalRSSHuge", wireType) + } + m.TotalRSSHuge = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalRSSHuge |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 21: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalMappedFile", wireType) + } + m.TotalMappedFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalMappedFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 22: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalDirty", wireType) + } + m.TotalDirty = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalDirty |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 23: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalWriteback", wireType) + } + m.TotalWriteback = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalWriteback |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 24: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPgPgIn", wireType) + } + m.TotalPgPgIn = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPgPgIn |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 25: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPgPgOut", wireType) + } + m.TotalPgPgOut = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPgPgOut |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 26: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPgFault", wireType) + } + m.TotalPgFault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPgFault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 27: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPgMajFault", wireType) + } + m.TotalPgMajFault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPgMajFault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 28: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInactiveAnon", wireType) + } + m.TotalInactiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalInactiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 29: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveAnon", wireType) + } + m.TotalActiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalActiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 30: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalInactiveFile", wireType) + } + m.TotalInactiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalInactiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 31: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalActiveFile", wireType) + } + m.TotalActiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalActiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 32: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalUnevictable", wireType) + } + m.TotalUnevictable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalUnevictable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 33: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Usage == nil { + m.Usage = &MemoryEntry{} + } + if err := m.Usage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 34: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Swap", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Swap == nil { + m.Swap = &MemoryEntry{} + } + if err := m.Swap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 35: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kernel", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Kernel == nil { + m.Kernel = &MemoryEntry{} + } + if err := m.Kernel.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 36: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field KernelTCP", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.KernelTCP == nil { + m.KernelTCP = &MemoryEntry{} + } + if err := m.KernelTCP.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MemoryEntry) 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 ErrIntOverflowMetrics + } + 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: MemoryEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + m.Usage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Usage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) + } + m.Max = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Max |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Failcnt", wireType) + } + m.Failcnt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Failcnt |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MemoryOomControl) 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 ErrIntOverflowMetrics + } + 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: MemoryOomControl: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryOomControl: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OomKillDisable", wireType) + } + m.OomKillDisable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OomKillDisable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnderOom", wireType) + } + m.UnderOom = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnderOom |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OomKill", wireType) + } + m.OomKill = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OomKill |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlkIOStat) 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 ErrIntOverflowMetrics + } + 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: BlkIOStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlkIOStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoServiceBytesRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoServiceBytesRecursive = append(m.IoServiceBytesRecursive, &BlkIOEntry{}) + if err := m.IoServiceBytesRecursive[len(m.IoServiceBytesRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoServicedRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoServicedRecursive = append(m.IoServicedRecursive, &BlkIOEntry{}) + if err := m.IoServicedRecursive[len(m.IoServicedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoQueuedRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoQueuedRecursive = append(m.IoQueuedRecursive, &BlkIOEntry{}) + if err := m.IoQueuedRecursive[len(m.IoQueuedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoServiceTimeRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoServiceTimeRecursive = append(m.IoServiceTimeRecursive, &BlkIOEntry{}) + if err := m.IoServiceTimeRecursive[len(m.IoServiceTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoWaitTimeRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoWaitTimeRecursive = append(m.IoWaitTimeRecursive, &BlkIOEntry{}) + if err := m.IoWaitTimeRecursive[len(m.IoWaitTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoMergedRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoMergedRecursive = append(m.IoMergedRecursive, &BlkIOEntry{}) + if err := m.IoMergedRecursive[len(m.IoMergedRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IoTimeRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IoTimeRecursive = append(m.IoTimeRecursive, &BlkIOEntry{}) + if err := m.IoTimeRecursive[len(m.IoTimeRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SectorsRecursive", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SectorsRecursive = append(m.SectorsRecursive, &BlkIOEntry{}) + if err := m.SectorsRecursive[len(m.SectorsRecursive)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlkIOEntry) 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 ErrIntOverflowMetrics + } + 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: BlkIOEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlkIOEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Op", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Op = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Device = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Major", wireType) + } + m.Major = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Major |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Minor", wireType) + } + m.Minor = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Minor |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RdmaStat) 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 ErrIntOverflowMetrics + } + 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: RdmaStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RdmaStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Current = append(m.Current, &RdmaEntry{}) + if err := m.Current[len(m.Current)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Limit = append(m.Limit, &RdmaEntry{}) + if err := m.Limit[len(m.Limit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RdmaEntry) 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 ErrIntOverflowMetrics + } + 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: RdmaEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RdmaEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Device = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HcaHandles", wireType) + } + m.HcaHandles = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HcaHandles |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HcaObjects", wireType) + } + m.HcaObjects = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HcaObjects |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NetworkStat) 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 ErrIntOverflowMetrics + } + 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: NetworkStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NetworkStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RxBytes", wireType) + } + m.RxBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RxBytes |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RxPackets", wireType) + } + m.RxPackets = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RxPackets |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RxErrors", wireType) + } + m.RxErrors = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RxErrors |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RxDropped", wireType) + } + m.RxDropped = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RxDropped |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxBytes", wireType) + } + m.TxBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxBytes |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxPackets", wireType) + } + m.TxPackets = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxPackets |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxErrors", wireType) + } + m.TxErrors = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxErrors |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxDropped", wireType) + } + m.TxDropped = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxDropped |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CgroupStats) 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 ErrIntOverflowMetrics + } + 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: CgroupStats: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CgroupStats: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrSleeping", wireType) + } + m.NrSleeping = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrSleeping |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrRunning", wireType) + } + m.NrRunning = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrRunning |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrStopped", wireType) + } + m.NrStopped = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrStopped |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrUninterruptible", wireType) + } + m.NrUninterruptible = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrUninterruptible |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrIoWait", wireType) + } + m.NrIoWait = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrIoWait |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMetrics(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetrics + } + 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, ErrIntOverflowMetrics + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetrics + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMetrics + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMetrics + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMetrics + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMetrics = fmt.Errorf("proto: unexpected end of group") +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt --- containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,790 @@ +file { + name: "github.com/containerd/cgroups/stats/v1/metrics.proto" + package: "io.containerd.cgroups.v1" + dependency: "gogoproto/gogo.proto" + message_type { + name: "Metrics" + field { + name: "hugetlb" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.HugetlbStat" + json_name: "hugetlb" + } + field { + name: "pids" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.PidsStat" + json_name: "pids" + } + field { + name: "cpu" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.CPUStat" + options { + 65004: "CPU" + } + json_name: "cpu" + } + field { + name: "memory" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryStat" + json_name: "memory" + } + field { + name: "blkio" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOStat" + json_name: "blkio" + } + field { + name: "rdma" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.RdmaStat" + json_name: "rdma" + } + field { + name: "network" + number: 7 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.NetworkStat" + json_name: "network" + } + field { + name: "cgroup_stats" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.CgroupStats" + json_name: "cgroupStats" + } + field { + name: "memory_oom_control" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryOomControl" + json_name: "memoryOomControl" + } + } + message_type { + name: "HugetlbStat" + field { + name: "usage" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "usage" + } + field { + name: "max" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "max" + } + field { + name: "failcnt" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "failcnt" + } + field { + name: "pagesize" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "pagesize" + } + } + message_type { + name: "PidsStat" + field { + name: "current" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "current" + } + field { + name: "limit" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "limit" + } + } + message_type { + name: "CPUStat" + field { + name: "usage" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.CPUUsage" + json_name: "usage" + } + field { + name: "throttling" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.Throttle" + json_name: "throttling" + } + } + message_type { + name: "CPUUsage" + field { + name: "total" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "total" + } + field { + name: "kernel" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "kernel" + } + field { + name: "user" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "user" + } + field { + name: "per_cpu" + number: 4 + label: LABEL_REPEATED + type: TYPE_UINT64 + options { + 65004: "PerCPU" + } + json_name: "perCpu" + } + } + message_type { + name: "Throttle" + field { + name: "periods" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "periods" + } + field { + name: "throttled_periods" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "throttledPeriods" + } + field { + name: "throttled_time" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "throttledTime" + } + } + message_type { + name: "MemoryStat" + field { + name: "cache" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "cache" + } + field { + name: "rss" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + options { + 65004: "RSS" + } + json_name: "rss" + } + field { + name: "rss_huge" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + options { + 65004: "RSSHuge" + } + json_name: "rssHuge" + } + field { + name: "mapped_file" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "mappedFile" + } + field { + name: "dirty" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "dirty" + } + field { + name: "writeback" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "writeback" + } + field { + name: "pg_pg_in" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgPgIn" + } + field { + name: "pg_pg_out" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgPgOut" + } + field { + name: "pg_fault" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgFault" + } + field { + name: "pg_maj_fault" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgMajFault" + } + field { + name: "inactive_anon" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "inactiveAnon" + } + field { + name: "active_anon" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "activeAnon" + } + field { + name: "inactive_file" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "inactiveFile" + } + field { + name: "active_file" + number: 14 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "activeFile" + } + field { + name: "unevictable" + number: 15 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "unevictable" + } + field { + name: "hierarchical_memory_limit" + number: 16 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "hierarchicalMemoryLimit" + } + field { + name: "hierarchical_swap_limit" + number: 17 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "hierarchicalSwapLimit" + } + field { + name: "total_cache" + number: 18 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalCache" + } + field { + name: "total_rss" + number: 19 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + options { + 65004: "TotalRSS" + } + json_name: "totalRss" + } + field { + name: "total_rss_huge" + number: 20 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + options { + 65004: "TotalRSSHuge" + } + json_name: "totalRssHuge" + } + field { + name: "total_mapped_file" + number: 21 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalMappedFile" + } + field { + name: "total_dirty" + number: 22 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalDirty" + } + field { + name: "total_writeback" + number: 23 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalWriteback" + } + field { + name: "total_pg_pg_in" + number: 24 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalPgPgIn" + } + field { + name: "total_pg_pg_out" + number: 25 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalPgPgOut" + } + field { + name: "total_pg_fault" + number: 26 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalPgFault" + } + field { + name: "total_pg_maj_fault" + number: 27 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalPgMajFault" + } + field { + name: "total_inactive_anon" + number: 28 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalInactiveAnon" + } + field { + name: "total_active_anon" + number: 29 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalActiveAnon" + } + field { + name: "total_inactive_file" + number: 30 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalInactiveFile" + } + field { + name: "total_active_file" + number: 31 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalActiveFile" + } + field { + name: "total_unevictable" + number: 32 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "totalUnevictable" + } + field { + name: "usage" + number: 33 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryEntry" + json_name: "usage" + } + field { + name: "swap" + number: 34 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryEntry" + json_name: "swap" + } + field { + name: "kernel" + number: 35 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryEntry" + json_name: "kernel" + } + field { + name: "kernel_tcp" + number: 36 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.MemoryEntry" + options { + 65004: "KernelTCP" + } + json_name: "kernelTcp" + } + } + message_type { + name: "MemoryEntry" + field { + name: "limit" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "limit" + } + field { + name: "usage" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "usage" + } + field { + name: "max" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "max" + } + field { + name: "failcnt" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "failcnt" + } + } + message_type { + name: "MemoryOomControl" + field { + name: "oom_kill_disable" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "oomKillDisable" + } + field { + name: "under_oom" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "underOom" + } + field { + name: "oom_kill" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "oomKill" + } + } + message_type { + name: "BlkIOStat" + field { + name: "io_service_bytes_recursive" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioServiceBytesRecursive" + } + field { + name: "io_serviced_recursive" + number: 2 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioServicedRecursive" + } + field { + name: "io_queued_recursive" + number: 3 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioQueuedRecursive" + } + field { + name: "io_service_time_recursive" + number: 4 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioServiceTimeRecursive" + } + field { + name: "io_wait_time_recursive" + number: 5 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioWaitTimeRecursive" + } + field { + name: "io_merged_recursive" + number: 6 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioMergedRecursive" + } + field { + name: "io_time_recursive" + number: 7 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "ioTimeRecursive" + } + field { + name: "sectors_recursive" + number: 8 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.BlkIOEntry" + json_name: "sectorsRecursive" + } + } + message_type { + name: "BlkIOEntry" + field { + name: "op" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "op" + } + field { + name: "device" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "device" + } + field { + name: "major" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "major" + } + field { + name: "minor" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "minor" + } + field { + name: "value" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "value" + } + } + message_type { + name: "RdmaStat" + field { + name: "current" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.RdmaEntry" + json_name: "current" + } + field { + name: "limit" + number: 2 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v1.RdmaEntry" + json_name: "limit" + } + } + message_type { + name: "RdmaEntry" + field { + name: "device" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "device" + } + field { + name: "hca_handles" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "hcaHandles" + } + field { + name: "hca_objects" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "hcaObjects" + } + } + message_type { + name: "NetworkStat" + field { + name: "name" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "name" + } + field { + name: "rx_bytes" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rxBytes" + } + field { + name: "rx_packets" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rxPackets" + } + field { + name: "rx_errors" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rxErrors" + } + field { + name: "rx_dropped" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rxDropped" + } + field { + name: "tx_bytes" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "txBytes" + } + field { + name: "tx_packets" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "txPackets" + } + field { + name: "tx_errors" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "txErrors" + } + field { + name: "tx_dropped" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "txDropped" + } + } + message_type { + name: "CgroupStats" + field { + name: "nr_sleeping" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrSleeping" + } + field { + name: "nr_running" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrRunning" + } + field { + name: "nr_stopped" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrStopped" + } + field { + name: "nr_uninterruptible" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrUninterruptible" + } + field { + name: "nr_io_wait" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrIoWait" + } + } + syntax: "proto3" +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto --- containerd-1.2.6/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/stats/v1/metrics.proto 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,158 @@ +syntax = "proto3"; + +package io.containerd.cgroups.v1; + +import "gogoproto/gogo.proto"; + +message Metrics { + repeated HugetlbStat hugetlb = 1; + PidsStat pids = 2; + CPUStat cpu = 3 [(gogoproto.customname) = "CPU"]; + MemoryStat memory = 4; + BlkIOStat blkio = 5; + RdmaStat rdma = 6; + repeated NetworkStat network = 7; + CgroupStats cgroup_stats = 8; + MemoryOomControl memory_oom_control = 9; +} + +message HugetlbStat { + uint64 usage = 1; + uint64 max = 2; + uint64 failcnt = 3; + string pagesize = 4; +} + +message PidsStat { + uint64 current = 1; + uint64 limit = 2; +} + +message CPUStat { + CPUUsage usage = 1; + Throttle throttling = 2; +} + +message CPUUsage { + // values in nanoseconds + uint64 total = 1; + uint64 kernel = 2; + uint64 user = 3; + repeated uint64 per_cpu = 4 [(gogoproto.customname) = "PerCPU"]; + +} + +message Throttle { + uint64 periods = 1; + uint64 throttled_periods = 2; + uint64 throttled_time = 3; +} + +message MemoryStat { + uint64 cache = 1; + uint64 rss = 2 [(gogoproto.customname) = "RSS"]; + uint64 rss_huge = 3 [(gogoproto.customname) = "RSSHuge"]; + uint64 mapped_file = 4; + uint64 dirty = 5; + uint64 writeback = 6; + uint64 pg_pg_in = 7; + uint64 pg_pg_out = 8; + uint64 pg_fault = 9; + uint64 pg_maj_fault = 10; + uint64 inactive_anon = 11; + uint64 active_anon = 12; + uint64 inactive_file = 13; + uint64 active_file = 14; + uint64 unevictable = 15; + uint64 hierarchical_memory_limit = 16; + uint64 hierarchical_swap_limit = 17; + uint64 total_cache = 18; + uint64 total_rss = 19 [(gogoproto.customname) = "TotalRSS"]; + uint64 total_rss_huge = 20 [(gogoproto.customname) = "TotalRSSHuge"]; + uint64 total_mapped_file = 21; + uint64 total_dirty = 22; + uint64 total_writeback = 23; + uint64 total_pg_pg_in = 24; + uint64 total_pg_pg_out = 25; + uint64 total_pg_fault = 26; + uint64 total_pg_maj_fault = 27; + uint64 total_inactive_anon = 28; + uint64 total_active_anon = 29; + uint64 total_inactive_file = 30; + uint64 total_active_file = 31; + uint64 total_unevictable = 32; + MemoryEntry usage = 33; + MemoryEntry swap = 34; + MemoryEntry kernel = 35; + MemoryEntry kernel_tcp = 36 [(gogoproto.customname) = "KernelTCP"]; + +} + +message MemoryEntry { + uint64 limit = 1; + uint64 usage = 2; + uint64 max = 3; + uint64 failcnt = 4; +} + +message MemoryOomControl { + uint64 oom_kill_disable = 1; + uint64 under_oom = 2; + uint64 oom_kill = 3; +} + +message BlkIOStat { + repeated BlkIOEntry io_service_bytes_recursive = 1; + repeated BlkIOEntry io_serviced_recursive = 2; + repeated BlkIOEntry io_queued_recursive = 3; + repeated BlkIOEntry io_service_time_recursive = 4; + repeated BlkIOEntry io_wait_time_recursive = 5; + repeated BlkIOEntry io_merged_recursive = 6; + repeated BlkIOEntry io_time_recursive = 7; + repeated BlkIOEntry sectors_recursive = 8; +} + +message BlkIOEntry { + string op = 1; + string device = 2; + uint64 major = 3; + uint64 minor = 4; + uint64 value = 5; +} + +message RdmaStat { + repeated RdmaEntry current = 1; + repeated RdmaEntry limit = 2; +} + +message RdmaEntry { + string device = 1; + uint32 hca_handles = 2; + uint32 hca_objects = 3; +} + +message NetworkStat { + string name = 1; + uint64 rx_bytes = 2; + uint64 rx_packets = 3; + uint64 rx_errors = 4; + uint64 rx_dropped = 5; + uint64 tx_bytes = 6; + uint64 tx_packets = 7; + uint64 tx_errors = 8; + uint64 tx_dropped = 9; +} + +// CgroupStats exports per-cgroup statistics. +message CgroupStats { + // number of tasks sleeping + uint64 nr_sleeping = 1; + // number of tasks running + uint64 nr_running = 2; + // number of tasks in stopped state + uint64 nr_stopped = 3; + // number of tasks in uninterruptible state + uint64 nr_uninterruptible = 4; + // number of tasks waiting on IO + uint64 nr_io_wait = 5; +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/subsystem.go containerd-1.5.9/vendor/github.com/containerd/cgroups/subsystem.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/subsystem.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/subsystem.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,7 +18,9 @@ import ( "fmt" + "os" + v1 "github.com/containerd/cgroups/stats/v1" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -45,7 +47,6 @@ // available on most linux systems func Subsystems() []Name { n := []Name{ - Hugetlb, Freezer, Pids, NetCLS, @@ -58,9 +59,12 @@ Blkio, Rdma, } - if !isUserNS { + if !RunningInUserNS() { n = append(n, Devices) } + if _, err := os.Stat("/sys/kernel/mm/hugepages"); err == nil { + n = append(n, Hugetlb) + } return n } @@ -85,7 +89,7 @@ type stater interface { Subsystem - Stat(path string, stats *Metrics) error + Stat(path string, stats *v1.Metrics) error } type updater interface { diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/systemd.go containerd-1.5.9/vendor/github.com/containerd/cgroups/systemd.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/systemd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/systemd.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,13 +17,12 @@ package cgroups import ( - "fmt" "path/filepath" "strings" "sync" - systemdDbus "github.com/coreos/go-systemd/dbus" - "github.com/godbus/dbus" + systemdDbus "github.com/coreos/go-systemd/v22/dbus" + "github.com/godbus/dbus/v5" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -78,7 +77,7 @@ return SystemdDbus } -func (s *SystemdController) Create(path string, resources *specs.LinuxResources) error { +func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error { conn, err := systemdDbus.New() if err != nil { return err @@ -105,7 +104,7 @@ } once.Do(checkDelegate) properties := []systemdDbus.Property{ - systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)), + systemdDbus.PropDescription("cgroup " + name), systemdDbus.PropWants(slice), newProperty("DefaultDependencies", false), newProperty("MemoryAccounting", true), @@ -150,10 +149,6 @@ } } -func unitName(name string) string { - return fmt.Sprintf("%s.slice", name) -} - func splitName(path string) (slice string, unit string) { slice, unit = filepath.Split(path) return strings.TrimSuffix(slice, "/"), unit diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/utils.go containerd-1.5.9/vendor/github.com/containerd/cgroups/utils.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/utils.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "bufio" + "errors" "fmt" "io" "io/ioutil" @@ -25,41 +26,93 @@ "path/filepath" "strconv" "strings" + "sync" + "syscall" "time" units "github.com/docker/go-units" specs "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/sys/unix" ) -var isUserNS = runningInUserNS() +var ( + nsOnce sync.Once + inUserNS bool + checkMode sync.Once + cgMode CGMode +) + +const unifiedMountpoint = "/sys/fs/cgroup" + +// CGMode is the cgroups mode of the host system +type CGMode int + +const ( + // Unavailable cgroup mountpoint + Unavailable CGMode = iota + // Legacy cgroups v1 + Legacy + // Hybrid with cgroups v1 and v2 controllers mounted + Hybrid + // Unified with only cgroups v2 mounted + Unified +) + +// Mode returns the cgroups mode running on the host +func Mode() CGMode { + checkMode.Do(func() { + var st unix.Statfs_t + if err := unix.Statfs(unifiedMountpoint, &st); err != nil { + cgMode = Unavailable + return + } + switch st.Type { + case unix.CGROUP2_SUPER_MAGIC: + cgMode = Unified + default: + cgMode = Legacy + if err := unix.Statfs(filepath.Join(unifiedMountpoint, "unified"), &st); err != nil { + return + } + if st.Type == unix.CGROUP2_SUPER_MAGIC { + cgMode = Hybrid + } + } + }) + return cgMode +} -// runningInUserNS detects whether we are currently running in a user namespace. +// RunningInUserNS detects whether we are currently running in a user namespace. // Copied from github.com/lxc/lxd/shared/util.go -func runningInUserNS() bool { - file, err := os.Open("/proc/self/uid_map") - if err != nil { - // This kernel-provided file only exists if user namespaces are supported - return false - } - defer file.Close() +func RunningInUserNS() bool { + nsOnce.Do(func() { + file, err := os.Open("/proc/self/uid_map") + if err != nil { + // This kernel-provided file only exists if user namespaces are supported + return + } + defer file.Close() - buf := bufio.NewReader(file) - l, _, err := buf.ReadLine() - if err != nil { - return false - } + buf := bufio.NewReader(file) + l, _, err := buf.ReadLine() + if err != nil { + return + } - line := string(l) - var a, b, c int64 - fmt.Sscanf(line, "%d %d %d", &a, &b, &c) - /* - * We assume we are in the initial user namespace if we have a full - * range - 4294967295 uids starting at uid 0. - */ - if a == 0 && b == 0 && c == 4294967295 { - return false - } - return true + line := string(l) + var a, b, c int64 + fmt.Sscanf(line, "%d %d %d", &a, &b, &c) + + /* + * We assume we are in the initial user namespace if we have a full + * range - 4294967295 uids starting at uid 0. + */ + if a == 0 && b == 0 && c == 4294967295 { + return + } + inUserNS = true + }) + return inUserNS } // defaults returns all known groups @@ -75,7 +128,7 @@ NewNetCls(root), NewNetPrio(root), NewPerfEvent(root), - NewCputset(root), + NewCpuset(root), NewCpu(root), NewCpuacct(root), NewMemory(root), @@ -84,7 +137,7 @@ } // only add the devices cgroup if we are not in a user namespace // because modifications are not allowed - if !isUserNS { + if !RunningInUserNS() { s = append(s, NewDevices(root)) } // add the hugetlb cgroup if error wasn't due to missing hugetlb @@ -135,6 +188,10 @@ }) } } + if err := s.Err(); err != nil { + // failed to read all pids? + return nil, err + } return out, nil } @@ -162,13 +219,16 @@ }) } } + if err := s.Err(); err != nil { + return nil, err + } return out, nil } func hugePageSizes() ([]string, error) { var ( pageSizes []string - sizeList = []string{"B", "kB", "MB", "GB", "TB", "PB"} + sizeList = []string{"B", "KB", "MB", "GB", "TB", "PB"} ) files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages") if err != nil { @@ -240,9 +300,6 @@ s = bufio.NewScanner(r) ) for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } var ( text = s.Text() parts = strings.SplitN(text, ":", 3) @@ -256,6 +313,9 @@ } } } + if err := s.Err(); err != nil { + return nil, err + } return cgroups, nil } @@ -267,16 +327,23 @@ defer f.Close() s := bufio.NewScanner(f) for s.Scan() { - if err := s.Err(); err != nil { - return "", err + fields := strings.Split(s.Text(), " ") + if len(fields) < 10 { + // broken mountinfo? + continue + } + if fields[len(fields)-3] != "cgroup" { + continue } - fields := strings.Fields(s.Text()) for _, opt := range strings.Split(fields[len(fields)-1], ",") { if opt == subsystem { return fields[3], nil } } } + if err := s.Err(); err != nil { + return "", err + } return "", ErrNoCgroupMountDestination } @@ -320,5 +387,18 @@ if !filepath.IsAbs(path) { path, _ = filepath.Rel(string(os.PathSeparator), filepath.Clean(string(os.PathSeparator)+path)) } - return filepath.Clean(path) + return path +} + +func retryingWriteFile(path string, data []byte, mode os.FileMode) error { + // Retry writes on EINTR; see: + // https://github.com/golang/go/issues/38033 + for { + err := ioutil.WriteFile(path, data, mode) + if err == nil { + return nil + } else if !errors.Is(err, syscall.EINTR) { + return err + } + } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v1.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v1.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v1.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v1.go 2022-01-05 17:30:58.000000000 +0000 @@ -54,28 +54,20 @@ defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { - if err := scanner.Err(); err != nil { - return "", err - } var ( - text = scanner.Text() - fields = strings.Split(text, " ") - // safe as mountinfo encodes mountpoints with spaces as \040. - index = strings.Index(text, " - ") - postSeparatorFields = strings.Fields(text[index+3:]) - numPostFields = len(postSeparatorFields) + text = scanner.Text() + fields = strings.Split(text, " ") + numFields = len(fields) ) - // this is an error as we can't detect if the mount is for "cgroup" - if numPostFields == 0 { - return "", fmt.Errorf("Found no fields post '-' in %q", text) + if numFields < 10 { + return "", fmt.Errorf("mountinfo: bad entry %q", text) } - if postSeparatorFields[0] == "cgroup" { - // check that the mount is properly formated. - if numPostFields < 3 { - return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) - } + if fields[numFields-3] == "cgroup" { return filepath.Dir(fields[4]), nil } } + if err := scanner.Err(); err != nil { + return "", err + } return "", ErrMountPointNotExist } diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/cpu.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/cpu.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/cpu.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/cpu.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "math" + "strconv" + "strings" +) + +type CPUMax string + +func NewCPUMax(quota *int64, period *uint64) CPUMax { + max := "max" + if quota != nil { + max = strconv.FormatInt(*quota, 10) + } + return CPUMax(strings.Join([]string{max, strconv.FormatUint(*period, 10)}, " ")) +} + +type CPU struct { + Weight *uint64 + Max CPUMax + Cpus string + Mems string +} + +func (c CPUMax) extractQuotaAndPeriod() (int64, uint64) { + var ( + quota int64 + period uint64 + ) + values := strings.Split(string(c), " ") + if values[0] == "max" { + quota = math.MaxInt64 + } else { + quota, _ = strconv.ParseInt(values[0], 10, 64) + } + period, _ = strconv.ParseUint(values[1], 10, 64) + return quota, period +} + +func (r *CPU) Values() (o []Value) { + if r.Weight != nil { + o = append(o, Value{ + filename: "cpu.weight", + value: *r.Weight, + }) + } + if r.Max != "" { + o = append(o, Value{ + filename: "cpu.max", + value: r.Max, + }) + } + if r.Cpus != "" { + o = append(o, Value{ + filename: "cpuset.cpus", + value: r.Cpus, + }) + } + if r.Mems != "" { + o = append(o, Value{ + filename: "cpuset.mems", + value: r.Mems, + }) + } + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/devicefilter.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/devicefilter.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/devicefilter.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/devicefilter.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,199 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Devicefilter containes eBPF device filter program +// +// The implementation is based on https://github.com/containers/crun/blob/0.10.2/src/libcrun/ebpf.c +// +// Although ebpf.c is originally licensed under LGPL-3.0-or-later, the author (Giuseppe Scrivano) +// agreed to relicense the file in Apache License 2.0: https://github.com/opencontainers/runc/issues/2144#issuecomment-543116397 +// +// This particular Go implementation based on runc version +// https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go +package v2 + +import ( + "fmt" + "math" + + "github.com/cilium/ebpf/asm" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const ( + // license string format is same as kernel MODULE_LICENSE macro + license = "Apache" +) + +// DeviceFilter returns eBPF device filter program and its license string +func DeviceFilter(devices []specs.LinuxDeviceCgroup) (asm.Instructions, string, error) { + p := &program{} + p.init() + for i := len(devices) - 1; i >= 0; i-- { + if err := p.appendDevice(devices[i]); err != nil { + return nil, "", err + } + } + insts, err := p.finalize() + return insts, license, err +} + +type program struct { + insts asm.Instructions + hasWildCard bool + blockID int +} + +func (p *program) init() { + // struct bpf_cgroup_dev_ctx: https://elixir.bootlin.com/linux/v5.3.6/source/include/uapi/linux/bpf.h#L3423 + /* + u32 access_type + u32 major + u32 minor + */ + // R2 <- type (lower 16 bit of u32 access_type at R1[0]) + p.insts = append(p.insts, + asm.LoadMem(asm.R2, asm.R1, 0, asm.Half)) + + // R3 <- access (upper 16 bit of u32 access_type at R1[0]) + p.insts = append(p.insts, + asm.LoadMem(asm.R3, asm.R1, 0, asm.Word), + // RSh: bitwise shift right + asm.RSh.Imm32(asm.R3, 16)) + + // R4 <- major (u32 major at R1[4]) + p.insts = append(p.insts, + asm.LoadMem(asm.R4, asm.R1, 4, asm.Word)) + + // R5 <- minor (u32 minor at R1[8]) + p.insts = append(p.insts, + asm.LoadMem(asm.R5, asm.R1, 8, asm.Word)) +} + +// appendDevice needs to be called from the last element of OCI linux.resources.devices to the head element. +func (p *program) appendDevice(dev specs.LinuxDeviceCgroup) error { + if p.blockID < 0 { + return errors.New("the program is finalized") + } + if p.hasWildCard { + // All entries after wildcard entry are ignored + return nil + } + + bpfType := int32(-1) + hasType := true + switch dev.Type { + case string('c'): + bpfType = int32(unix.BPF_DEVCG_DEV_CHAR) + case string('b'): + bpfType = int32(unix.BPF_DEVCG_DEV_BLOCK) + case string('a'): + hasType = false + default: + // if not specified in OCI json, typ is set to DeviceTypeAll + return errors.Errorf("invalid DeviceType %q", dev.Type) + } + if *dev.Major > math.MaxUint32 { + return errors.Errorf("invalid major %d", *dev.Major) + } + if *dev.Minor > math.MaxUint32 { + return errors.Errorf("invalid minor %d", *dev.Major) + } + hasMajor := *dev.Major >= 0 // if not specified in OCI json, major is set to -1 + hasMinor := *dev.Minor >= 0 + bpfAccess := int32(0) + for _, r := range dev.Access { + switch r { + case 'r': + bpfAccess |= unix.BPF_DEVCG_ACC_READ + case 'w': + bpfAccess |= unix.BPF_DEVCG_ACC_WRITE + case 'm': + bpfAccess |= unix.BPF_DEVCG_ACC_MKNOD + default: + return errors.Errorf("unknown device access %v", r) + } + } + // If the access is rwm, skip the check. + hasAccess := bpfAccess != (unix.BPF_DEVCG_ACC_READ | unix.BPF_DEVCG_ACC_WRITE | unix.BPF_DEVCG_ACC_MKNOD) + + blockSym := fmt.Sprintf("block-%d", p.blockID) + nextBlockSym := fmt.Sprintf("block-%d", p.blockID+1) + prevBlockLastIdx := len(p.insts) - 1 + if hasType { + p.insts = append(p.insts, + // if (R2 != bpfType) goto next + asm.JNE.Imm(asm.R2, bpfType, nextBlockSym), + ) + } + if hasAccess { + p.insts = append(p.insts, + // if (R3 & bpfAccess == 0 /* use R1 as a temp var */) goto next + asm.Mov.Reg32(asm.R1, asm.R3), + asm.And.Imm32(asm.R1, bpfAccess), + asm.JEq.Imm(asm.R1, 0, nextBlockSym), + ) + } + if hasMajor { + p.insts = append(p.insts, + // if (R4 != major) goto next + asm.JNE.Imm(asm.R4, int32(*dev.Major), nextBlockSym), + ) + } + if hasMinor { + p.insts = append(p.insts, + // if (R5 != minor) goto next + asm.JNE.Imm(asm.R5, int32(*dev.Minor), nextBlockSym), + ) + } + if !hasType && !hasAccess && !hasMajor && !hasMinor { + p.hasWildCard = true + } + p.insts = append(p.insts, acceptBlock(dev.Allow)...) + // set blockSym to the first instruction we added in this iteration + p.insts[prevBlockLastIdx+1] = p.insts[prevBlockLastIdx+1].Sym(blockSym) + p.blockID++ + return nil +} + +func (p *program) finalize() (asm.Instructions, error) { + if p.hasWildCard { + // acceptBlock with asm.Return() is already inserted + return p.insts, nil + } + blockSym := fmt.Sprintf("block-%d", p.blockID) + p.insts = append(p.insts, + // R0 <- 0 + asm.Mov.Imm32(asm.R0, 0).Sym(blockSym), + asm.Return(), + ) + p.blockID = -1 + return p.insts, nil +} + +func acceptBlock(accept bool) asm.Instructions { + v := int32(0) + if accept { + v = 1 + } + return []asm.Instruction{ + // R0 <- v + asm.Mov.Imm32(asm.R0, v), + asm.Return(), + } +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/ebpf.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/ebpf.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/ebpf.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/ebpf.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,95 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/asm" + "github.com/cilium/ebpf/link" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// LoadAttachCgroupDeviceFilter installs eBPF device filter program to /sys/fs/cgroup/ directory. +// +// Requires the system to be running in cgroup2 unified-mode with kernel >= 4.15 . +// +// https://github.com/torvalds/linux/commit/ebc614f687369f9df99828572b1d85a7c2de3d92 +func LoadAttachCgroupDeviceFilter(insts asm.Instructions, license string, dirFD int) (func() error, error) { + nilCloser := func() error { + return nil + } + spec := &ebpf.ProgramSpec{ + Type: ebpf.CGroupDevice, + Instructions: insts, + License: license, + } + prog, err := ebpf.NewProgram(spec) + if err != nil { + return nilCloser, err + } + err = link.RawAttachProgram(link.RawAttachProgramOptions{ + Target: dirFD, + Program: prog, + Attach: ebpf.AttachCGroupDevice, + Flags: unix.BPF_F_ALLOW_MULTI, + }) + if err != nil { + return nilCloser, errors.Wrap(err, "failed to call BPF_PROG_ATTACH (BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI)") + } + closer := func() error { + err = link.RawDetachProgram(link.RawDetachProgramOptions{ + Target: dirFD, + Program: prog, + Attach: ebpf.AttachCGroupDevice, + }) + if err != nil { + return errors.Wrap(err, "failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE)") + } + return nil + } + return closer, nil +} + +func isRWM(cgroupPermissions string) bool { + r := false + w := false + m := false + for _, rn := range cgroupPermissions { + switch rn { + case 'r': + r = true + case 'w': + w = true + case 'm': + m = true + } + } + return r && w && m +} + +// the logic is from runc +// https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/fs/devices_v2.go#L44 +func canSkipEBPFError(devices []specs.LinuxDeviceCgroup) bool { + for _, dev := range devices { + if dev.Allow || !isRWM(dev.Access) { + return false + } + } + return true +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/errors.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/errors.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "errors" + "os" +) + +var ( + ErrInvalidPid = errors.New("cgroups: pid must be greater than 0") + ErrMountPointNotExist = errors.New("cgroups: cgroup mountpoint does not exist") + ErrInvalidFormat = errors.New("cgroups: parsing file with invalid format failed") + ErrFreezerNotSupported = errors.New("cgroups: freezer cgroup (v2) not supported on this system") + ErrMemoryNotSupported = errors.New("cgroups: memory cgroup (v2) not supported on this system") + ErrPidsNotSupported = errors.New("cgroups: pids cgroup (v2) not supported on this system") + ErrCPUNotSupported = errors.New("cgroups: cpu cgroup (v2) not supported on this system") + ErrCgroupDeleted = errors.New("cgroups: cgroup deleted") + ErrNoCgroupMountDestination = errors.New("cgroups: cannot find cgroup mount destination") + ErrInvalidGroupPath = errors.New("cgroups: invalid group path") +) + +// ErrorHandler is a function that handles and acts on errors +type ErrorHandler func(err error) error + +// IgnoreNotExist ignores any errors that are for not existing files +func IgnoreNotExist(err error) error { + if os.IsNotExist(err) { + return nil + } + return err +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/hugetlb.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/hugetlb.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/hugetlb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/hugetlb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import "strings" + +type HugeTlb []HugeTlbEntry + +type HugeTlbEntry struct { + HugePageSize string + Limit uint64 +} + +func (r *HugeTlb) Values() (o []Value) { + for _, e := range *r { + o = append(o, Value{ + filename: strings.Join([]string{"hugetlb", e.HugePageSize, "max"}, "."), + value: e.Limit, + }) + } + + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/io.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/io.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/io.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/io.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,64 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import "fmt" + +type IOType string + +const ( + ReadBPS IOType = "rbps" + WriteBPS IOType = "wbps" + ReadIOPS IOType = "riops" + WriteIOPS IOType = "wiops" +) + +type BFQ struct { + Weight uint16 +} + +type Entry struct { + Type IOType + Major int64 + Minor int64 + Rate uint64 +} + +func (e Entry) String() string { + return fmt.Sprintf("%d:%d %s=%d", e.Major, e.Minor, e.Type, e.Rate) +} + +type IO struct { + BFQ BFQ + Max []Entry +} + +func (i *IO) Values() (o []Value) { + if i.BFQ.Weight != 0 { + o = append(o, Value{ + filename: "io.bfq.weight", + value: i.BFQ.Weight, + }) + } + for _, e := range i.Max { + o = append(o, Value{ + filename: "io.max", + value: e.String(), + }) + } + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/manager.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/manager.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/manager.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/manager.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,782 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "bufio" + "io/ioutil" + "math" + "os" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + "github.com/containerd/cgroups/v2/stats" + systemdDbus "github.com/coreos/go-systemd/v22/dbus" + "github.com/godbus/dbus/v5" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +const ( + subtreeControl = "cgroup.subtree_control" + controllersFile = "cgroup.controllers" + defaultCgroup2Path = "/sys/fs/cgroup" + defaultSlice = "system.slice" +) + +var ( + canDelegate bool +) + +type Event struct { + Low uint64 + High uint64 + Max uint64 + OOM uint64 + OOMKill uint64 +} + +// Resources for a cgroups v2 unified hierarchy +type Resources struct { + CPU *CPU + Memory *Memory + Pids *Pids + IO *IO + RDMA *RDMA + HugeTlb *HugeTlb + // When len(Devices) is zero, devices are not controlled + Devices []specs.LinuxDeviceCgroup +} + +// Values returns the raw filenames and values that +// can be written to the unified hierarchy +func (r *Resources) Values() (o []Value) { + if r.CPU != nil { + o = append(o, r.CPU.Values()...) + } + if r.Memory != nil { + o = append(o, r.Memory.Values()...) + } + if r.Pids != nil { + o = append(o, r.Pids.Values()...) + } + if r.IO != nil { + o = append(o, r.IO.Values()...) + } + if r.RDMA != nil { + o = append(o, r.RDMA.Values()...) + } + if r.HugeTlb != nil { + o = append(o, r.HugeTlb.Values()...) + } + return o +} + +// EnabledControllers returns the list of all not nil resource controllers +func (r *Resources) EnabledControllers() (c []string) { + if r.CPU != nil { + c = append(c, "cpu") + c = append(c, "cpuset") + } + if r.Memory != nil { + c = append(c, "memory") + } + if r.Pids != nil { + c = append(c, "pids") + } + if r.IO != nil { + c = append(c, "io") + } + if r.RDMA != nil { + c = append(c, "rdma") + } + if r.HugeTlb != nil { + c = append(c, "hugetlb") + } + return +} + +// Value of a cgroup setting +type Value struct { + filename string + value interface{} +} + +// write the value to the full, absolute path, of a unified hierarchy +func (c *Value) write(path string, perm os.FileMode) error { + var data []byte + switch t := c.value.(type) { + case uint64: + data = []byte(strconv.FormatUint(t, 10)) + case uint16: + data = []byte(strconv.FormatUint(uint64(t), 10)) + case int64: + data = []byte(strconv.FormatInt(t, 10)) + case []byte: + data = t + case string: + data = []byte(t) + case CPUMax: + data = []byte(t) + default: + return ErrInvalidFormat + } + + // Retry writes on EINTR; see: + // https://github.com/golang/go/issues/38033 + for { + err := ioutil.WriteFile( + filepath.Join(path, c.filename), + data, + perm, + ) + if err == nil { + return nil + } else if !errors.Is(err, syscall.EINTR) { + return err + } + } +} + +func writeValues(path string, values []Value) error { + for _, o := range values { + if err := o.write(path, defaultFilePerm); err != nil { + return err + } + } + return nil +} + +func NewManager(mountpoint string, group string, resources *Resources) (*Manager, error) { + if resources == nil { + return nil, errors.New("resources reference is nil") + } + if err := VerifyGroupPath(group); err != nil { + return nil, err + } + path := filepath.Join(mountpoint, group) + if err := os.MkdirAll(path, defaultDirPerm); err != nil { + return nil, err + } + m := Manager{ + unifiedMountpoint: mountpoint, + path: path, + } + if err := m.ToggleControllers(resources.EnabledControllers(), Enable); err != nil { + // clean up cgroup dir on failure + os.Remove(path) + return nil, err + } + if err := setResources(path, resources); err != nil { + os.Remove(path) + return nil, err + } + return &m, nil +} + +func LoadManager(mountpoint string, group string) (*Manager, error) { + if err := VerifyGroupPath(group); err != nil { + return nil, err + } + path := filepath.Join(mountpoint, group) + return &Manager{ + unifiedMountpoint: mountpoint, + path: path, + }, nil +} + +type Manager struct { + unifiedMountpoint string + path string +} + +func setResources(path string, resources *Resources) error { + if resources != nil { + if err := writeValues(path, resources.Values()); err != nil { + return err + } + if err := setDevices(path, resources.Devices); err != nil { + return err + } + } + return nil +} + +func (c *Manager) RootControllers() ([]string, error) { + b, err := ioutil.ReadFile(filepath.Join(c.unifiedMountpoint, controllersFile)) + if err != nil { + return nil, err + } + return strings.Fields(string(b)), nil +} + +func (c *Manager) Controllers() ([]string, error) { + b, err := ioutil.ReadFile(filepath.Join(c.path, controllersFile)) + if err != nil { + return nil, err + } + return strings.Fields(string(b)), nil +} + +type ControllerToggle int + +const ( + Enable ControllerToggle = iota + 1 + Disable +) + +func toggleFunc(controllers []string, prefix string) []string { + out := make([]string, len(controllers)) + for i, c := range controllers { + out[i] = prefix + c + } + return out +} + +func (c *Manager) ToggleControllers(controllers []string, t ControllerToggle) error { + // when c.path is like /foo/bar/baz, the following files need to be written: + // * /sys/fs/cgroup/cgroup.subtree_control + // * /sys/fs/cgroup/foo/cgroup.subtree_control + // * /sys/fs/cgroup/foo/bar/cgroup.subtree_control + // Note that /sys/fs/cgroup/foo/bar/baz/cgroup.subtree_control does not need to be written. + split := strings.Split(c.path, "/") + var lastErr error + for i := range split { + f := strings.Join(split[:i], "/") + if !strings.HasPrefix(f, c.unifiedMountpoint) || f == c.path { + continue + } + filePath := filepath.Join(f, subtreeControl) + if err := c.writeSubtreeControl(filePath, controllers, t); err != nil { + // When running as rootless, the user may face EPERM on parent groups, but it is neglible when the + // controller is already written. + // So we only return the last error. + lastErr = errors.Wrapf(err, "failed to write subtree controllers %+v to %q", controllers, filePath) + } + } + return lastErr +} + +func (c *Manager) writeSubtreeControl(filePath string, controllers []string, t ControllerToggle) error { + f, err := os.OpenFile(filePath, os.O_WRONLY, 0) + if err != nil { + return err + } + defer f.Close() + switch t { + case Enable: + controllers = toggleFunc(controllers, "+") + case Disable: + controllers = toggleFunc(controllers, "-") + } + _, err = f.WriteString(strings.Join(controllers, " ")) + return err +} + +func (c *Manager) NewChild(name string, resources *Resources) (*Manager, error) { + if strings.HasPrefix(name, "/") { + return nil, errors.New("name must be relative") + } + path := filepath.Join(c.path, name) + if err := os.MkdirAll(path, defaultDirPerm); err != nil { + return nil, err + } + if err := setResources(path, resources); err != nil { + // clean up cgroup dir on failure + os.Remove(path) + return nil, err + } + return &Manager{ + unifiedMountpoint: c.unifiedMountpoint, + path: path, + }, nil +} + +func (c *Manager) AddProc(pid uint64) error { + v := Value{ + filename: cgroupProcs, + value: pid, + } + return writeValues(c.path, []Value{v}) +} + +func (c *Manager) Delete() error { + return remove(c.path) +} + +func (c *Manager) Procs(recursive bool) ([]uint64, error) { + var processes []uint64 + err := filepath.Walk(c.path, func(p string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !recursive && info.IsDir() { + if p == c.path { + return nil + } + return filepath.SkipDir + } + _, name := filepath.Split(p) + if name != cgroupProcs { + return nil + } + procs, err := parseCgroupProcsFile(p) + if err != nil { + return err + } + processes = append(processes, procs...) + return nil + }) + return processes, err +} + +var singleValueFiles = []string{ + "pids.current", + "pids.max", +} + +func (c *Manager) Stat() (*stats.Metrics, error) { + controllers, err := c.Controllers() + if err != nil { + return nil, err + } + out := make(map[string]interface{}) + for _, controller := range controllers { + switch controller { + case "cpu", "memory": + if err := readKVStatsFile(c.path, controller+".stat", out); err != nil { + if os.IsNotExist(err) { + continue + } + return nil, err + } + } + } + for _, name := range singleValueFiles { + if err := readSingleFile(c.path, name, out); err != nil { + if os.IsNotExist(err) { + continue + } + return nil, err + } + } + memoryEvents := make(map[string]interface{}) + if err := readKVStatsFile(c.path, "memory.events", memoryEvents); err != nil { + if !os.IsNotExist(err) { + return nil, err + } + } + var metrics stats.Metrics + + metrics.Pids = &stats.PidsStat{ + Current: getPidValue("pids.current", out), + Limit: getPidValue("pids.max", out), + } + metrics.CPU = &stats.CPUStat{ + UsageUsec: getUint64Value("usage_usec", out), + UserUsec: getUint64Value("user_usec", out), + SystemUsec: getUint64Value("system_usec", out), + NrPeriods: getUint64Value("nr_periods", out), + NrThrottled: getUint64Value("nr_throttled", out), + ThrottledUsec: getUint64Value("throttled_usec", out), + } + metrics.Memory = &stats.MemoryStat{ + Anon: getUint64Value("anon", out), + File: getUint64Value("file", out), + KernelStack: getUint64Value("kernel_stack", out), + Slab: getUint64Value("slab", out), + Sock: getUint64Value("sock", out), + Shmem: getUint64Value("shmem", out), + FileMapped: getUint64Value("file_mapped", out), + FileDirty: getUint64Value("file_dirty", out), + FileWriteback: getUint64Value("file_writeback", out), + AnonThp: getUint64Value("anon_thp", out), + InactiveAnon: getUint64Value("inactive_anon", out), + ActiveAnon: getUint64Value("active_anon", out), + InactiveFile: getUint64Value("inactive_file", out), + ActiveFile: getUint64Value("active_file", out), + Unevictable: getUint64Value("unevictable", out), + SlabReclaimable: getUint64Value("slab_reclaimable", out), + SlabUnreclaimable: getUint64Value("slab_unreclaimable", out), + Pgfault: getUint64Value("pgfault", out), + Pgmajfault: getUint64Value("pgmajfault", out), + WorkingsetRefault: getUint64Value("workingset_refault", out), + WorkingsetActivate: getUint64Value("workingset_activate", out), + WorkingsetNodereclaim: getUint64Value("workingset_nodereclaim", out), + Pgrefill: getUint64Value("pgrefill", out), + Pgscan: getUint64Value("pgscan", out), + Pgsteal: getUint64Value("pgsteal", out), + Pgactivate: getUint64Value("pgactivate", out), + Pgdeactivate: getUint64Value("pgdeactivate", out), + Pglazyfree: getUint64Value("pglazyfree", out), + Pglazyfreed: getUint64Value("pglazyfreed", out), + ThpFaultAlloc: getUint64Value("thp_fault_alloc", out), + ThpCollapseAlloc: getUint64Value("thp_collapse_alloc", out), + Usage: getStatFileContentUint64(filepath.Join(c.path, "memory.current")), + UsageLimit: getStatFileContentUint64(filepath.Join(c.path, "memory.max")), + SwapUsage: getStatFileContentUint64(filepath.Join(c.path, "memory.swap.current")), + SwapLimit: getStatFileContentUint64(filepath.Join(c.path, "memory.swap.max")), + } + if len(memoryEvents) > 0 { + metrics.MemoryEvents = &stats.MemoryEvents{ + Low: getUint64Value("low", memoryEvents), + High: getUint64Value("high", memoryEvents), + Max: getUint64Value("max", memoryEvents), + Oom: getUint64Value("oom", memoryEvents), + OomKill: getUint64Value("oom_kill", memoryEvents), + } + } + metrics.Io = &stats.IOStat{Usage: readIoStats(c.path)} + metrics.Rdma = &stats.RdmaStat{ + Current: rdmaStats(filepath.Join(c.path, "rdma.current")), + Limit: rdmaStats(filepath.Join(c.path, "rdma.max")), + } + metrics.Hugetlb = readHugeTlbStats(c.path) + + return &metrics, nil +} + +func getUint64Value(key string, out map[string]interface{}) uint64 { + v, ok := out[key] + if !ok { + return 0 + } + switch t := v.(type) { + case uint64: + return t + } + return 0 +} + +func getPidValue(key string, out map[string]interface{}) uint64 { + v, ok := out[key] + if !ok { + return 0 + } + switch t := v.(type) { + case uint64: + return t + case string: + if t == "max" { + return math.MaxUint64 + } + } + return 0 +} + +func readSingleFile(path string, file string, out map[string]interface{}) error { + f, err := os.Open(filepath.Join(path, file)) + if err != nil { + return err + } + defer f.Close() + data, err := ioutil.ReadAll(f) + if err != nil { + return err + } + s := strings.TrimSpace(string(data)) + v, err := parseUint(s, 10, 64) + if err != nil { + // if we cannot parse as a uint, parse as a string + out[file] = s + return nil + } + out[file] = v + return nil +} + +func readKVStatsFile(path string, file string, out map[string]interface{}) error { + f, err := os.Open(filepath.Join(path, file)) + if err != nil { + return err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + name, value, err := parseKV(s.Text()) + if err != nil { + return errors.Wrapf(err, "error while parsing %s (line=%q)", filepath.Join(path, file), s.Text()) + } + out[name] = value + } + return s.Err() +} + +func (c *Manager) Freeze() error { + return c.freeze(c.path, Frozen) +} + +func (c *Manager) Thaw() error { + return c.freeze(c.path, Thawed) +} + +func (c *Manager) freeze(path string, state State) error { + values := state.Values() + for { + if err := writeValues(path, values); err != nil { + return err + } + current, err := fetchState(path) + if err != nil { + return err + } + if current == state { + return nil + } + time.Sleep(1 * time.Millisecond) + } +} + +// MemoryEventFD returns inotify file descriptor and 'memory.events' inotify watch descriptor +func (c *Manager) MemoryEventFD() (int, uint32, error) { + fpath := filepath.Join(c.path, "memory.events") + fd, err := syscall.InotifyInit() + if err != nil { + return 0, 0, errors.Errorf("Failed to create inotify fd") + } + wd, err := syscall.InotifyAddWatch(fd, fpath, unix.IN_MODIFY) + if wd < 0 { + syscall.Close(fd) + return 0, 0, errors.Errorf("Failed to add inotify watch for %q", fpath) + } + + return fd, uint32(wd), nil +} + +func (c *Manager) EventChan() (<-chan Event, <-chan error) { + ec := make(chan Event) + errCh := make(chan error) + go c.waitForEvents(ec, errCh) + + return ec, nil +} + +func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) { + fd, wd, err := c.MemoryEventFD() + + defer syscall.InotifyRmWatch(fd, wd) + defer syscall.Close(fd) + + if err != nil { + errCh <- err + return + } + + for { + buffer := make([]byte, syscall.SizeofInotifyEvent*10) + bytesRead, err := syscall.Read(fd, buffer) + if err != nil { + errCh <- err + return + } + if bytesRead >= syscall.SizeofInotifyEvent { + out := make(map[string]interface{}) + if err := readKVStatsFile(c.path, "memory.events", out); err == nil { + e := Event{} + if v, ok := out["high"]; ok { + e.High, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert high to uint64: %+v", v) + return + } + } + if v, ok := out["low"]; ok { + e.Low, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert low to uint64: %+v", v) + return + } + } + if v, ok := out["max"]; ok { + e.Max, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert max to uint64: %+v", v) + return + } + } + if v, ok := out["oom"]; ok { + e.OOM, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert oom to uint64: %+v", v) + return + } + } + if v, ok := out["oom_kill"]; ok { + e.OOMKill, ok = v.(uint64) + if !ok { + errCh <- errors.Errorf("cannot convert oom_kill to uint64: %+v", v) + return + } + } + ec <- e + } else { + errCh <- err + return + } + } + } +} + +func setDevices(path string, devices []specs.LinuxDeviceCgroup) error { + if len(devices) == 0 { + return nil + } + insts, license, err := DeviceFilter(devices) + if err != nil { + return err + } + dirFD, err := unix.Open(path, unix.O_DIRECTORY|unix.O_RDONLY, 0600) + if err != nil { + return errors.Errorf("cannot get dir FD for %s", path) + } + defer unix.Close(dirFD) + if _, err := LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil { + if !canSkipEBPFError(devices) { + return err + } + } + return nil +} + +func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, error) { + if slice == "" { + slice = defaultSlice + } + path := filepath.Join(defaultCgroup2Path, slice, group) + conn, err := systemdDbus.New() + if err != nil { + return &Manager{}, err + } + defer conn.Close() + + properties := []systemdDbus.Property{ + systemdDbus.PropDescription("cgroup " + group), + newSystemdProperty("DefaultDependencies", false), + newSystemdProperty("MemoryAccounting", true), + newSystemdProperty("CPUAccounting", true), + newSystemdProperty("IOAccounting", true), + } + + // if we create a slice, the parent is defined via a Wants= + if strings.HasSuffix(group, ".slice") { + properties = append(properties, systemdDbus.PropWants(defaultSlice)) + } else { + // otherwise, we use Slice= + properties = append(properties, systemdDbus.PropSlice(defaultSlice)) + } + + // only add pid if its valid, -1 is used w/ general slice creation. + if pid != -1 { + properties = append(properties, newSystemdProperty("PIDs", []uint32{uint32(pid)})) + } + + if resources.Memory != nil && *resources.Memory.Max != 0 { + properties = append(properties, + newSystemdProperty("MemoryMax", uint64(*resources.Memory.Max))) + } + + if resources.CPU != nil && *resources.CPU.Weight != 0 { + properties = append(properties, + newSystemdProperty("CPUWeight", *resources.CPU.Weight)) + } + + if resources.CPU != nil && resources.CPU.Max != "" { + quota, period := resources.CPU.Max.extractQuotaAndPeriod() + // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd. + // corresponds to USEC_INFINITY in systemd + // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd + // always setting a property value ensures we can apply a quota and remove it later + cpuQuotaPerSecUSec := uint64(math.MaxUint64) + if quota > 0 { + // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota + // (integer percentage of CPU) internally. This means that if a fractional percent of + // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest + // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect. + cpuQuotaPerSecUSec = uint64(quota*1000000) / period + if cpuQuotaPerSecUSec%10000 != 0 { + cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000 + } + } + properties = append(properties, + newSystemdProperty("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec)) + } + + // If we can delegate, we add the property back in + if canDelegate { + properties = append(properties, newSystemdProperty("Delegate", true)) + } + + if resources.Pids != nil && resources.Pids.Max > 0 { + properties = append(properties, + newSystemdProperty("TasksAccounting", true), + newSystemdProperty("TasksMax", uint64(resources.Pids.Max))) + } + + statusChan := make(chan string, 1) + if _, err := conn.StartTransientUnit(group, "replace", properties, statusChan); err == nil { + select { + case <-statusChan: + case <-time.After(time.Second): + logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", group) + } + } else if !isUnitExists(err) { + return &Manager{}, err + } + + return &Manager{ + path: path, + }, nil +} + +func LoadSystemd(slice, group string) (*Manager, error) { + if slice == "" { + slice = defaultSlice + } + group = filepath.Join(defaultCgroup2Path, slice, group) + return &Manager{ + path: group, + }, nil +} + +func (c *Manager) DeleteSystemd() error { + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + group := systemdUnitFromPath(c.path) + ch := make(chan string) + _, err = conn.StopUnit(group, "replace", ch) + if err != nil { + return err + } + <-ch + return nil +} + +func newSystemdProperty(name string, units interface{}) systemdDbus.Property { + return systemdDbus.Property{ + Name: name, + Value: dbus.MakeVariant(units), + } +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/memory.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/memory.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/memory.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/memory.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +type Memory struct { + Swap *int64 + Max *int64 + Low *int64 + High *int64 +} + +func (r *Memory) Values() (o []Value) { + if r.Swap != nil { + o = append(o, Value{ + filename: "memory.swap.max", + value: *r.Swap, + }) + } + if r.Max != nil { + o = append(o, Value{ + filename: "memory.max", + value: *r.Max, + }) + } + if r.Low != nil { + o = append(o, Value{ + filename: "memory.low", + value: *r.Low, + }) + } + if r.High != nil { + o = append(o, Value{ + filename: "memory.high", + value: *r.High, + }) + } + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/paths.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/paths.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/paths.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/paths.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,60 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "fmt" + "path/filepath" + "strings" +) + +// NestedGroupPath will nest the cgroups based on the calling processes cgroup +// placing its child processes inside its own path +func NestedGroupPath(suffix string) (string, error) { + path, err := parseCgroupFile("/proc/self/cgroup") + if err != nil { + return "", err + } + return filepath.Join(path, suffix), nil +} + +// PidGroupPath will return the correct cgroup paths for an existing process running inside a cgroup +// This is commonly used for the Load function to restore an existing container +func PidGroupPath(pid int) (string, error) { + p := fmt.Sprintf("/proc/%d/cgroup", pid) + return parseCgroupFile(p) +} + +// VerifyGroupPath verifies the format of group path string g. +// The format is same as the third field in /proc/PID/cgroup. +// e.g. "/user.slice/user-1001.slice/session-1.scope" +// +// g must be a "clean" absolute path starts with "/", and must not contain "/sys/fs/cgroup" prefix. +// +// VerifyGroupPath doesn't verify whether g actually exists on the system. +func VerifyGroupPath(g string) error { + if !strings.HasPrefix(g, "/") { + return ErrInvalidGroupPath + } + if filepath.Clean(g) != g { + return ErrInvalidGroupPath + } + if strings.HasPrefix(g, "/sys/fs/cgroup") { + return ErrInvalidGroupPath + } + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/pids.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/pids.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/pids.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/pids.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import "strconv" + +type Pids struct { + Max int64 +} + +func (r *Pids) Values() (o []Value) { + if r.Max != 0 { + limit := "max" + if r.Max > 0 { + limit = strconv.FormatInt(r.Max, 10) + } + o = append(o, Value{ + filename: "pids.max", + value: limit, + }) + } + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/rdma.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/rdma.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/rdma.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/rdma.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "fmt" +) + +type RDMA struct { + Limit []RDMAEntry +} + +type RDMAEntry struct { + Device string + HcaHandles uint32 + HcaObjects uint32 +} + +func (r RDMAEntry) String() string { + return fmt.Sprintf("%s hca_handle=%d hca_object=%d", r.Device, r.HcaHandles, r.HcaObjects) +} + +func (r *RDMA) Values() (o []Value) { + for _, e := range r.Limit { + o = append(o, Value{ + filename: "rdma.max", + value: e.String(), + }) + } + + return o +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/state.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/state.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/state.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/state.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,65 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "io/ioutil" + "path/filepath" + "strings" +) + +// State is a type that represents the state of the current cgroup +type State string + +const ( + Unknown State = "" + Thawed State = "thawed" + Frozen State = "frozen" + Deleted State = "deleted" + + cgroupFreeze = "cgroup.freeze" +) + +func (s State) Values() []Value { + v := Value{ + filename: cgroupFreeze, + } + switch s { + case Frozen: + v.value = "1" + case Thawed: + v.value = "0" + } + return []Value{ + v, + } +} + +func fetchState(path string) (State, error) { + current, err := ioutil.ReadFile(filepath.Join(path, cgroupFreeze)) + if err != nil { + return Unknown, err + } + switch strings.TrimSpace(string(current)) { + case "1": + return Frozen, nil + case "0": + return Thawed, nil + default: + return Unknown, nil + } +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/doc.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/doc.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package stats diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,3992 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/containerd/cgroups/v2/stats/metrics.proto + +package stats + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// 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.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Metrics struct { + Pids *PidsStat `protobuf:"bytes,1,opt,name=pids,proto3" json:"pids,omitempty"` + CPU *CPUStat `protobuf:"bytes,2,opt,name=cpu,proto3" json:"cpu,omitempty"` + Memory *MemoryStat `protobuf:"bytes,4,opt,name=memory,proto3" json:"memory,omitempty"` + Rdma *RdmaStat `protobuf:"bytes,5,opt,name=rdma,proto3" json:"rdma,omitempty"` + Io *IOStat `protobuf:"bytes,6,opt,name=io,proto3" json:"io,omitempty"` + Hugetlb []*HugeTlbStat `protobuf:"bytes,7,rep,name=hugetlb,proto3" json:"hugetlb,omitempty"` + MemoryEvents *MemoryEvents `protobuf:"bytes,8,opt,name=memory_events,json=memoryEvents,proto3" json:"memory_events,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Metrics) Reset() { *m = Metrics{} } +func (*Metrics) ProtoMessage() {} +func (*Metrics) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{0} +} +func (m *Metrics) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Metrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Metrics.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Metrics) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metrics.Merge(m, src) +} +func (m *Metrics) XXX_Size() int { + return m.Size() +} +func (m *Metrics) XXX_DiscardUnknown() { + xxx_messageInfo_Metrics.DiscardUnknown(m) +} + +var xxx_messageInfo_Metrics proto.InternalMessageInfo + +type PidsStat struct { + Current uint64 `protobuf:"varint,1,opt,name=current,proto3" json:"current,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PidsStat) Reset() { *m = PidsStat{} } +func (*PidsStat) ProtoMessage() {} +func (*PidsStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{1} +} +func (m *PidsStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PidsStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PidsStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PidsStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_PidsStat.Merge(m, src) +} +func (m *PidsStat) XXX_Size() int { + return m.Size() +} +func (m *PidsStat) XXX_DiscardUnknown() { + xxx_messageInfo_PidsStat.DiscardUnknown(m) +} + +var xxx_messageInfo_PidsStat proto.InternalMessageInfo + +type CPUStat struct { + UsageUsec uint64 `protobuf:"varint,1,opt,name=usage_usec,json=usageUsec,proto3" json:"usage_usec,omitempty"` + UserUsec uint64 `protobuf:"varint,2,opt,name=user_usec,json=userUsec,proto3" json:"user_usec,omitempty"` + SystemUsec uint64 `protobuf:"varint,3,opt,name=system_usec,json=systemUsec,proto3" json:"system_usec,omitempty"` + NrPeriods uint64 `protobuf:"varint,4,opt,name=nr_periods,json=nrPeriods,proto3" json:"nr_periods,omitempty"` + NrThrottled uint64 `protobuf:"varint,5,opt,name=nr_throttled,json=nrThrottled,proto3" json:"nr_throttled,omitempty"` + ThrottledUsec uint64 `protobuf:"varint,6,opt,name=throttled_usec,json=throttledUsec,proto3" json:"throttled_usec,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CPUStat) Reset() { *m = CPUStat{} } +func (*CPUStat) ProtoMessage() {} +func (*CPUStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{2} +} +func (m *CPUStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CPUStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CPUStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CPUStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_CPUStat.Merge(m, src) +} +func (m *CPUStat) XXX_Size() int { + return m.Size() +} +func (m *CPUStat) XXX_DiscardUnknown() { + xxx_messageInfo_CPUStat.DiscardUnknown(m) +} + +var xxx_messageInfo_CPUStat proto.InternalMessageInfo + +type MemoryStat struct { + Anon uint64 `protobuf:"varint,1,opt,name=anon,proto3" json:"anon,omitempty"` + File uint64 `protobuf:"varint,2,opt,name=file,proto3" json:"file,omitempty"` + KernelStack uint64 `protobuf:"varint,3,opt,name=kernel_stack,json=kernelStack,proto3" json:"kernel_stack,omitempty"` + Slab uint64 `protobuf:"varint,4,opt,name=slab,proto3" json:"slab,omitempty"` + Sock uint64 `protobuf:"varint,5,opt,name=sock,proto3" json:"sock,omitempty"` + Shmem uint64 `protobuf:"varint,6,opt,name=shmem,proto3" json:"shmem,omitempty"` + FileMapped uint64 `protobuf:"varint,7,opt,name=file_mapped,json=fileMapped,proto3" json:"file_mapped,omitempty"` + FileDirty uint64 `protobuf:"varint,8,opt,name=file_dirty,json=fileDirty,proto3" json:"file_dirty,omitempty"` + FileWriteback uint64 `protobuf:"varint,9,opt,name=file_writeback,json=fileWriteback,proto3" json:"file_writeback,omitempty"` + AnonThp uint64 `protobuf:"varint,10,opt,name=anon_thp,json=anonThp,proto3" json:"anon_thp,omitempty"` + InactiveAnon uint64 `protobuf:"varint,11,opt,name=inactive_anon,json=inactiveAnon,proto3" json:"inactive_anon,omitempty"` + ActiveAnon uint64 `protobuf:"varint,12,opt,name=active_anon,json=activeAnon,proto3" json:"active_anon,omitempty"` + InactiveFile uint64 `protobuf:"varint,13,opt,name=inactive_file,json=inactiveFile,proto3" json:"inactive_file,omitempty"` + ActiveFile uint64 `protobuf:"varint,14,opt,name=active_file,json=activeFile,proto3" json:"active_file,omitempty"` + Unevictable uint64 `protobuf:"varint,15,opt,name=unevictable,proto3" json:"unevictable,omitempty"` + SlabReclaimable uint64 `protobuf:"varint,16,opt,name=slab_reclaimable,json=slabReclaimable,proto3" json:"slab_reclaimable,omitempty"` + SlabUnreclaimable uint64 `protobuf:"varint,17,opt,name=slab_unreclaimable,json=slabUnreclaimable,proto3" json:"slab_unreclaimable,omitempty"` + Pgfault uint64 `protobuf:"varint,18,opt,name=pgfault,proto3" json:"pgfault,omitempty"` + Pgmajfault uint64 `protobuf:"varint,19,opt,name=pgmajfault,proto3" json:"pgmajfault,omitempty"` + WorkingsetRefault uint64 `protobuf:"varint,20,opt,name=workingset_refault,json=workingsetRefault,proto3" json:"workingset_refault,omitempty"` + WorkingsetActivate uint64 `protobuf:"varint,21,opt,name=workingset_activate,json=workingsetActivate,proto3" json:"workingset_activate,omitempty"` + WorkingsetNodereclaim uint64 `protobuf:"varint,22,opt,name=workingset_nodereclaim,json=workingsetNodereclaim,proto3" json:"workingset_nodereclaim,omitempty"` + Pgrefill uint64 `protobuf:"varint,23,opt,name=pgrefill,proto3" json:"pgrefill,omitempty"` + Pgscan uint64 `protobuf:"varint,24,opt,name=pgscan,proto3" json:"pgscan,omitempty"` + Pgsteal uint64 `protobuf:"varint,25,opt,name=pgsteal,proto3" json:"pgsteal,omitempty"` + Pgactivate uint64 `protobuf:"varint,26,opt,name=pgactivate,proto3" json:"pgactivate,omitempty"` + Pgdeactivate uint64 `protobuf:"varint,27,opt,name=pgdeactivate,proto3" json:"pgdeactivate,omitempty"` + Pglazyfree uint64 `protobuf:"varint,28,opt,name=pglazyfree,proto3" json:"pglazyfree,omitempty"` + Pglazyfreed uint64 `protobuf:"varint,29,opt,name=pglazyfreed,proto3" json:"pglazyfreed,omitempty"` + ThpFaultAlloc uint64 `protobuf:"varint,30,opt,name=thp_fault_alloc,json=thpFaultAlloc,proto3" json:"thp_fault_alloc,omitempty"` + ThpCollapseAlloc uint64 `protobuf:"varint,31,opt,name=thp_collapse_alloc,json=thpCollapseAlloc,proto3" json:"thp_collapse_alloc,omitempty"` + Usage uint64 `protobuf:"varint,32,opt,name=usage,proto3" json:"usage,omitempty"` + UsageLimit uint64 `protobuf:"varint,33,opt,name=usage_limit,json=usageLimit,proto3" json:"usage_limit,omitempty"` + SwapUsage uint64 `protobuf:"varint,34,opt,name=swap_usage,json=swapUsage,proto3" json:"swap_usage,omitempty"` + SwapLimit uint64 `protobuf:"varint,35,opt,name=swap_limit,json=swapLimit,proto3" json:"swap_limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryStat) Reset() { *m = MemoryStat{} } +func (*MemoryStat) ProtoMessage() {} +func (*MemoryStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{3} +} +func (m *MemoryStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryStat.Merge(m, src) +} +func (m *MemoryStat) XXX_Size() int { + return m.Size() +} +func (m *MemoryStat) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryStat.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryStat proto.InternalMessageInfo + +type MemoryEvents struct { + Low uint64 `protobuf:"varint,1,opt,name=low,proto3" json:"low,omitempty"` + High uint64 `protobuf:"varint,2,opt,name=high,proto3" json:"high,omitempty"` + Max uint64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` + Oom uint64 `protobuf:"varint,4,opt,name=oom,proto3" json:"oom,omitempty"` + OomKill uint64 `protobuf:"varint,5,opt,name=oom_kill,json=oomKill,proto3" json:"oom_kill,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MemoryEvents) Reset() { *m = MemoryEvents{} } +func (*MemoryEvents) ProtoMessage() {} +func (*MemoryEvents) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{4} +} +func (m *MemoryEvents) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MemoryEvents) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MemoryEvents.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MemoryEvents) XXX_Merge(src proto.Message) { + xxx_messageInfo_MemoryEvents.Merge(m, src) +} +func (m *MemoryEvents) XXX_Size() int { + return m.Size() +} +func (m *MemoryEvents) XXX_DiscardUnknown() { + xxx_messageInfo_MemoryEvents.DiscardUnknown(m) +} + +var xxx_messageInfo_MemoryEvents proto.InternalMessageInfo + +type RdmaStat struct { + Current []*RdmaEntry `protobuf:"bytes,1,rep,name=current,proto3" json:"current,omitempty"` + Limit []*RdmaEntry `protobuf:"bytes,2,rep,name=limit,proto3" json:"limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RdmaStat) Reset() { *m = RdmaStat{} } +func (*RdmaStat) ProtoMessage() {} +func (*RdmaStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{5} +} +func (m *RdmaStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RdmaStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RdmaStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RdmaStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_RdmaStat.Merge(m, src) +} +func (m *RdmaStat) XXX_Size() int { + return m.Size() +} +func (m *RdmaStat) XXX_DiscardUnknown() { + xxx_messageInfo_RdmaStat.DiscardUnknown(m) +} + +var xxx_messageInfo_RdmaStat proto.InternalMessageInfo + +type RdmaEntry struct { + Device string `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` + HcaHandles uint32 `protobuf:"varint,2,opt,name=hca_handles,json=hcaHandles,proto3" json:"hca_handles,omitempty"` + HcaObjects uint32 `protobuf:"varint,3,opt,name=hca_objects,json=hcaObjects,proto3" json:"hca_objects,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RdmaEntry) Reset() { *m = RdmaEntry{} } +func (*RdmaEntry) ProtoMessage() {} +func (*RdmaEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{6} +} +func (m *RdmaEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RdmaEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RdmaEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RdmaEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_RdmaEntry.Merge(m, src) +} +func (m *RdmaEntry) XXX_Size() int { + return m.Size() +} +func (m *RdmaEntry) XXX_DiscardUnknown() { + xxx_messageInfo_RdmaEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_RdmaEntry proto.InternalMessageInfo + +type IOStat struct { + Usage []*IOEntry `protobuf:"bytes,1,rep,name=usage,proto3" json:"usage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IOStat) Reset() { *m = IOStat{} } +func (*IOStat) ProtoMessage() {} +func (*IOStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{7} +} +func (m *IOStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IOStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IOStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IOStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_IOStat.Merge(m, src) +} +func (m *IOStat) XXX_Size() int { + return m.Size() +} +func (m *IOStat) XXX_DiscardUnknown() { + xxx_messageInfo_IOStat.DiscardUnknown(m) +} + +var xxx_messageInfo_IOStat proto.InternalMessageInfo + +type IOEntry struct { + Major uint64 `protobuf:"varint,1,opt,name=major,proto3" json:"major,omitempty"` + Minor uint64 `protobuf:"varint,2,opt,name=minor,proto3" json:"minor,omitempty"` + Rbytes uint64 `protobuf:"varint,3,opt,name=rbytes,proto3" json:"rbytes,omitempty"` + Wbytes uint64 `protobuf:"varint,4,opt,name=wbytes,proto3" json:"wbytes,omitempty"` + Rios uint64 `protobuf:"varint,5,opt,name=rios,proto3" json:"rios,omitempty"` + Wios uint64 `protobuf:"varint,6,opt,name=wios,proto3" json:"wios,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IOEntry) Reset() { *m = IOEntry{} } +func (*IOEntry) ProtoMessage() {} +func (*IOEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{8} +} +func (m *IOEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IOEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IOEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IOEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_IOEntry.Merge(m, src) +} +func (m *IOEntry) XXX_Size() int { + return m.Size() +} +func (m *IOEntry) XXX_DiscardUnknown() { + xxx_messageInfo_IOEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_IOEntry proto.InternalMessageInfo + +type HugeTlbStat struct { + Current uint64 `protobuf:"varint,1,opt,name=current,proto3" json:"current,omitempty"` + Max uint64 `protobuf:"varint,2,opt,name=max,proto3" json:"max,omitempty"` + Pagesize string `protobuf:"bytes,3,opt,name=pagesize,proto3" json:"pagesize,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HugeTlbStat) Reset() { *m = HugeTlbStat{} } +func (*HugeTlbStat) ProtoMessage() {} +func (*HugeTlbStat) Descriptor() ([]byte, []int) { + return fileDescriptor_2fc6005842049e6b, []int{9} +} +func (m *HugeTlbStat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HugeTlbStat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HugeTlbStat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *HugeTlbStat) XXX_Merge(src proto.Message) { + xxx_messageInfo_HugeTlbStat.Merge(m, src) +} +func (m *HugeTlbStat) XXX_Size() int { + return m.Size() +} +func (m *HugeTlbStat) XXX_DiscardUnknown() { + xxx_messageInfo_HugeTlbStat.DiscardUnknown(m) +} + +var xxx_messageInfo_HugeTlbStat proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Metrics)(nil), "io.containerd.cgroups.v2.Metrics") + proto.RegisterType((*PidsStat)(nil), "io.containerd.cgroups.v2.PidsStat") + proto.RegisterType((*CPUStat)(nil), "io.containerd.cgroups.v2.CPUStat") + proto.RegisterType((*MemoryStat)(nil), "io.containerd.cgroups.v2.MemoryStat") + proto.RegisterType((*MemoryEvents)(nil), "io.containerd.cgroups.v2.MemoryEvents") + proto.RegisterType((*RdmaStat)(nil), "io.containerd.cgroups.v2.RdmaStat") + proto.RegisterType((*RdmaEntry)(nil), "io.containerd.cgroups.v2.RdmaEntry") + proto.RegisterType((*IOStat)(nil), "io.containerd.cgroups.v2.IOStat") + proto.RegisterType((*IOEntry)(nil), "io.containerd.cgroups.v2.IOEntry") + proto.RegisterType((*HugeTlbStat)(nil), "io.containerd.cgroups.v2.HugeTlbStat") +} + +func init() { + proto.RegisterFile("github.com/containerd/cgroups/v2/stats/metrics.proto", fileDescriptor_2fc6005842049e6b) +} + +var fileDescriptor_2fc6005842049e6b = []byte{ + // 1198 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0x4d, 0x73, 0xd4, 0x46, + 0x13, 0x66, 0xed, 0xc5, 0xeb, 0xed, 0xb5, 0xc1, 0x0c, 0x86, 0x57, 0xc0, 0xcb, 0xda, 0x5e, 0x02, + 0x45, 0xaa, 0x92, 0xdd, 0x94, 0xf3, 0x55, 0x49, 0x91, 0x4a, 0x19, 0x02, 0x45, 0x8a, 0x10, 0x5c, + 0x02, 0x57, 0x8e, 0xaa, 0x59, 0x69, 0x2c, 0x0d, 0x96, 0x34, 0xaa, 0x99, 0x91, 0x1d, 0x73, 0xca, + 0x21, 0xd7, 0x54, 0x7e, 0x4d, 0xfe, 0x03, 0xb7, 0xe4, 0x98, 0x53, 0x2a, 0xf8, 0x97, 0xa4, 0xba, + 0x67, 0x64, 0x29, 0x07, 0x43, 0x6e, 0xd3, 0x4f, 0x3f, 0xdd, 0xea, 0x8f, 0x99, 0x6e, 0xc1, 0x27, + 0xa9, 0xb4, 0x59, 0x3d, 0x9f, 0xc6, 0xaa, 0x98, 0xc5, 0xaa, 0xb4, 0x5c, 0x96, 0x42, 0x27, 0xb3, + 0x38, 0xd5, 0xaa, 0xae, 0xcc, 0xec, 0x70, 0x7b, 0x66, 0x2c, 0xb7, 0x66, 0x56, 0x08, 0xab, 0x65, + 0x6c, 0xa6, 0x95, 0x56, 0x56, 0xb1, 0x40, 0xaa, 0x69, 0xcb, 0x9e, 0x7a, 0xf6, 0xf4, 0x70, 0xfb, + 0xfa, 0x7a, 0xaa, 0x52, 0x45, 0xa4, 0x19, 0x9e, 0x1c, 0x7f, 0xf2, 0xdb, 0x22, 0x0c, 0x9e, 0x3a, + 0x0f, 0xec, 0x33, 0xe8, 0x57, 0x32, 0x31, 0x41, 0x6f, 0xb3, 0x77, 0x77, 0xb4, 0x3d, 0x99, 0x9e, + 0xe5, 0x6a, 0xba, 0x2b, 0x13, 0xf3, 0xdc, 0x72, 0x1b, 0x12, 0x9f, 0xdd, 0x83, 0xc5, 0xb8, 0xaa, + 0x83, 0x05, 0x32, 0xdb, 0x3a, 0xdb, 0xec, 0xc1, 0xee, 0x1e, 0x5a, 0xdd, 0x1f, 0x9c, 0xfc, 0xb5, + 0xb1, 0xf8, 0x60, 0x77, 0x2f, 0x44, 0x33, 0x76, 0x0f, 0x96, 0x0a, 0x51, 0x28, 0x7d, 0x1c, 0xf4, + 0xc9, 0xc1, 0x7b, 0x67, 0x3b, 0x78, 0x4a, 0x3c, 0xfa, 0xb2, 0xb7, 0xc1, 0x98, 0x75, 0x52, 0xf0, + 0xe0, 0xfc, 0xbb, 0x62, 0x0e, 0x93, 0x82, 0xbb, 0x98, 0x91, 0xcf, 0x3e, 0x82, 0x05, 0xa9, 0x82, + 0x25, 0xb2, 0xda, 0x3c, 0xdb, 0xea, 0xdb, 0x67, 0x64, 0xb3, 0x20, 0x15, 0xfb, 0x1a, 0x06, 0x59, + 0x9d, 0x0a, 0x9b, 0xcf, 0x83, 0xc1, 0xe6, 0xe2, 0xdd, 0xd1, 0xf6, 0xed, 0xb3, 0xcd, 0x1e, 0xd7, + 0xa9, 0x78, 0x91, 0xcf, 0xc9, 0xb6, 0xb1, 0x62, 0x4f, 0x60, 0xd5, 0x05, 0x1d, 0x89, 0x43, 0x51, + 0x5a, 0x13, 0x2c, 0xd3, 0xd7, 0xef, 0xbc, 0x2b, 0xdf, 0x87, 0xc4, 0x0e, 0x57, 0x8a, 0x8e, 0x34, + 0xf9, 0x12, 0x96, 0x9b, 0x2e, 0xb0, 0x00, 0x06, 0x71, 0xad, 0xb5, 0x28, 0x2d, 0xb5, 0xae, 0x1f, + 0x36, 0x22, 0x5b, 0x87, 0xf3, 0xb9, 0x2c, 0xa4, 0xa5, 0xde, 0xf4, 0x43, 0x27, 0x4c, 0x7e, 0xef, + 0xc1, 0xc0, 0xf7, 0x82, 0xdd, 0x04, 0xa8, 0x0d, 0x4f, 0x45, 0x54, 0x1b, 0x11, 0x7b, 0xf3, 0x21, + 0x21, 0x7b, 0x46, 0xc4, 0xec, 0x06, 0x0c, 0x6b, 0x23, 0xb4, 0xd3, 0x3a, 0x27, 0xcb, 0x08, 0x90, + 0x72, 0x03, 0x46, 0xe6, 0xd8, 0x58, 0x51, 0x38, 0xf5, 0x22, 0xa9, 0xc1, 0x41, 0x44, 0xb8, 0x09, + 0x50, 0xea, 0xa8, 0x12, 0x5a, 0xaa, 0xc4, 0x50, 0x7b, 0xfb, 0xe1, 0xb0, 0xd4, 0xbb, 0x0e, 0x60, + 0x5b, 0xb0, 0x52, 0xea, 0xc8, 0x66, 0x5a, 0x59, 0x9b, 0x8b, 0x84, 0x7a, 0xd8, 0x0f, 0x47, 0xa5, + 0x7e, 0xd1, 0x40, 0xec, 0x36, 0x5c, 0x38, 0xd5, 0xbb, 0xaf, 0x2c, 0x11, 0x69, 0xf5, 0x14, 0xc5, + 0x0f, 0x4d, 0x7e, 0x1d, 0x02, 0xb4, 0x97, 0x83, 0x31, 0xe8, 0xf3, 0x52, 0x95, 0x3e, 0x1d, 0x3a, + 0x23, 0xb6, 0x2f, 0x73, 0xe1, 0x93, 0xa0, 0x33, 0x06, 0x70, 0x20, 0x74, 0x29, 0xf2, 0xc8, 0x58, + 0x1e, 0x1f, 0xf8, 0x0c, 0x46, 0x0e, 0x7b, 0x8e, 0x10, 0x9a, 0x99, 0x9c, 0xcf, 0x7d, 0xf0, 0x74, + 0x26, 0x4c, 0xc5, 0x07, 0x3e, 0x5e, 0x3a, 0x63, 0xa5, 0x4d, 0x56, 0x88, 0xc2, 0xc7, 0xe7, 0x04, + 0xac, 0x10, 0x7e, 0x28, 0x2a, 0x78, 0x55, 0x89, 0x24, 0x18, 0xb8, 0x0a, 0x21, 0xf4, 0x94, 0x10, + 0xac, 0x10, 0x11, 0x12, 0xa9, 0xed, 0x31, 0x5d, 0x88, 0x7e, 0x38, 0x44, 0xe4, 0x1b, 0x04, 0x30, + 0x7d, 0x52, 0x1f, 0x69, 0x69, 0xc5, 0x1c, 0x43, 0x1c, 0xba, 0xf4, 0x11, 0xfd, 0xa1, 0x01, 0xd9, + 0x35, 0x58, 0xc6, 0x1c, 0x23, 0x9b, 0x55, 0x01, 0xb8, 0x1b, 0x80, 0xf2, 0x8b, 0xac, 0x62, 0xb7, + 0x60, 0x55, 0x96, 0x3c, 0xb6, 0xf2, 0x50, 0x44, 0x54, 0x93, 0x11, 0xe9, 0x57, 0x1a, 0x70, 0x07, + 0x6b, 0xb3, 0x01, 0xa3, 0x2e, 0x65, 0xc5, 0x85, 0xd9, 0x21, 0x74, 0xbd, 0x50, 0x15, 0x57, 0xff, + 0xed, 0xe5, 0x11, 0x56, 0xb3, 0xf5, 0x42, 0x94, 0x0b, 0x5d, 0x2f, 0x44, 0xd8, 0x84, 0x51, 0x5d, + 0x8a, 0x43, 0x19, 0x5b, 0x3e, 0xcf, 0x45, 0x70, 0xd1, 0x55, 0xbb, 0x03, 0xb1, 0xf7, 0x61, 0x0d, + 0x2b, 0x1c, 0x69, 0x11, 0xe7, 0x5c, 0x16, 0x44, 0x5b, 0x23, 0xda, 0x45, 0xc4, 0xc3, 0x16, 0x66, + 0x1f, 0x02, 0x23, 0x6a, 0x5d, 0x76, 0xc9, 0x97, 0x88, 0x7c, 0x09, 0x35, 0x7b, 0x5d, 0x05, 0xbe, + 0x91, 0x2a, 0xdd, 0xe7, 0x75, 0x6e, 0x03, 0xe6, 0x2a, 0xe4, 0x45, 0x36, 0x06, 0xa8, 0xd2, 0x82, + 0xbf, 0x74, 0xca, 0xcb, 0x2e, 0xea, 0x16, 0xc1, 0x0f, 0x1d, 0x29, 0x7d, 0x20, 0xcb, 0xd4, 0x08, + 0x1b, 0x69, 0xe1, 0x78, 0xeb, 0xee, 0x43, 0xad, 0x26, 0x74, 0x0a, 0x36, 0x83, 0xcb, 0x1d, 0x3a, + 0x65, 0xcf, 0xad, 0x08, 0xae, 0x10, 0xbf, 0xe3, 0x69, 0xc7, 0x6b, 0xd8, 0xa7, 0x70, 0xb5, 0x63, + 0x50, 0xaa, 0x44, 0xf8, 0xb8, 0x83, 0xab, 0x64, 0x73, 0xa5, 0xd5, 0x7e, 0xdf, 0x2a, 0xd9, 0x75, + 0x58, 0xae, 0x52, 0x2d, 0xf6, 0x65, 0x9e, 0x07, 0xff, 0x73, 0x0f, 0xb3, 0x91, 0xd9, 0x55, 0x58, + 0xaa, 0x52, 0x13, 0xf3, 0x32, 0x08, 0x48, 0xe3, 0x25, 0x57, 0x04, 0x63, 0x05, 0xcf, 0x83, 0x6b, + 0x4d, 0x11, 0x48, 0x74, 0x45, 0x38, 0x0d, 0xf6, 0x7a, 0x53, 0x84, 0x06, 0x61, 0x13, 0x58, 0xa9, + 0xd2, 0x44, 0x9c, 0x32, 0x6e, 0xb8, 0xfe, 0x77, 0x31, 0xe7, 0x23, 0xe7, 0xaf, 0x8e, 0xf7, 0xb5, + 0x10, 0xc1, 0xff, 0x1b, 0x1f, 0x0d, 0x82, 0xed, 0x6f, 0xa5, 0x24, 0xb8, 0xe9, 0xda, 0xdf, 0x81, + 0xd8, 0x1d, 0xb8, 0x68, 0xb3, 0x2a, 0xa2, 0x42, 0x46, 0x3c, 0xcf, 0x55, 0x1c, 0x8c, 0x9b, 0xe7, + 0x5e, 0x3d, 0x42, 0x74, 0x07, 0x41, 0xf6, 0x01, 0x30, 0xe4, 0xc5, 0x2a, 0xcf, 0x79, 0x65, 0x84, + 0xa7, 0x6e, 0x10, 0x75, 0xcd, 0x66, 0xd5, 0x03, 0xaf, 0x70, 0xec, 0x75, 0x38, 0x4f, 0x03, 0x2d, + 0xd8, 0x74, 0x4f, 0x93, 0x04, 0xbc, 0xad, 0x6e, 0xf0, 0xb9, 0x01, 0xb9, 0xe5, 0xc2, 0x25, 0xe8, + 0x3b, 0x44, 0xf0, 0x69, 0x9a, 0x23, 0x5e, 0x45, 0xce, 0x76, 0xe2, 0x9e, 0x26, 0x22, 0x7b, 0x64, + 0xdf, 0xa8, 0x9d, 0xf9, 0xad, 0x56, 0x4d, 0xd6, 0x13, 0x03, 0x2b, 0xdd, 0xe9, 0xcd, 0xd6, 0x60, + 0x31, 0x57, 0x47, 0x7e, 0x22, 0xe1, 0x11, 0xa7, 0x48, 0x26, 0xd3, 0xac, 0x19, 0x48, 0x78, 0x46, + 0x56, 0xc1, 0x7f, 0xf4, 0x73, 0x08, 0x8f, 0x88, 0x28, 0x55, 0xf8, 0xf1, 0x83, 0x47, 0x7c, 0xec, + 0x4a, 0x15, 0xd1, 0x01, 0x36, 0xde, 0x4d, 0xa0, 0x81, 0x52, 0xc5, 0x13, 0x99, 0xe7, 0x93, 0x9f, + 0x7b, 0xb0, 0xdc, 0xec, 0x39, 0xf6, 0x55, 0x77, 0x2b, 0xe0, 0xbe, 0xba, 0xf5, 0xf6, 0xe5, 0xf8, + 0xb0, 0xb4, 0xfa, 0xb8, 0x5d, 0x1d, 0x5f, 0xb4, 0xab, 0xe3, 0x3f, 0x1b, 0xfb, 0xfd, 0x22, 0x60, + 0x78, 0x8a, 0xe1, 0x5d, 0x4c, 0xf0, 0x81, 0x0b, 0xca, 0x7d, 0x18, 0x7a, 0x09, 0xeb, 0x9f, 0xc5, + 0x3c, 0xca, 0x78, 0x99, 0xe4, 0xc2, 0x50, 0x15, 0x56, 0x43, 0xc8, 0x62, 0xfe, 0xd8, 0x21, 0x0d, + 0x41, 0xcd, 0x5f, 0x8a, 0xd8, 0x1a, 0xaa, 0x89, 0x23, 0x3c, 0x73, 0xc8, 0x64, 0x07, 0x96, 0xdc, + 0x7a, 0x66, 0x9f, 0x37, 0x1d, 0x76, 0x89, 0x6e, 0xbd, 0x6d, 0x9f, 0xfb, 0x48, 0x89, 0x3f, 0xf9, + 0xa5, 0x07, 0x03, 0x0f, 0xe1, 0x35, 0x29, 0xf8, 0x4b, 0xa5, 0x7d, 0x8f, 0x9c, 0x40, 0xa8, 0x2c, + 0x95, 0x6e, 0x36, 0x28, 0x09, 0x98, 0x94, 0x9e, 0x1f, 0x5b, 0x61, 0x7c, 0xab, 0xbc, 0x84, 0xf8, + 0x91, 0xc3, 0x5d, 0xc3, 0xbc, 0x84, 0xbd, 0xd6, 0x52, 0x99, 0x66, 0x63, 0xe0, 0x19, 0xb1, 0x23, + 0xc4, 0xdc, 0xc2, 0xa0, 0xf3, 0x64, 0x0f, 0x46, 0x9d, 0x5f, 0x87, 0xb7, 0x2c, 0x76, 0x7f, 0x51, + 0x16, 0xda, 0x8b, 0x82, 0xf3, 0x80, 0xa7, 0xc2, 0xc8, 0x57, 0x82, 0x82, 0x1a, 0x86, 0xa7, 0xf2, + 0xfd, 0xe0, 0xf5, 0x9b, 0xf1, 0xb9, 0x3f, 0xdf, 0x8c, 0xcf, 0xfd, 0x74, 0x32, 0xee, 0xbd, 0x3e, + 0x19, 0xf7, 0xfe, 0x38, 0x19, 0xf7, 0xfe, 0x3e, 0x19, 0xf7, 0xe6, 0x4b, 0xf4, 0x17, 0xf8, 0xf1, + 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x2b, 0x30, 0xd6, 0x6d, 0x0a, 0x00, 0x00, +} + +func (m *Metrics) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Metrics) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Metrics) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.MemoryEvents != nil { + { + size, err := m.MemoryEvents.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if len(m.Hugetlb) > 0 { + for iNdEx := len(m.Hugetlb) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Hugetlb[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if m.Io != nil { + { + size, err := m.Io.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if m.Rdma != nil { + { + size, err := m.Rdma.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.Memory != nil { + { + size, err := m.Memory.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.CPU != nil { + { + size, err := m.CPU.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Pids != nil { + { + size, err := m.Pids.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PidsStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PidsStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PidsStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Limit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x10 + } + if m.Current != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Current)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *CPUStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CPUStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CPUStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ThrottledUsec != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ThrottledUsec)) + i-- + dAtA[i] = 0x30 + } + if m.NrThrottled != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrThrottled)) + i-- + dAtA[i] = 0x28 + } + if m.NrPeriods != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.NrPeriods)) + i-- + dAtA[i] = 0x20 + } + if m.SystemUsec != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.SystemUsec)) + i-- + dAtA[i] = 0x18 + } + if m.UserUsec != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.UserUsec)) + i-- + dAtA[i] = 0x10 + } + if m.UsageUsec != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.UsageUsec)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MemoryStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MemoryStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.SwapLimit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.SwapLimit)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x98 + } + if m.SwapUsage != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.SwapUsage)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x90 + } + if m.UsageLimit != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.UsageLimit)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x88 + } + if m.Usage != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Usage)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x80 + } + if m.ThpCollapseAlloc != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ThpCollapseAlloc)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xf8 + } + if m.ThpFaultAlloc != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ThpFaultAlloc)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xf0 + } + if m.Pglazyfreed != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pglazyfreed)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xe8 + } + if m.Pglazyfree != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pglazyfree)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xe0 + } + if m.Pgdeactivate != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgdeactivate)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd8 + } + if m.Pgactivate != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgactivate)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xd0 + } + if m.Pgsteal != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgsteal)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc8 + } + if m.Pgscan != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgscan)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc0 + } + if m.Pgrefill != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgrefill)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb8 + } + if m.WorkingsetNodereclaim != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.WorkingsetNodereclaim)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb0 + } + if m.WorkingsetActivate != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.WorkingsetActivate)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa8 + } + if m.WorkingsetRefault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.WorkingsetRefault)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.Pgmajfault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgmajfault)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } + if m.Pgfault != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Pgfault)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x90 + } + if m.SlabUnreclaimable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.SlabUnreclaimable)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.SlabReclaimable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.SlabReclaimable)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if m.Unevictable != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Unevictable)) + i-- + dAtA[i] = 0x78 + } + if m.ActiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveFile)) + i-- + dAtA[i] = 0x70 + } + if m.InactiveFile != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveFile)) + i-- + dAtA[i] = 0x68 + } + if m.ActiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.ActiveAnon)) + i-- + dAtA[i] = 0x60 + } + if m.InactiveAnon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.InactiveAnon)) + i-- + dAtA[i] = 0x58 + } + if m.AnonThp != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.AnonThp)) + i-- + dAtA[i] = 0x50 + } + if m.FileWriteback != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.FileWriteback)) + i-- + dAtA[i] = 0x48 + } + if m.FileDirty != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.FileDirty)) + i-- + dAtA[i] = 0x40 + } + if m.FileMapped != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.FileMapped)) + i-- + dAtA[i] = 0x38 + } + if m.Shmem != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Shmem)) + i-- + dAtA[i] = 0x30 + } + if m.Sock != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Sock)) + i-- + dAtA[i] = 0x28 + } + if m.Slab != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Slab)) + i-- + dAtA[i] = 0x20 + } + if m.KernelStack != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.KernelStack)) + i-- + dAtA[i] = 0x18 + } + if m.File != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.File)) + i-- + dAtA[i] = 0x10 + } + if m.Anon != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Anon)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MemoryEvents) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MemoryEvents) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MemoryEvents) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.OomKill != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.OomKill)) + i-- + dAtA[i] = 0x28 + } + if m.Oom != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Oom)) + i-- + dAtA[i] = 0x20 + } + if m.Max != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) + i-- + dAtA[i] = 0x18 + } + if m.High != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.High)) + i-- + dAtA[i] = 0x10 + } + if m.Low != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Low)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RdmaStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RdmaStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RdmaStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Limit) > 0 { + for iNdEx := len(m.Limit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Limit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Current) > 0 { + for iNdEx := len(m.Current) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Current[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RdmaEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RdmaEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RdmaEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.HcaObjects != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HcaObjects)) + i-- + dAtA[i] = 0x18 + } + if m.HcaHandles != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.HcaHandles)) + i-- + dAtA[i] = 0x10 + } + if len(m.Device) > 0 { + i -= len(m.Device) + copy(dAtA[i:], m.Device) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Device))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *IOStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IOStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IOStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Usage) > 0 { + for iNdEx := len(m.Usage) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Usage[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMetrics(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *IOEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IOEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IOEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Wios != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Wios)) + i-- + dAtA[i] = 0x30 + } + if m.Rios != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Rios)) + i-- + dAtA[i] = 0x28 + } + if m.Wbytes != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Wbytes)) + i-- + dAtA[i] = 0x20 + } + if m.Rbytes != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Rbytes)) + i-- + dAtA[i] = 0x18 + } + if m.Minor != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Minor)) + i-- + dAtA[i] = 0x10 + } + if m.Major != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Major)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *HugeTlbStat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HugeTlbStat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HugeTlbStat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Pagesize) > 0 { + i -= len(m.Pagesize) + copy(dAtA[i:], m.Pagesize) + i = encodeVarintMetrics(dAtA, i, uint64(len(m.Pagesize))) + i-- + dAtA[i] = 0x1a + } + if m.Max != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Max)) + i-- + dAtA[i] = 0x10 + } + if m.Current != 0 { + i = encodeVarintMetrics(dAtA, i, uint64(m.Current)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintMetrics(dAtA []byte, offset int, v uint64) int { + offset -= sovMetrics(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Metrics) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pids != nil { + l = m.Pids.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.CPU != nil { + l = m.CPU.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Memory != nil { + l = m.Memory.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Rdma != nil { + l = m.Rdma.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.Io != nil { + l = m.Io.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if len(m.Hugetlb) > 0 { + for _, e := range m.Hugetlb { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.MemoryEvents != nil { + l = m.MemoryEvents.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *PidsStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Current != 0 { + n += 1 + sovMetrics(uint64(m.Current)) + } + if m.Limit != 0 { + n += 1 + sovMetrics(uint64(m.Limit)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CPUStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UsageUsec != 0 { + n += 1 + sovMetrics(uint64(m.UsageUsec)) + } + if m.UserUsec != 0 { + n += 1 + sovMetrics(uint64(m.UserUsec)) + } + if m.SystemUsec != 0 { + n += 1 + sovMetrics(uint64(m.SystemUsec)) + } + if m.NrPeriods != 0 { + n += 1 + sovMetrics(uint64(m.NrPeriods)) + } + if m.NrThrottled != 0 { + n += 1 + sovMetrics(uint64(m.NrThrottled)) + } + if m.ThrottledUsec != 0 { + n += 1 + sovMetrics(uint64(m.ThrottledUsec)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *MemoryStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Anon != 0 { + n += 1 + sovMetrics(uint64(m.Anon)) + } + if m.File != 0 { + n += 1 + sovMetrics(uint64(m.File)) + } + if m.KernelStack != 0 { + n += 1 + sovMetrics(uint64(m.KernelStack)) + } + if m.Slab != 0 { + n += 1 + sovMetrics(uint64(m.Slab)) + } + if m.Sock != 0 { + n += 1 + sovMetrics(uint64(m.Sock)) + } + if m.Shmem != 0 { + n += 1 + sovMetrics(uint64(m.Shmem)) + } + if m.FileMapped != 0 { + n += 1 + sovMetrics(uint64(m.FileMapped)) + } + if m.FileDirty != 0 { + n += 1 + sovMetrics(uint64(m.FileDirty)) + } + if m.FileWriteback != 0 { + n += 1 + sovMetrics(uint64(m.FileWriteback)) + } + if m.AnonThp != 0 { + n += 1 + sovMetrics(uint64(m.AnonThp)) + } + if m.InactiveAnon != 0 { + n += 1 + sovMetrics(uint64(m.InactiveAnon)) + } + if m.ActiveAnon != 0 { + n += 1 + sovMetrics(uint64(m.ActiveAnon)) + } + if m.InactiveFile != 0 { + n += 1 + sovMetrics(uint64(m.InactiveFile)) + } + if m.ActiveFile != 0 { + n += 1 + sovMetrics(uint64(m.ActiveFile)) + } + if m.Unevictable != 0 { + n += 1 + sovMetrics(uint64(m.Unevictable)) + } + if m.SlabReclaimable != 0 { + n += 2 + sovMetrics(uint64(m.SlabReclaimable)) + } + if m.SlabUnreclaimable != 0 { + n += 2 + sovMetrics(uint64(m.SlabUnreclaimable)) + } + if m.Pgfault != 0 { + n += 2 + sovMetrics(uint64(m.Pgfault)) + } + if m.Pgmajfault != 0 { + n += 2 + sovMetrics(uint64(m.Pgmajfault)) + } + if m.WorkingsetRefault != 0 { + n += 2 + sovMetrics(uint64(m.WorkingsetRefault)) + } + if m.WorkingsetActivate != 0 { + n += 2 + sovMetrics(uint64(m.WorkingsetActivate)) + } + if m.WorkingsetNodereclaim != 0 { + n += 2 + sovMetrics(uint64(m.WorkingsetNodereclaim)) + } + if m.Pgrefill != 0 { + n += 2 + sovMetrics(uint64(m.Pgrefill)) + } + if m.Pgscan != 0 { + n += 2 + sovMetrics(uint64(m.Pgscan)) + } + if m.Pgsteal != 0 { + n += 2 + sovMetrics(uint64(m.Pgsteal)) + } + if m.Pgactivate != 0 { + n += 2 + sovMetrics(uint64(m.Pgactivate)) + } + if m.Pgdeactivate != 0 { + n += 2 + sovMetrics(uint64(m.Pgdeactivate)) + } + if m.Pglazyfree != 0 { + n += 2 + sovMetrics(uint64(m.Pglazyfree)) + } + if m.Pglazyfreed != 0 { + n += 2 + sovMetrics(uint64(m.Pglazyfreed)) + } + if m.ThpFaultAlloc != 0 { + n += 2 + sovMetrics(uint64(m.ThpFaultAlloc)) + } + if m.ThpCollapseAlloc != 0 { + n += 2 + sovMetrics(uint64(m.ThpCollapseAlloc)) + } + if m.Usage != 0 { + n += 2 + sovMetrics(uint64(m.Usage)) + } + if m.UsageLimit != 0 { + n += 2 + sovMetrics(uint64(m.UsageLimit)) + } + if m.SwapUsage != 0 { + n += 2 + sovMetrics(uint64(m.SwapUsage)) + } + if m.SwapLimit != 0 { + n += 2 + sovMetrics(uint64(m.SwapLimit)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *MemoryEvents) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Low != 0 { + n += 1 + sovMetrics(uint64(m.Low)) + } + if m.High != 0 { + n += 1 + sovMetrics(uint64(m.High)) + } + if m.Max != 0 { + n += 1 + sovMetrics(uint64(m.Max)) + } + if m.Oom != 0 { + n += 1 + sovMetrics(uint64(m.Oom)) + } + if m.OomKill != 0 { + n += 1 + sovMetrics(uint64(m.OomKill)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RdmaStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Current) > 0 { + for _, e := range m.Current { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if len(m.Limit) > 0 { + for _, e := range m.Limit { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RdmaEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Device) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.HcaHandles != 0 { + n += 1 + sovMetrics(uint64(m.HcaHandles)) + } + if m.HcaObjects != 0 { + n += 1 + sovMetrics(uint64(m.HcaObjects)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *IOStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Usage) > 0 { + for _, e := range m.Usage { + l = e.Size() + n += 1 + l + sovMetrics(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *IOEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Major != 0 { + n += 1 + sovMetrics(uint64(m.Major)) + } + if m.Minor != 0 { + n += 1 + sovMetrics(uint64(m.Minor)) + } + if m.Rbytes != 0 { + n += 1 + sovMetrics(uint64(m.Rbytes)) + } + if m.Wbytes != 0 { + n += 1 + sovMetrics(uint64(m.Wbytes)) + } + if m.Rios != 0 { + n += 1 + sovMetrics(uint64(m.Rios)) + } + if m.Wios != 0 { + n += 1 + sovMetrics(uint64(m.Wios)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *HugeTlbStat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Current != 0 { + n += 1 + sovMetrics(uint64(m.Current)) + } + if m.Max != 0 { + n += 1 + sovMetrics(uint64(m.Max)) + } + l = len(m.Pagesize) + if l > 0 { + n += 1 + l + sovMetrics(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovMetrics(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMetrics(x uint64) (n int) { + return sovMetrics(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Metrics) String() string { + if this == nil { + return "nil" + } + repeatedStringForHugetlb := "[]*HugeTlbStat{" + for _, f := range this.Hugetlb { + repeatedStringForHugetlb += strings.Replace(f.String(), "HugeTlbStat", "HugeTlbStat", 1) + "," + } + repeatedStringForHugetlb += "}" + s := strings.Join([]string{`&Metrics{`, + `Pids:` + strings.Replace(this.Pids.String(), "PidsStat", "PidsStat", 1) + `,`, + `CPU:` + strings.Replace(this.CPU.String(), "CPUStat", "CPUStat", 1) + `,`, + `Memory:` + strings.Replace(this.Memory.String(), "MemoryStat", "MemoryStat", 1) + `,`, + `Rdma:` + strings.Replace(this.Rdma.String(), "RdmaStat", "RdmaStat", 1) + `,`, + `Io:` + strings.Replace(this.Io.String(), "IOStat", "IOStat", 1) + `,`, + `Hugetlb:` + repeatedStringForHugetlb + `,`, + `MemoryEvents:` + strings.Replace(this.MemoryEvents.String(), "MemoryEvents", "MemoryEvents", 1) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *PidsStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PidsStat{`, + `Current:` + fmt.Sprintf("%v", this.Current) + `,`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CPUStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CPUStat{`, + `UsageUsec:` + fmt.Sprintf("%v", this.UsageUsec) + `,`, + `UserUsec:` + fmt.Sprintf("%v", this.UserUsec) + `,`, + `SystemUsec:` + fmt.Sprintf("%v", this.SystemUsec) + `,`, + `NrPeriods:` + fmt.Sprintf("%v", this.NrPeriods) + `,`, + `NrThrottled:` + fmt.Sprintf("%v", this.NrThrottled) + `,`, + `ThrottledUsec:` + fmt.Sprintf("%v", this.ThrottledUsec) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *MemoryStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryStat{`, + `Anon:` + fmt.Sprintf("%v", this.Anon) + `,`, + `File:` + fmt.Sprintf("%v", this.File) + `,`, + `KernelStack:` + fmt.Sprintf("%v", this.KernelStack) + `,`, + `Slab:` + fmt.Sprintf("%v", this.Slab) + `,`, + `Sock:` + fmt.Sprintf("%v", this.Sock) + `,`, + `Shmem:` + fmt.Sprintf("%v", this.Shmem) + `,`, + `FileMapped:` + fmt.Sprintf("%v", this.FileMapped) + `,`, + `FileDirty:` + fmt.Sprintf("%v", this.FileDirty) + `,`, + `FileWriteback:` + fmt.Sprintf("%v", this.FileWriteback) + `,`, + `AnonThp:` + fmt.Sprintf("%v", this.AnonThp) + `,`, + `InactiveAnon:` + fmt.Sprintf("%v", this.InactiveAnon) + `,`, + `ActiveAnon:` + fmt.Sprintf("%v", this.ActiveAnon) + `,`, + `InactiveFile:` + fmt.Sprintf("%v", this.InactiveFile) + `,`, + `ActiveFile:` + fmt.Sprintf("%v", this.ActiveFile) + `,`, + `Unevictable:` + fmt.Sprintf("%v", this.Unevictable) + `,`, + `SlabReclaimable:` + fmt.Sprintf("%v", this.SlabReclaimable) + `,`, + `SlabUnreclaimable:` + fmt.Sprintf("%v", this.SlabUnreclaimable) + `,`, + `Pgfault:` + fmt.Sprintf("%v", this.Pgfault) + `,`, + `Pgmajfault:` + fmt.Sprintf("%v", this.Pgmajfault) + `,`, + `WorkingsetRefault:` + fmt.Sprintf("%v", this.WorkingsetRefault) + `,`, + `WorkingsetActivate:` + fmt.Sprintf("%v", this.WorkingsetActivate) + `,`, + `WorkingsetNodereclaim:` + fmt.Sprintf("%v", this.WorkingsetNodereclaim) + `,`, + `Pgrefill:` + fmt.Sprintf("%v", this.Pgrefill) + `,`, + `Pgscan:` + fmt.Sprintf("%v", this.Pgscan) + `,`, + `Pgsteal:` + fmt.Sprintf("%v", this.Pgsteal) + `,`, + `Pgactivate:` + fmt.Sprintf("%v", this.Pgactivate) + `,`, + `Pgdeactivate:` + fmt.Sprintf("%v", this.Pgdeactivate) + `,`, + `Pglazyfree:` + fmt.Sprintf("%v", this.Pglazyfree) + `,`, + `Pglazyfreed:` + fmt.Sprintf("%v", this.Pglazyfreed) + `,`, + `ThpFaultAlloc:` + fmt.Sprintf("%v", this.ThpFaultAlloc) + `,`, + `ThpCollapseAlloc:` + fmt.Sprintf("%v", this.ThpCollapseAlloc) + `,`, + `Usage:` + fmt.Sprintf("%v", this.Usage) + `,`, + `UsageLimit:` + fmt.Sprintf("%v", this.UsageLimit) + `,`, + `SwapUsage:` + fmt.Sprintf("%v", this.SwapUsage) + `,`, + `SwapLimit:` + fmt.Sprintf("%v", this.SwapLimit) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *MemoryEvents) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MemoryEvents{`, + `Low:` + fmt.Sprintf("%v", this.Low) + `,`, + `High:` + fmt.Sprintf("%v", this.High) + `,`, + `Max:` + fmt.Sprintf("%v", this.Max) + `,`, + `Oom:` + fmt.Sprintf("%v", this.Oom) + `,`, + `OomKill:` + fmt.Sprintf("%v", this.OomKill) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *RdmaStat) String() string { + if this == nil { + return "nil" + } + repeatedStringForCurrent := "[]*RdmaEntry{" + for _, f := range this.Current { + repeatedStringForCurrent += strings.Replace(f.String(), "RdmaEntry", "RdmaEntry", 1) + "," + } + repeatedStringForCurrent += "}" + repeatedStringForLimit := "[]*RdmaEntry{" + for _, f := range this.Limit { + repeatedStringForLimit += strings.Replace(f.String(), "RdmaEntry", "RdmaEntry", 1) + "," + } + repeatedStringForLimit += "}" + s := strings.Join([]string{`&RdmaStat{`, + `Current:` + repeatedStringForCurrent + `,`, + `Limit:` + repeatedStringForLimit + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *RdmaEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RdmaEntry{`, + `Device:` + fmt.Sprintf("%v", this.Device) + `,`, + `HcaHandles:` + fmt.Sprintf("%v", this.HcaHandles) + `,`, + `HcaObjects:` + fmt.Sprintf("%v", this.HcaObjects) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *IOStat) String() string { + if this == nil { + return "nil" + } + repeatedStringForUsage := "[]*IOEntry{" + for _, f := range this.Usage { + repeatedStringForUsage += strings.Replace(f.String(), "IOEntry", "IOEntry", 1) + "," + } + repeatedStringForUsage += "}" + s := strings.Join([]string{`&IOStat{`, + `Usage:` + repeatedStringForUsage + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *IOEntry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&IOEntry{`, + `Major:` + fmt.Sprintf("%v", this.Major) + `,`, + `Minor:` + fmt.Sprintf("%v", this.Minor) + `,`, + `Rbytes:` + fmt.Sprintf("%v", this.Rbytes) + `,`, + `Wbytes:` + fmt.Sprintf("%v", this.Wbytes) + `,`, + `Rios:` + fmt.Sprintf("%v", this.Rios) + `,`, + `Wios:` + fmt.Sprintf("%v", this.Wios) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *HugeTlbStat) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&HugeTlbStat{`, + `Current:` + fmt.Sprintf("%v", this.Current) + `,`, + `Max:` + fmt.Sprintf("%v", this.Max) + `,`, + `Pagesize:` + fmt.Sprintf("%v", this.Pagesize) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func valueToStringMetrics(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Metrics) 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 ErrIntOverflowMetrics + } + 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: Metrics: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Metrics: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pids", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pids == nil { + m.Pids = &PidsStat{} + } + if err := m.Pids.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CPU", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CPU == nil { + m.CPU = &CPUStat{} + } + if err := m.CPU.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memory", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Memory == nil { + m.Memory = &MemoryStat{} + } + if err := m.Memory.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rdma", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Rdma == nil { + m.Rdma = &RdmaStat{} + } + if err := m.Rdma.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Io", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Io == nil { + m.Io = &IOStat{} + } + if err := m.Io.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hugetlb", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hugetlb = append(m.Hugetlb, &HugeTlbStat{}) + if err := m.Hugetlb[len(m.Hugetlb)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MemoryEvents", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MemoryEvents == nil { + m.MemoryEvents = &MemoryEvents{} + } + if err := m.MemoryEvents.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PidsStat) 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 ErrIntOverflowMetrics + } + 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: PidsStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PidsStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + m.Current = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Current |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CPUStat) 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 ErrIntOverflowMetrics + } + 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: CPUStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CPUStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UsageUsec", wireType) + } + m.UsageUsec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UsageUsec |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UserUsec", wireType) + } + m.UserUsec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UserUsec |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SystemUsec", wireType) + } + m.SystemUsec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SystemUsec |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrPeriods", wireType) + } + m.NrPeriods = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrPeriods |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NrThrottled", wireType) + } + m.NrThrottled = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NrThrottled |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThrottledUsec", wireType) + } + m.ThrottledUsec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThrottledUsec |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MemoryStat) 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 ErrIntOverflowMetrics + } + 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: MemoryStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Anon", wireType) + } + m.Anon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Anon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field File", wireType) + } + m.File = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.File |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field KernelStack", wireType) + } + m.KernelStack = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.KernelStack |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Slab", wireType) + } + m.Slab = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Slab |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sock", wireType) + } + m.Sock = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sock |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shmem", wireType) + } + m.Shmem = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Shmem |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FileMapped", wireType) + } + m.FileMapped = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FileMapped |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FileDirty", wireType) + } + m.FileDirty = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FileDirty |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FileWriteback", wireType) + } + m.FileWriteback = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FileWriteback |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AnonThp", wireType) + } + m.AnonThp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AnonThp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InactiveAnon", wireType) + } + m.InactiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InactiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveAnon", wireType) + } + m.ActiveAnon = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ActiveAnon |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InactiveFile", wireType) + } + m.InactiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InactiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveFile", wireType) + } + m.ActiveFile = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ActiveFile |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Unevictable", wireType) + } + m.Unevictable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Unevictable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SlabReclaimable", wireType) + } + m.SlabReclaimable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SlabReclaimable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SlabUnreclaimable", wireType) + } + m.SlabUnreclaimable = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SlabUnreclaimable |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 18: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgfault", wireType) + } + m.Pgfault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgfault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgmajfault", wireType) + } + m.Pgmajfault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgmajfault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WorkingsetRefault", wireType) + } + m.WorkingsetRefault = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WorkingsetRefault |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 21: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WorkingsetActivate", wireType) + } + m.WorkingsetActivate = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WorkingsetActivate |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 22: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WorkingsetNodereclaim", wireType) + } + m.WorkingsetNodereclaim = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WorkingsetNodereclaim |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 23: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgrefill", wireType) + } + m.Pgrefill = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgrefill |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 24: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgscan", wireType) + } + m.Pgscan = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgscan |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 25: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgsteal", wireType) + } + m.Pgsteal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgsteal |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 26: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgactivate", wireType) + } + m.Pgactivate = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgactivate |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 27: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pgdeactivate", wireType) + } + m.Pgdeactivate = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pgdeactivate |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 28: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pglazyfree", wireType) + } + m.Pglazyfree = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pglazyfree |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 29: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pglazyfreed", wireType) + } + m.Pglazyfreed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Pglazyfreed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 30: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThpFaultAlloc", wireType) + } + m.ThpFaultAlloc = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThpFaultAlloc |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 31: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThpCollapseAlloc", wireType) + } + m.ThpCollapseAlloc = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThpCollapseAlloc |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 32: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + m.Usage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Usage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 33: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UsageLimit", wireType) + } + m.UsageLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UsageLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 34: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapUsage", wireType) + } + m.SwapUsage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SwapUsage |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 35: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapLimit", wireType) + } + m.SwapLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SwapLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MemoryEvents) 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 ErrIntOverflowMetrics + } + 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: MemoryEvents: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MemoryEvents: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Low", wireType) + } + m.Low = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Low |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field High", wireType) + } + m.High = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.High |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) + } + m.Max = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Max |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Oom", wireType) + } + m.Oom = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Oom |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OomKill", wireType) + } + m.OomKill = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OomKill |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RdmaStat) 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 ErrIntOverflowMetrics + } + 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: RdmaStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RdmaStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Current = append(m.Current, &RdmaEntry{}) + if err := m.Current[len(m.Current)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Limit = append(m.Limit, &RdmaEntry{}) + if err := m.Limit[len(m.Limit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RdmaEntry) 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 ErrIntOverflowMetrics + } + 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: RdmaEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RdmaEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Device = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HcaHandles", wireType) + } + m.HcaHandles = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HcaHandles |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HcaObjects", wireType) + } + m.HcaObjects = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HcaObjects |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IOStat) 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 ErrIntOverflowMetrics + } + 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: IOStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IOStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Usage", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMetrics + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Usage = append(m.Usage, &IOEntry{}) + if err := m.Usage[len(m.Usage)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IOEntry) 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 ErrIntOverflowMetrics + } + 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: IOEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IOEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Major", wireType) + } + m.Major = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Major |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Minor", wireType) + } + m.Minor = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Minor |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Rbytes", wireType) + } + m.Rbytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Rbytes |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Wbytes", wireType) + } + m.Wbytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Wbytes |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Rios", wireType) + } + m.Rios = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Rios |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Wios", wireType) + } + m.Wios = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Wios |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HugeTlbStat) 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 ErrIntOverflowMetrics + } + 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: HugeTlbStat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HugeTlbStat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + m.Current = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Current |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) + } + m.Max = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Max |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagesize", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetrics + } + 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 ErrInvalidLengthMetrics + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetrics + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pagesize = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetrics(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetrics + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMetrics(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetrics + } + 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, ErrIntOverflowMetrics + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetrics + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMetrics + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMetrics + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMetrics + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMetrics = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMetrics = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMetrics = fmt.Errorf("proto: unexpected end of group") +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.txt containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.txt --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.txt 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.txt 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,539 @@ +file { + name: "github.com/containerd/cgroups/v2/stats/metrics.proto" + package: "io.containerd.cgroups.v2" + dependency: "gogoproto/gogo.proto" + message_type { + name: "Metrics" + field { + name: "pids" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.PidsStat" + json_name: "pids" + } + field { + name: "cpu" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.CPUStat" + options { + 65004: "CPU" + } + json_name: "cpu" + } + field { + name: "memory" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.MemoryStat" + json_name: "memory" + } + field { + name: "rdma" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.RdmaStat" + json_name: "rdma" + } + field { + name: "io" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.IOStat" + json_name: "io" + } + field { + name: "hugetlb" + number: 7 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.HugeTlbStat" + json_name: "hugetlb" + } + field { + name: "memory_events" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.MemoryEvents" + json_name: "memoryEvents" + } + } + message_type { + name: "PidsStat" + field { + name: "current" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "current" + } + field { + name: "limit" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "limit" + } + } + message_type { + name: "CPUStat" + field { + name: "usage_usec" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "usageUsec" + } + field { + name: "user_usec" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "userUsec" + } + field { + name: "system_usec" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "systemUsec" + } + field { + name: "nr_periods" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrPeriods" + } + field { + name: "nr_throttled" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "nrThrottled" + } + field { + name: "throttled_usec" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "throttledUsec" + } + } + message_type { + name: "MemoryStat" + field { + name: "anon" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "anon" + } + field { + name: "file" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "file" + } + field { + name: "kernel_stack" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "kernelStack" + } + field { + name: "slab" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "slab" + } + field { + name: "sock" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "sock" + } + field { + name: "shmem" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "shmem" + } + field { + name: "file_mapped" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "fileMapped" + } + field { + name: "file_dirty" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "fileDirty" + } + field { + name: "file_writeback" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "fileWriteback" + } + field { + name: "anon_thp" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "anonThp" + } + field { + name: "inactive_anon" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "inactiveAnon" + } + field { + name: "active_anon" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "activeAnon" + } + field { + name: "inactive_file" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "inactiveFile" + } + field { + name: "active_file" + number: 14 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "activeFile" + } + field { + name: "unevictable" + number: 15 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "unevictable" + } + field { + name: "slab_reclaimable" + number: 16 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "slabReclaimable" + } + field { + name: "slab_unreclaimable" + number: 17 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "slabUnreclaimable" + } + field { + name: "pgfault" + number: 18 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgfault" + } + field { + name: "pgmajfault" + number: 19 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgmajfault" + } + field { + name: "workingset_refault" + number: 20 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "workingsetRefault" + } + field { + name: "workingset_activate" + number: 21 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "workingsetActivate" + } + field { + name: "workingset_nodereclaim" + number: 22 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "workingsetNodereclaim" + } + field { + name: "pgrefill" + number: 23 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgrefill" + } + field { + name: "pgscan" + number: 24 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgscan" + } + field { + name: "pgsteal" + number: 25 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgsteal" + } + field { + name: "pgactivate" + number: 26 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgactivate" + } + field { + name: "pgdeactivate" + number: 27 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pgdeactivate" + } + field { + name: "pglazyfree" + number: 28 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pglazyfree" + } + field { + name: "pglazyfreed" + number: 29 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "pglazyfreed" + } + field { + name: "thp_fault_alloc" + number: 30 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "thpFaultAlloc" + } + field { + name: "thp_collapse_alloc" + number: 31 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "thpCollapseAlloc" + } + field { + name: "usage" + number: 32 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "usage" + } + field { + name: "usage_limit" + number: 33 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "usageLimit" + } + field { + name: "swap_usage" + number: 34 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "swapUsage" + } + field { + name: "swap_limit" + number: 35 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "swapLimit" + } + } + message_type { + name: "MemoryEvents" + field { + name: "low" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "low" + } + field { + name: "high" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "high" + } + field { + name: "max" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "max" + } + field { + name: "oom" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "oom" + } + field { + name: "oom_kill" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "oomKill" + } + } + message_type { + name: "RdmaStat" + field { + name: "current" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.RdmaEntry" + json_name: "current" + } + field { + name: "limit" + number: 2 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.RdmaEntry" + json_name: "limit" + } + } + message_type { + name: "RdmaEntry" + field { + name: "device" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "device" + } + field { + name: "hca_handles" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "hcaHandles" + } + field { + name: "hca_objects" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "hcaObjects" + } + } + message_type { + name: "IOStat" + field { + name: "usage" + number: 1 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".io.containerd.cgroups.v2.IOEntry" + json_name: "usage" + } + } + message_type { + name: "IOEntry" + field { + name: "major" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "major" + } + field { + name: "minor" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "minor" + } + field { + name: "rbytes" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rbytes" + } + field { + name: "wbytes" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "wbytes" + } + field { + name: "rios" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "rios" + } + field { + name: "wios" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "wios" + } + } + message_type { + name: "HugeTlbStat" + field { + name: "current" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "current" + } + field { + name: "max" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_UINT64 + json_name: "max" + } + field { + name: "pagesize" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "pagesize" + } + } + syntax: "proto3" +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/stats/metrics.proto 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,105 @@ +syntax = "proto3"; + +package io.containerd.cgroups.v2; + + import "gogoproto/gogo.proto"; + +message Metrics { + PidsStat pids = 1; + CPUStat cpu = 2 [(gogoproto.customname) = "CPU"]; + MemoryStat memory = 4; + RdmaStat rdma = 5; + IOStat io = 6; + repeated HugeTlbStat hugetlb = 7; + MemoryEvents memory_events = 8; +} + +message PidsStat { + uint64 current = 1; + uint64 limit = 2; +} + +message CPUStat { + uint64 usage_usec = 1; + uint64 user_usec = 2; + uint64 system_usec = 3; + uint64 nr_periods = 4; + uint64 nr_throttled = 5; + uint64 throttled_usec = 6; +} + +message MemoryStat { + uint64 anon = 1; + uint64 file = 2; + uint64 kernel_stack = 3; + uint64 slab = 4; + uint64 sock = 5; + uint64 shmem = 6; + uint64 file_mapped = 7; + uint64 file_dirty = 8; + uint64 file_writeback = 9; + uint64 anon_thp = 10; + uint64 inactive_anon = 11; + uint64 active_anon = 12; + uint64 inactive_file = 13; + uint64 active_file = 14; + uint64 unevictable = 15; + uint64 slab_reclaimable = 16; + uint64 slab_unreclaimable = 17; + uint64 pgfault = 18; + uint64 pgmajfault = 19; + uint64 workingset_refault = 20; + uint64 workingset_activate = 21; + uint64 workingset_nodereclaim = 22; + uint64 pgrefill = 23; + uint64 pgscan = 24; + uint64 pgsteal = 25; + uint64 pgactivate = 26; + uint64 pgdeactivate = 27; + uint64 pglazyfree = 28; + uint64 pglazyfreed = 29; + uint64 thp_fault_alloc = 30; + uint64 thp_collapse_alloc = 31; + uint64 usage = 32; + uint64 usage_limit = 33; + uint64 swap_usage = 34; + uint64 swap_limit = 35; +} + +message MemoryEvents { + uint64 low = 1; + uint64 high = 2; + uint64 max = 3; + uint64 oom = 4; + uint64 oom_kill = 5; +} + +message RdmaStat { + repeated RdmaEntry current = 1; + repeated RdmaEntry limit = 2; +} + +message RdmaEntry { + string device = 1; + uint32 hca_handles = 2; + uint32 hca_objects = 3; +} + +message IOStat { + repeated IOEntry usage = 1; +} + +message IOEntry { + uint64 major = 1; + uint64 minor = 2; + uint64 rbytes = 3; + uint64 wbytes = 4; + uint64 rios = 5; + uint64 wios = 6; +} + +message HugeTlbStat { + uint64 current = 1; + uint64 max = 2; + string pagesize = 3; +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/utils.go containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/utils.go --- containerd-1.2.6/vendor/github.com/containerd/cgroups/v2/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/v2/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,436 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v2 + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "math" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/containerd/cgroups/v2/stats" + "github.com/godbus/dbus/v5" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + cgroupProcs = "cgroup.procs" + defaultDirPerm = 0755 +) + +// defaultFilePerm is a var so that the test framework can change the filemode +// of all files created when the tests are running. The difference between the +// tests and real world use is that files like "cgroup.procs" will exist when writing +// to a read cgroup filesystem and do not exist prior when running in the tests. +// this is set to a non 0 value in the test code +var defaultFilePerm = os.FileMode(0) + +// remove will remove a cgroup path handling EAGAIN and EBUSY errors and +// retrying the remove after a exp timeout +func remove(path string) error { + var err error + delay := 10 * time.Millisecond + for i := 0; i < 5; i++ { + if i != 0 { + time.Sleep(delay) + delay *= 2 + } + if err = os.RemoveAll(path); err == nil { + return nil + } + } + return errors.Wrapf(err, "cgroups: unable to remove path %q", path) +} + +// parseCgroupProcsFile parses /sys/fs/cgroup/$GROUPPATH/cgroup.procs +func parseCgroupProcsFile(path string) ([]uint64, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + var ( + out []uint64 + s = bufio.NewScanner(f) + ) + for s.Scan() { + if t := s.Text(); t != "" { + pid, err := strconv.ParseUint(t, 10, 0) + if err != nil { + return nil, err + } + out = append(out, pid) + } + } + if err := s.Err(); err != nil { + return nil, err + } + return out, nil +} + +func parseKV(raw string) (string, interface{}, error) { + parts := strings.Fields(raw) + switch len(parts) { + case 2: + v, err := parseUint(parts[1], 10, 64) + if err != nil { + // if we cannot parse as a uint, parse as a string + return parts[0], parts[1], nil + } + return parts[0], v, nil + default: + return "", 0, ErrInvalidFormat + } +} + +func parseUint(s string, base, bitSize int) (uint64, error) { + v, err := strconv.ParseUint(s, base, bitSize) + if err != nil { + intValue, intErr := strconv.ParseInt(s, base, bitSize) + // 1. Handle negative values greater than MinInt64 (and) + // 2. Handle negative values lesser than MinInt64 + if intErr == nil && intValue < 0 { + return 0, nil + } else if intErr != nil && + intErr.(*strconv.NumError).Err == strconv.ErrRange && + intValue < 0 { + return 0, nil + } + return 0, err + } + return v, nil +} + +// parseCgroupFile parses /proc/PID/cgroup file and return string +func parseCgroupFile(path string) (string, error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + return parseCgroupFromReader(f) +} + +func parseCgroupFromReader(r io.Reader) (string, error) { + var ( + s = bufio.NewScanner(r) + ) + for s.Scan() { + var ( + text = s.Text() + parts = strings.SplitN(text, ":", 3) + ) + if len(parts) < 3 { + return "", fmt.Errorf("invalid cgroup entry: %q", text) + } + // text is like "0::/user.slice/user-1001.slice/session-1.scope" + if parts[0] == "0" && parts[1] == "" { + return parts[2], nil + } + } + if err := s.Err(); err != nil { + return "", err + } + return "", fmt.Errorf("cgroup path not found") +} + +// ToResources converts the oci LinuxResources struct into a +// v2 Resources type for use with this package. +// +// converting cgroups configuration from v1 to v2 +// ref: https://github.com/containers/crun/blob/master/crun.1.md#cgroup-v2 +func ToResources(spec *specs.LinuxResources) *Resources { + var resources Resources + if cpu := spec.CPU; cpu != nil { + resources.CPU = &CPU{ + Cpus: cpu.Cpus, + Mems: cpu.Mems, + } + if shares := cpu.Shares; shares != nil { + convertedWeight := 1 + ((*shares-2)*9999)/262142 + resources.CPU.Weight = &convertedWeight + } + if period := cpu.Period; period != nil { + resources.CPU.Max = NewCPUMax(cpu.Quota, period) + } + } + if mem := spec.Memory; mem != nil { + resources.Memory = &Memory{} + if swap := mem.Swap; swap != nil { + resources.Memory.Swap = swap + } + if l := mem.Limit; l != nil { + resources.Memory.Max = l + } + if l := mem.Reservation; l != nil { + resources.Memory.Low = l + } + } + if hugetlbs := spec.HugepageLimits; hugetlbs != nil { + hugeTlbUsage := HugeTlb{} + for _, hugetlb := range hugetlbs { + hugeTlbUsage = append(hugeTlbUsage, HugeTlbEntry{ + HugePageSize: hugetlb.Pagesize, + Limit: hugetlb.Limit, + }) + } + resources.HugeTlb = &hugeTlbUsage + } + if pids := spec.Pids; pids != nil { + resources.Pids = &Pids{ + Max: pids.Limit, + } + } + if i := spec.BlockIO; i != nil { + resources.IO = &IO{} + if i.Weight != nil { + resources.IO.BFQ.Weight = 1 + (*i.Weight-10)*9999/990 + } + for t, devices := range map[IOType][]specs.LinuxThrottleDevice{ + ReadBPS: i.ThrottleReadBpsDevice, + WriteBPS: i.ThrottleWriteBpsDevice, + ReadIOPS: i.ThrottleReadIOPSDevice, + WriteIOPS: i.ThrottleWriteIOPSDevice, + } { + for _, d := range devices { + resources.IO.Max = append(resources.IO.Max, Entry{ + Type: t, + Major: d.Major, + Minor: d.Minor, + Rate: d.Rate, + }) + } + } + } + if i := spec.Rdma; i != nil { + resources.RDMA = &RDMA{} + for device, value := range spec.Rdma { + if device != "" && (value.HcaHandles != nil || value.HcaObjects != nil) { + resources.RDMA.Limit = append(resources.RDMA.Limit, RDMAEntry{ + Device: device, + HcaHandles: *value.HcaHandles, + HcaObjects: *value.HcaObjects, + }) + } + } + } + + return &resources +} + +// Gets uint64 parsed content of single value cgroup stat file +func getStatFileContentUint64(filePath string) uint64 { + contents, err := ioutil.ReadFile(filePath) + if err != nil { + return 0 + } + trimmed := strings.TrimSpace(string(contents)) + if trimmed == "max" { + return math.MaxUint64 + } + + res, err := parseUint(trimmed, 10, 64) + if err != nil { + logrus.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), filePath) + return res + } + + return res +} + +func readIoStats(path string) []*stats.IOEntry { + // more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt + var usage []*stats.IOEntry + fpath := filepath.Join(path, "io.stat") + currentData, err := ioutil.ReadFile(fpath) + if err != nil { + return usage + } + entries := strings.Split(string(currentData), "\n") + + for _, entry := range entries { + parts := strings.Split(entry, " ") + if len(parts) < 2 { + continue + } + majmin := strings.Split(parts[0], ":") + if len(majmin) != 2 { + continue + } + major, err := strconv.ParseUint(majmin[0], 10, 0) + if err != nil { + return usage + } + minor, err := strconv.ParseUint(majmin[1], 10, 0) + if err != nil { + return usage + } + parts = parts[1:] + ioEntry := stats.IOEntry{ + Major: major, + Minor: minor, + } + for _, s := range parts { + keyPairValue := strings.Split(s, "=") + if len(keyPairValue) != 2 { + continue + } + v, err := strconv.ParseUint(keyPairValue[1], 10, 0) + if err != nil { + continue + } + switch keyPairValue[0] { + case "rbytes": + ioEntry.Rbytes = v + case "wbytes": + ioEntry.Wbytes = v + case "rios": + ioEntry.Rios = v + case "wios": + ioEntry.Wios = v + } + } + usage = append(usage, &ioEntry) + } + return usage +} + +func rdmaStats(filepath string) []*stats.RdmaEntry { + currentData, err := ioutil.ReadFile(filepath) + if err != nil { + return []*stats.RdmaEntry{} + } + return toRdmaEntry(strings.Split(string(currentData), "\n")) +} + +func parseRdmaKV(raw string, entry *stats.RdmaEntry) { + var value uint64 + var err error + + parts := strings.Split(raw, "=") + switch len(parts) { + case 2: + if parts[1] == "max" { + value = math.MaxUint32 + } else { + value, err = parseUint(parts[1], 10, 32) + if err != nil { + return + } + } + if parts[0] == "hca_handle" { + entry.HcaHandles = uint32(value) + } else if parts[0] == "hca_object" { + entry.HcaObjects = uint32(value) + } + } +} + +func toRdmaEntry(strEntries []string) []*stats.RdmaEntry { + var rdmaEntries []*stats.RdmaEntry + for i := range strEntries { + parts := strings.Fields(strEntries[i]) + switch len(parts) { + case 3: + entry := new(stats.RdmaEntry) + entry.Device = parts[0] + parseRdmaKV(parts[1], entry) + parseRdmaKV(parts[2], entry) + + rdmaEntries = append(rdmaEntries, entry) + default: + continue + } + } + return rdmaEntries +} + +// isUnitExists returns true if the error is that a systemd unit already exists. +func isUnitExists(err error) bool { + if err != nil { + if dbusError, ok := err.(dbus.Error); ok { + return strings.Contains(dbusError.Name, "org.freedesktop.systemd1.UnitExists") + } + } + return false +} + +func systemdUnitFromPath(path string) string { + _, unit := filepath.Split(path) + return unit +} + +func readHugeTlbStats(path string) []*stats.HugeTlbStat { + var usage = []*stats.HugeTlbStat{} + var keyUsage = make(map[string]*stats.HugeTlbStat) + f, err := os.Open(path) + if err != nil { + return usage + } + files, err := f.Readdir(-1) + f.Close() + if err != nil { + return usage + } + + for _, file := range files { + if strings.Contains(file.Name(), "hugetlb") && + (strings.HasSuffix(file.Name(), "max") || strings.HasSuffix(file.Name(), "current")) { + var hugeTlb *stats.HugeTlbStat + var ok bool + fileName := strings.Split(file.Name(), ".") + pageSize := fileName[1] + if hugeTlb, ok = keyUsage[pageSize]; !ok { + hugeTlb = &stats.HugeTlbStat{} + } + hugeTlb.Pagesize = pageSize + out, err := ioutil.ReadFile(filepath.Join(path, file.Name())) + if err != nil { + continue + } + var value uint64 + stringVal := strings.TrimSpace(string(out)) + if stringVal == "max" { + value = math.MaxUint64 + } else { + value, err = strconv.ParseUint(stringVal, 10, 64) + } + if err != nil { + continue + } + switch fileName[2] { + case "max": + hugeTlb.Max = value + case "current": + hugeTlb.Current = value + } + keyUsage[pageSize] = hugeTlb + } + } + for _, entry := range keyUsage { + usage = append(usage, entry) + } + return usage +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cgroups/Vagrantfile containerd-1.5.9/vendor/github.com/containerd/cgroups/Vagrantfile --- containerd-1.2.6/vendor/github.com/containerd/cgroups/Vagrantfile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cgroups/Vagrantfile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| +# Fedora box is used for testing cgroup v2 support + config.vm.box = "fedora/32-cloud-base" + config.vm.provider :virtualbox do |v| + v.memory = 2048 + v.cpus = 2 + end + config.vm.provider :libvirt do |v| + v.memory = 2048 + v.cpus = 2 + end + config.vm.provision "shell", inline: <<-SHELL + set -eux -o pipefail + # configuration + GO_VERSION="1.15" + + # install gcc and Golang + dnf -y install gcc + curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local + + # setup env vars + cat >> /etc/profile.d/sh.local < /test.sh < +#include +#include +*/ +import "C" + +// openpt allocates a new pseudo-terminal and establishes a connection with its +// control device. +func openpt() (*os.File, error) { + fd, err := C.posix_openpt(C.O_RDWR) + if err != nil { + return nil, fmt.Errorf("posix_openpt: %w", err) + } + if _, err := C.grantpt(fd); err != nil { + C.close(fd) + return nil, fmt.Errorf("grantpt: %w", err) + } + return os.NewFile(uintptr(fd), ""), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/pty_freebsd_nocgo.go containerd-1.5.9/vendor/github.com/containerd/console/pty_freebsd_nocgo.go --- containerd-1.2.6/vendor/github.com/containerd/console/pty_freebsd_nocgo.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/pty_freebsd_nocgo.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +// +build freebsd,!cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "os" +) + +// +// Implementing the functions below requires cgo support. Non-cgo stubs +// versions are defined below to enable cross-compilation of source code +// that depends on these functions, but the resultant cross-compiled +// binaries cannot actually be used. If the stub function(s) below are +// actually invoked they will display an error message and cause the +// calling process to exit. +// + +func openpt() (*os.File, error) { + panic("openpt() support requires cgo.") +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/pty_unix.go containerd-1.5.9/vendor/github.com/containerd/console/pty_unix.go --- containerd-1.2.6/vendor/github.com/containerd/console/pty_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/pty_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,30 @@ +// +build darwin linux netbsd openbsd solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device +func openpt() (*os.File, error) { + return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/README.md containerd-1.5.9/vendor/github.com/containerd/console/README.md --- containerd-1.2.6/vendor/github.com/containerd/console/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,8 @@ # console -[![Build Status](https://travis-ci.org/containerd/console.svg?branch=master)](https://travis-ci.org/containerd/console) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/containerd/console) +[![Build Status](https://github.com/containerd/console/workflows/CI/badge.svg)](https://github.com/containerd/console/actions?query=workflow%3ACI) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/console)](https://goreportcard.com/report/github.com/containerd/console) Golang package for dealing with consoles. Light on deps and a simple API. @@ -15,3 +17,13 @@ ws, err := current.Size() current.Resize(ws) ``` + +## Project details + +console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_darwin.go containerd-1.5.9/vendor/github.com/containerd/console/tc_darwin.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_darwin.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,7 +19,6 @@ import ( "fmt" "os" - "unsafe" "golang.org/x/sys/unix" ) @@ -29,18 +28,10 @@ cmdTcSet = unix.TIOCSETA ) -func ioctl(fd, flag, data uintptr) error { - if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, flag, data); err != 0 { - return err - } - return nil -} - // unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. // unlockpt should be called before opening the slave side of a pty. func unlockpt(f *os.File) error { - var u int32 - return ioctl(f.Fd(), unix.TIOCPTYUNLK, uintptr(unsafe.Pointer(&u))) + return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0) } // ptsname retrieves the name of the first available pts for the given master. diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd_cgo.go containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd_cgo.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd_cgo.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd_cgo.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +// +build freebsd,cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +/* +#include +#include +*/ +import "C" + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + fd := C.int(f.Fd()) + if _, err := C.unlockpt(fd); err != nil { + C.close(fd) + return fmt.Errorf("unlockpt: %w", err) + } + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) + if err != nil { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", n), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd.go containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package console - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -const ( - cmdTcGet = unix.TIOCGETA - cmdTcSet = unix.TIOCSETA -) - -// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. -// unlockpt should be called before opening the slave side of a pty. -// This does not exist on FreeBSD, it does not allocate controlling terminals on open -func unlockpt(f *os.File) error { - return nil -} - -// ptsname retrieves the name of the first available pts for the given master. -func ptsname(f *os.File) (string, error) { - n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) - if err != nil { - return "", err - } - return fmt.Sprintf("/dev/pts/%d", n), nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd_nocgo.go containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd_nocgo.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_freebsd_nocgo.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_freebsd_nocgo.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +// +build freebsd,!cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +// +// Implementing the functions below requires cgo support. Non-cgo stubs +// versions are defined below to enable cross-compilation of source code +// that depends on these functions, but the resultant cross-compiled +// binaries cannot actually be used. If the stub function(s) below are +// actually invoked they will display an error message and cause the +// calling process to exit. +// + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + panic("unlockpt() support requires cgo.") +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) + if err != nil { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", n), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_linux.go containerd-1.5.9/vendor/github.com/containerd/console/tc_linux.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,6 +33,7 @@ // unlockpt should be called before opening the slave side of a pty. func unlockpt(f *os.File) error { var u int32 + // XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81. if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 { return err } @@ -42,6 +43,7 @@ // ptsname retrieves the name of the first available pts for the given master. func ptsname(f *os.File) (string, error) { var u uint32 + // XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81. if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 { return "", err } diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_netbsd.go containerd-1.5.9/vendor/github.com/containerd/console/tc_netbsd.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_netbsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_netbsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,45 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "bytes" + "os" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +// This does not exist on NetBSD, it does not allocate controlling terminals on open +func unlockpt(f *os.File) error { + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME) + if err != nil { + return "", err + } + return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/console/tc_unix.go containerd-1.5.9/vendor/github.com/containerd/console/tc_unix.go --- containerd-1.2.6/vendor/github.com/containerd/console/tc_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/console/tc_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build darwin freebsd linux openbsd solaris +// +build darwin freebsd linux netbsd openbsd solaris /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/AUTHORS containerd-1.5.9/vendor/github.com/containerd/continuity/AUTHORS --- containerd-1.2.6/vendor/github.com/containerd/continuity/AUTHORS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/AUTHORS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +Aaron Lehmann +Akash Gupta +Akihiro Suda +Akihiro Suda +Akihiro Suda +Andrew Pennebaker +Brandon Philips +Brian Goff +Christopher Jones +Daniel, Dao Quang Minh +Darren Stahl +Derek McGowan +Derek McGowan +Edward Pilatowicz +Ian Campbell +Ivan Markin +Justin Cormack +Justin Cummins +Kasper Fabæch Brandt +Kir Kolyshkin +Michael Crosby +Michael Crosby +Michael Wan +Mike Brown +Niels de Vos +Phil Estes +Phil Estes +Samuel Karp +Sam Whited +Sebastiaan van Stijn +Shengjing Zhu +Stephen J Day +Tibor Vass +Tobias Klauser +Tom Faulhaber +Tonis Tiigi +Trevor Porter +Wei Fu +Wilbert van de Ridder +Xiaodong Ye diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/context.go containerd-1.5.9/vendor/github.com/containerd/continuity/context.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/context.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/context.go 2022-01-05 17:30:58.000000000 +0000 @@ -596,7 +596,7 @@ return err } } - return c.pathDriver.Walk(root, func(p string, fi os.FileInfo, err error) error { + return c.pathDriver.Walk(root, func(p string, fi os.FileInfo, _ error) error { contained, err := c.containWithRoot(p, root) return fn(contained, fi, err) }) @@ -613,12 +613,6 @@ return p, nil } -// contain cleans and santizes the filesystem path p to be an absolute path, -// effectively relative to the context root. -func (c *context) contain(p string) (string, error) { - return c.containWithRoot(p, c.root) -} - // containWithRoot cleans and santizes the filesystem path p to be an absolute path, // effectively relative to the passed root. Extra care should be used when calling this // instead of contain. This is needed for Walk, as if context root is a symlink, diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/devices/devices_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/devices/devices_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/devices/devices_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/devices/devices_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,6 +32,7 @@ return 0, 0, fmt.Errorf("cannot extract device from os.FileInfo") } + //nolint:unconvert dev := uint64(sys.Rdev) return uint64(unix.Major(dev)), uint64(unix.Minor(dev)), nil } @@ -55,7 +56,7 @@ m |= unix.S_IFIFO } - return unix.Mknod(p, m, int(dev)) + return mknod(p, m, dev) } // syscallMode returns the syscall-specific mode bits from Go's portable mode bits. diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/devices/mknod_freebsd.go containerd-1.5.9/vendor/github.com/containerd/continuity/devices/mknod_freebsd.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/devices/mknod_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/devices/mknod_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devices + +import "golang.org/x/sys/unix" + +func mknod(path string, mode uint32, dev uint64) (err error) { + return unix.Mknod(path, mode, dev) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/devices/mknod_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/devices/mknod_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/devices/mknod_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/devices/mknod_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +// +build linux darwin solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package devices + +import "golang.org/x/sys/unix" + +func mknod(path string, mode uint32, dev uint64) (err error) { + return unix.Mknod(path, mode, int(dev)) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/digests.go containerd-1.5.9/vendor/github.com/containerd/continuity/digests.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/digests.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/digests.go 2022-01-05 17:30:58.000000000 +0000 @@ -88,13 +88,9 @@ } disjoint := len(as) + len(bs) - if len(uniqified) == disjoint { - // if these two sets have the same cardinality, we know both sides - // didn't share any digests. - return false - } - - return true + // if these two sets have the same cardinality, we know both sides + // didn't share any digests. + return len(uniqified) != disjoint } type digestSlice []digest.Digest diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver.go containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver.go 2022-01-05 17:30:58.000000000 +0000 @@ -138,6 +138,10 @@ return os.Lstat(p) } +func (d *driver) Readlink(p string) (string, error) { + return os.Readlink(p) +} + func (d *driver) Mkdir(p string, mode os.FileMode) error { return os.Mkdir(p, mode) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -131,8 +131,3 @@ func (d *driver) DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error) { return devices.DeviceInfo(fi) } - -// Readlink was forked on Windows to fix a Golang bug, use the "os" package here -func (d *driver) Readlink(p string) (string, error) { - return os.Readlink(p) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver_windows.go containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver_windows.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/driver/driver_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/driver/driver_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,5 @@ +// +build go1.13 + /* Copyright The containerd Authors. @@ -14,12 +16,14 @@ limitations under the License. */ +// Go 1.13 is the minimally supported version for Windows. +// Earlier golang releases have bug in os.Readlink +// (see https://github.com/golang/go/issues/30463). + package driver import ( "os" - - "github.com/containerd/continuity/sysx" ) func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error { @@ -35,9 +39,3 @@ // TODO: Use Window's equivalent return os.Chmod(path, mode) } - -// Readlink is forked in order to support Volume paths which are used -// in container layers. -func (d *driver) Readlink(p string) (string, error) { - return sysx.Readlink(p) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_darwinopenbsdsolaris.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_darwinopenbsdsolaris.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_darwinopenbsdsolaris.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_darwinopenbsdsolaris.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +// +build darwin openbsd solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fs + +import ( + "os" + "syscall" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +func copyDevice(dst string, fi os.FileInfo) error { + st, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return errors.New("unsupported stat type") + } + return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev)) +} + +func utimesNano(name string, atime, mtime syscall.Timespec) error { + timespec := []syscall.Timespec{atime, mtime} + return syscall.UtimesNano(name, timespec) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_freebsd.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_freebsd.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_freebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_freebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +// +build freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fs + +import ( + "os" + "syscall" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +func copyDevice(dst string, fi os.FileInfo) error { + st, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return errors.New("unsupported stat type") + } + return unix.Mknod(dst, uint32(fi.Mode()), st.Rdev) +} + +func utimesNano(name string, atime, mtime syscall.Timespec) error { + at := unix.NsecToTimespec(atime.Nano()) + mt := unix.NsecToTimespec(mtime.Nano()) + utimes := [2]unix.Timespec{at, mt} + return unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy.go 2022-01-05 17:30:58.000000000 +0000 @@ -32,20 +32,70 @@ }, } +// XAttrErrorHandlers transform a non-nil xattr error. +// Return nil to ignore an error. +// xattrKey can be empty for listxattr operation. +type XAttrErrorHandler func(dst, src, xattrKey string, err error) error + +type copyDirOpts struct { + xeh XAttrErrorHandler + // xex contains a set of xattrs to exclude when copying + xex map[string]struct{} +} + +type CopyDirOpt func(*copyDirOpts) error + +// WithXAttrErrorHandler allows specifying XAttrErrorHandler +// If nil XAttrErrorHandler is specified (default), CopyDir stops +// on a non-nil xattr error. +func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt { + return func(o *copyDirOpts) error { + o.xeh = xeh + return nil + } +} + +// WithAllowXAttrErrors allows ignoring xattr errors. +func WithAllowXAttrErrors() CopyDirOpt { + xeh := func(dst, src, xattrKey string, err error) error { + return nil + } + return WithXAttrErrorHandler(xeh) +} + +// WithXAttrExclude allows for exclusion of specified xattr during CopyDir operation. +func WithXAttrExclude(keys ...string) CopyDirOpt { + return func(o *copyDirOpts) error { + if o.xex == nil { + o.xex = make(map[string]struct{}, len(keys)) + } + for _, key := range keys { + o.xex[key] = struct{}{} + } + return nil + } +} + // CopyDir copies the directory from src to dst. // Most efficient copy of files is attempted. -func CopyDir(dst, src string) error { +func CopyDir(dst, src string, opts ...CopyDirOpt) error { + var o copyDirOpts + for _, opt := range opts { + if err := opt(&o); err != nil { + return err + } + } inodes := map[uint64]string{} - return copyDirectory(dst, src, inodes) + return copyDirectory(dst, src, inodes, &o) } -func copyDirectory(dst, src string, inodes map[uint64]string) error { +func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error { stat, err := os.Stat(src) if err != nil { return errors.Wrapf(err, "failed to stat %s", src) } if !stat.IsDir() { - return errors.Errorf("source is not directory") + return errors.Errorf("source %s is not directory", src) } if st, err := os.Stat(dst); err != nil { @@ -69,13 +119,17 @@ return errors.Wrapf(err, "failed to copy file info for %s", dst) } + if err := copyXAttrs(dst, src, o.xex, o.xeh); err != nil { + return errors.Wrap(err, "failed to copy xattrs") + } + for _, fi := range fis { source := filepath.Join(src, fi.Name()) target := filepath.Join(dst, fi.Name()) switch { case fi.IsDir(): - if err := copyDirectory(target, source, inodes); err != nil { + if err := copyDirectory(target, source, inodes, o); err != nil { return err } continue @@ -111,7 +165,7 @@ return errors.Wrap(err, "failed to copy file info") } - if err := copyXAttrs(target, source); err != nil { + if err := copyXAttrs(target, source, o.xex, o.xeh); err != nil { return errors.Wrap(err, "failed to copy xattrs") } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_linux.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_linux.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -51,7 +51,10 @@ } } - timespec := []unix.Timespec{unix.Timespec(StatAtime(st)), unix.Timespec(StatMtime(st))} + timespec := []unix.Timespec{ + unix.NsecToTimespec(syscall.TimespecToNsec(StatAtime(st))), + unix.NsecToTimespec(syscall.TimespecToNsec(StatMtime(st))), + } if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { return errors.Wrapf(err, "failed to utime %s", name) } @@ -59,6 +62,8 @@ return nil } +const maxSSizeT = int64(^uint(0) >> 1) + func copyFileContent(dst, src *os.File) error { st, err := src.Stat() if err != nil { @@ -71,7 +76,16 @@ dstFd := int(dst.Fd()) for size > 0 { - n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, int(size), 0) + // Ensure that we are never trying to copy more than SSIZE_MAX at a + // time and at the same time avoids overflows when the file is larger + // than 4GB on 32-bit systems. + var copySize int + if size > maxSSizeT { + copySize = int(maxSSizeT) + } else { + copySize = int(size) + } + n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0) if err != nil { if (err != unix.ENOSYS && err != unix.EXDEV) || !first { return errors.Wrap(err, "copy file range failed") @@ -90,18 +104,37 @@ return nil } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error { xattrKeys, err := sysx.LListxattr(src) if err != nil { - return errors.Wrapf(err, "failed to list xattrs on %s", src) + e := errors.Wrapf(err, "failed to list xattrs on %s", src) + if errorHandler != nil { + e = errorHandler(dst, src, "", e) + } + return e } for _, xattr := range xattrKeys { + if _, exclude := excludes[xattr]; exclude { + continue + } data, err := sysx.LGetxattr(src, xattr) if err != nil { - return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + if errorHandler != nil { + if e = errorHandler(dst, src, xattr, e); e == nil { + continue + } + } + return e } if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { - return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + if errorHandler != nil { + if e = errorHandler(dst, src, xattr, e); e == nil { + continue + } + } + return e } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build solaris darwin freebsd +// +build darwin freebsd openbsd solaris /* Copyright The containerd Authors. @@ -25,7 +25,6 @@ "github.com/containerd/continuity/sysx" "github.com/pkg/errors" - "golang.org/x/sys/unix" ) func copyFileInfo(fi os.FileInfo, name string) error { @@ -53,8 +52,7 @@ } } - timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)} - if err := syscall.UtimesNano(name, timespec); err != nil { + if err := utimesNano(name, StatAtime(st), StatMtime(st)); err != nil { return errors.Wrapf(err, "failed to utime %s", name) } @@ -69,28 +67,39 @@ return err } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error { xattrKeys, err := sysx.LListxattr(src) if err != nil { - return errors.Wrapf(err, "failed to list xattrs on %s", src) + e := errors.Wrapf(err, "failed to list xattrs on %s", src) + if errorHandler != nil { + e = errorHandler(dst, src, "", e) + } + return e } for _, xattr := range xattrKeys { + if _, exclude := excludes[xattr]; exclude { + continue + } data, err := sysx.LGetxattr(src, xattr) if err != nil { - return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + if errorHandler != nil { + if e = errorHandler(dst, src, xattr, e); e == nil { + continue + } + } + return e } if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { - return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + if errorHandler != nil { + if e = errorHandler(dst, src, xattr, e); e == nil { + continue + } + } + return e } } return nil } - -func copyDevice(dst string, fi os.FileInfo) error { - st, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - return errors.New("unsupported stat type") - } - return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev)) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_windows.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_windows.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/copy_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/copy_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -40,7 +40,7 @@ return err } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, excludes map[string]struct{}, errorHandler XAttrErrorHandler) error { return nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/du_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/du_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/du_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/du_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -25,6 +25,14 @@ "syscall" ) +// blocksUnitSize is the unit used by `st_blocks` in `stat` in bytes. +// See https://man7.org/linux/man-pages/man2/stat.2.html +// st_blocks +// This field indicates the number of blocks allocated to the +// file, in 512-byte units. (This may be smaller than +// st_size/512 when the file has holes.) +const blocksUnitSize = 512 + type inode struct { // TODO(stevvooe): Can probably reduce memory usage by not tracking // device, but we can leave this right for now. @@ -33,9 +41,9 @@ func newInode(stat *syscall.Stat_t) inode { return inode{ - // Dev is uint32 on darwin/bsd, uint64 on linux/solaris + // Dev is uint32 on darwin/bsd, uint64 on linux/solaris/freebsd dev: uint64(stat.Dev), // nolint: unconvert - // Ino is uint32 on bsd, uint64 on darwin/linux/solaris + // Ino is uint32 on bsd, uint64 on darwin/linux/solaris/freebsd ino: uint64(stat.Ino), // nolint: unconvert } } @@ -59,10 +67,11 @@ default: } - inoKey := newInode(fi.Sys().(*syscall.Stat_t)) + stat := fi.Sys().(*syscall.Stat_t) + inoKey := newInode(stat) if _, ok := inodes[inoKey]; !ok { inodes[inoKey] = struct{}{} - size += fi.Size() + size += stat.Blocks * blocksUnitSize } return nil @@ -89,10 +98,11 @@ } if kind == ChangeKindAdd || kind == ChangeKindModify { - inoKey := newInode(fi.Sys().(*syscall.Stat_t)) + stat := fi.Sys().(*syscall.Stat_t) + inoKey := newInode(stat) if _, ok := inodes[inoKey]; !ok { inodes[inoKey] = struct{}{} - size += fi.Size() + size += stat.Blocks * blocksUnitSize } return nil diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/compare.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/compare.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/compare.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/compare.go 2022-01-05 17:30:58.000000000 +0000 @@ -49,15 +49,7 @@ diff := diffResourceList(m1.Resources, m2.Resources) if diff.HasDiff() { - if len(diff.Deletions) != 0 { - return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String()) - } - // TODO: Also skip Recycle Bin contents in Windows layers which is used to store deleted files in some cases - for _, add := range diff.Additions { - if ok, _ := metadataFiles[add.Path()]; !ok { - return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String()) - } - } + return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String()) } return nil diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package fstest // TODO: Any more metadata files generated by Windows layers? +// TODO: Also skip Recycle Bin contents in Windows layers which is used to store deleted files in some cases var metadataFiles = map[string]bool{ "\\System Volume Information": true, "\\WcSandboxState": true, diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go 2022-01-05 17:30:58.000000000 +0000 @@ -42,7 +42,17 @@ } func (l resourceListDifference) HasDiff() bool { - return len(l.Additions) > 0 || len(l.Deletions) > 0 || len(l.Updates) > 0 + if len(l.Deletions) > 0 || len(l.Updates) > 0 || (len(metadataFiles) == 0 && len(l.Additions) > 0) { + return true + } + + for _, add := range l.Additions { + if ok := metadataFiles[add.Path()]; !ok { + return true + } + } + + return false } func (l resourceListDifference) String() string { @@ -56,7 +66,7 @@ for _, upt := range l.Updates { fmt.Fprintf(buf, "~ %s\n", upt.String()) } - return string(buf.Bytes()) + return buf.String() } // diffManifest compares two resource lists and returns the list diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/file.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/file.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/file.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/file.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,9 +20,9 @@ "bytes" "io" "math/rand" - "net" "os" "path/filepath" + "syscall" "time" ) @@ -158,11 +158,15 @@ func CreateSocket(name string, perm os.FileMode) Applier { return applyFn(func(root string) error { fullPath := filepath.Join(root, name) - ln, err := net.Listen("unix", fullPath) + fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) if err != nil { return err } - defer ln.Close() + defer syscall.Close(fd) + sa := &syscall.SockaddrUnix{Name: fullPath} + if err := syscall.Bind(fd, sa); err != nil { + return err + } return os.Chmod(fullPath, perm) }) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/file_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/file_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/file_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/file_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,7 +29,8 @@ // SetXAttr sets the xatter for the file func SetXAttr(name, key, value string) Applier { return applyFn(func(root string) error { - return sysx.LSetxattr(name, key, []byte(value), 0) + path := filepath.Join(root, name) + return sysx.LSetxattr(path, key, []byte(value), 0) }) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/testsuite.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/testsuite.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/fstest/testsuite.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/fstest/testsuite.go 2022-01-05 17:30:58.000000000 +0000 @@ -90,7 +90,7 @@ Symlink("libnothing.so", "/usr/local/lib/libnothing.so.2"), CreateDir("/home", 0755), CreateDir("/home/derek", 0700), - CreateDir("/var/run/socket", 0700), + // TODO: CreateSocket: how should Sockets be handled in continuity? ) // basicTest covers basic operations @@ -210,7 +210,7 @@ } // Hardlink name before with modification - // Tests link is created for unmodified files when new hardlinked file is seen first + // Tests link is created for unmodified files when a new hard linked file is seen first hardlinkBeforeUnmodified = []Applier{ baseApplier, Apply( diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/path.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/path.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/path.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/path.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,7 +22,6 @@ "io" "os" "path/filepath" - "strings" "github.com/pkg/errors" ) @@ -47,9 +46,8 @@ if upper == nil { return ChangeKindDelete, lower.path } - // TODO: compare by directory - switch i := strings.Compare(lower.path, upper.path); { + switch i := directoryCompare(lower.path, upper.path); { case i < 0: // File in lower that is not in upper return ChangeKindDelete, lower.path @@ -61,6 +59,35 @@ } } +func directoryCompare(a, b string) int { + l := len(a) + if len(b) < l { + l = len(b) + } + for i := 0; i < l; i++ { + c1, c2 := a[i], b[i] + if c1 == filepath.Separator { + c1 = byte(0) + } + if c2 == filepath.Separator { + c2 = byte(0) + } + if c1 < c2 { + return -1 + } + if c1 > c2 { + return +1 + } + } + if len(a) < len(b) { + return -1 + } + if len(a) > len(b) { + return +1 + } + return 0 +} + func sameFile(f1, f2 *currentPath) (bool, error) { if os.SameFile(f1.f, f2.f) { return true, nil @@ -90,15 +117,13 @@ // If the timestamp may have been truncated in both of the // files, check content of file to determine difference if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 { - var eq bool if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink { - eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath) - } else if f1.f.Size() > 0 { - eq, err = compareFileContent(f1.fullPath, f2.fullPath) + return compareSymlinkTarget(f1.fullPath, f2.fullPath) } - if err != nil || !eq { - return eq, err + if f1.f.Size() == 0 { // if file sizes are zero length, the files are the same by definition + return true, nil } + return compareFileContent(f1.fullPath, f2.fullPath) } else if t1.Nanosecond() != t2.Nanosecond() { return false, nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_bsd.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_bsd.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_bsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_bsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -// +build darwin freebsd - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package fs - -import ( - "syscall" - "time" -) - -// StatAtime returns the access time from a stat struct -func StatAtime(st *syscall.Stat_t) syscall.Timespec { - return st.Atimespec -} - -// StatCtime returns the created time from a stat struct -func StatCtime(st *syscall.Stat_t) syscall.Timespec { - return st.Ctimespec -} - -// StatMtime returns the modified time from a stat struct -func StatMtime(st *syscall.Stat_t) syscall.Timespec { - return st.Mtimespec -} - -// StatATimeAsTime returns the access time as a time.Time -func StatATimeAsTime(st *syscall.Stat_t) time.Time { - return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_darwinfreebsd.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_darwinfreebsd.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_darwinfreebsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_darwinfreebsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +// +build darwin freebsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fs + +import ( + "syscall" + "time" +) + +// StatAtime returns the access time from a stat struct +func StatAtime(st *syscall.Stat_t) syscall.Timespec { + return st.Atimespec +} + +// StatCtime returns the created time from a stat struct +func StatCtime(st *syscall.Stat_t) syscall.Timespec { + return st.Ctimespec +} + +// StatMtime returns the modified time from a stat struct +func StatMtime(st *syscall.Stat_t) syscall.Timespec { + return st.Mtimespec +} + +// StatATimeAsTime returns the access time as a time.Time +func StatATimeAsTime(st *syscall.Stat_t) time.Time { + return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_linux.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_linux.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package fs - -import ( - "syscall" - "time" -) - -// StatAtime returns the Atim -func StatAtime(st *syscall.Stat_t) syscall.Timespec { - return st.Atim -} - -// StatCtime returns the Ctim -func StatCtime(st *syscall.Stat_t) syscall.Timespec { - return st.Ctim -} - -// StatMtime returns the Mtim -func StatMtime(st *syscall.Stat_t) syscall.Timespec { - return st.Mtim -} - -// StatATimeAsTime returns st.Atim as a time.Time -func StatATimeAsTime(st *syscall.Stat_t) time.Time { - // The int64 conversions ensure the line compiles for 32-bit systems as well. - return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_linuxopenbsd.go containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_linuxopenbsd.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/fs/stat_linuxopenbsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/fs/stat_linuxopenbsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,45 @@ +// +build linux openbsd + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fs + +import ( + "syscall" + "time" +) + +// StatAtime returns the Atim +func StatAtime(st *syscall.Stat_t) syscall.Timespec { + return st.Atim +} + +// StatCtime returns the Ctim +func StatCtime(st *syscall.Stat_t) syscall.Timespec { + return st.Ctim +} + +// StatMtime returns the Mtim +func StatMtime(st *syscall.Stat_t) syscall.Timespec { + return st.Mtim +} + +// StatATimeAsTime returns st.Atim as a time.Time +func StatATimeAsTime(st *syscall.Stat_t) time.Time { + // The int64 conversions ensure the line compiles for 32-bit systems as well. + return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/.gitignore containerd-1.5.9/vendor/github.com/containerd/continuity/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/continuity/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +bin + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/continuity/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/continuity/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,18 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +run: + timeout: 3m diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/go.mod containerd-1.5.9/vendor/github.com/containerd/continuity/go.mod --- containerd-1.2.6/vendor/github.com/containerd/continuity/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,15 @@ +module github.com/containerd/continuity + +go 1.13 + +require ( + bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898 + github.com/dustin/go-humanize v1.0.0 + github.com/golang/protobuf v1.3.5 + github.com/opencontainers/go-digest v1.0.0 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + github.com/spf13/cobra v1.0.0 + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/go.sum containerd-1.5.9/vendor/github.com/containerd/continuity/go.sum --- containerd-1.2.6/vendor/github.com/containerd/continuity/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,148 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898 h1:SC+c6A1qTFstO9qmB86mPV2IpYme/2ZoEQ0hrP+wo+Q= +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/groups_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/groups_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/groups_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/groups_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -14,6 +14,7 @@ limitations under the License. */ +//nolint:unused,deadcode package continuity import ( diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/hardlinks.go containerd-1.5.9/vendor/github.com/containerd/continuity/hardlinks.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/hardlinks.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/hardlinks.go 2022-01-05 17:30:58.000000000 +0000 @@ -53,7 +53,7 @@ } // Merge processes the current state of the hardlink manager and merges any -// shared nodes into hardlinked resources. +// shared nodes into hard linked resources. func (hlm *hardlinkManager) Merge() ([]Resource, error) { var resources []Resource for key, linked := range hlm.hardlinks { diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/hardlinks_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/hardlinks_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/hardlinks_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/hardlinks_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -48,5 +48,6 @@ return hardlinkKey{}, errNotAHardLink } + //nolint:unconvert return hardlinkKey{dev: uint64(sys.Dev), inode: uint64(sys.Ino)}, nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/LICENSE containerd-1.5.9/vendor/github.com/containerd/continuity/LICENSE --- containerd-1.2.6/vendor/github.com/containerd/continuity/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,7 @@ + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -175,28 +176,16 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} + Copyright The containerd Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + 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. - diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/.mailmap containerd-1.5.9/vendor/github.com/containerd/continuity/.mailmap --- containerd-1.2.6/vendor/github.com/containerd/continuity/.mailmap 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/.mailmap 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +Stephen J Day Stephen Day diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/Makefile containerd-1.5.9/vendor/github.com/containerd/continuity/Makefile --- containerd-1.2.6/vendor/github.com/containerd/continuity/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,82 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Set an output prefix, which is the local directory if not specified +PREFIX?=$(shell pwd) + +# Used to populate version variable in main package. +VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always) + +GO_LDFLAGS=-ldflags "-X `go list -mod=vendor ./version`.Version=$(VERSION)" + +PKG=github.com/containerd/continuity + +PACKAGES=$(shell go list -mod=vendor ./... | grep -v /vendor/) +TEST_REQUIRES_ROOT_PACKAGES=$(filter \ + ${PACKAGES}, \ + $(shell \ + for f in $$(git grep -l testutil.RequiresRoot | grep -v Makefile); do \ + d="$$(dirname $$f)"; \ + [ "$$d" = "." ] && echo "${PKG}" && continue; \ + echo "${PKG}/$$d"; \ + done | sort -u) \ + ) + +.PHONY: clean all lint build test binaries +.DEFAULT: default + +all: AUTHORS clean lint build test binaries + +AUTHORS: .mailmap .git/HEAD + git log --format='%aN <%aE>' | sort -fu > $@ + +# This only needs to be generated by hand when cutting full releases. +version/version.go: + ./version/version.sh > $@ + +${PREFIX}/bin/continuity: version/version.go $(shell find . -type f -name '*.go') + @echo "+ $@" + @go build -mod=vendor -o $@ ${GO_LDFLAGS} ${GO_GCFLAGS} ./cmd/continuity + +generate: + go generate -mod=vendor $(PACKAGES) + +lint: + @echo "+ $@" + @golangci-lint run + +build: + @echo "+ $@" + @go build -mod=vendor -v ${GO_LDFLAGS} $(PACKAGES) + +test: + @echo "+ $@" + @go test -mod=vendor $(PACKAGES) + +root-test: + @echo "+ $@" + @go test ${TEST_REQUIRES_ROOT_PACKAGES} -test.root + +test-compile: + @echo "+ $@" + @for pkg in $(PACKAGES); do go test -mod=vendor -c $$pkg; done + +binaries: ${PREFIX}/bin/continuity + @echo "+ $@" + @if [ x$$GOOS = xwindows ]; then echo "+ continuity -> continuity.exe"; mv ${PREFIX}/bin/continuity ${PREFIX}/bin/continuity.exe; fi + +clean: + @echo "+ $@" + @rm -rf "${PREFIX}/bin/continuity" "${PREFIX}/bin/continuity.exe" + diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/manifest.go containerd-1.5.9/vendor/github.com/containerd/continuity/manifest.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/manifest.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/manifest.go 2022-01-05 17:30:58.000000000 +0000 @@ -114,11 +114,13 @@ } // merge and post-process the hardlinks. + // nolint:misspell hardlinked, err := hardlinks.Merge() if err != nil { return nil, err } + // nolint:misspell for _, resource := range hardlinked { resourcesByPath[resource.Path()] = resource } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/proto/manifest.pb.go containerd-1.5.9/vendor/github.com/containerd/continuity/proto/manifest.pb.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/proto/manifest.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/proto/manifest.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: manifest.proto -// DO NOT EDIT! /* Package proto is a generated protocol buffer package. @@ -97,6 +96,83 @@ func (*Resource) ProtoMessage() {} func (*Resource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *Resource) GetPath() []string { + if m != nil { + return m.Path + } + return nil +} + +func (m *Resource) GetUid() int64 { + if m != nil { + return m.Uid + } + return 0 +} + +func (m *Resource) GetGid() int64 { + if m != nil { + return m.Gid + } + return 0 +} + +func (m *Resource) GetUser() string { + if m != nil { + return m.User + } + return "" +} + +func (m *Resource) GetGroup() string { + if m != nil { + return m.Group + } + return "" +} + +func (m *Resource) GetMode() uint32 { + if m != nil { + return m.Mode + } + return 0 +} + +func (m *Resource) GetSize() uint64 { + if m != nil { + return m.Size + } + return 0 +} + +func (m *Resource) GetDigest() []string { + if m != nil { + return m.Digest + } + return nil +} + +func (m *Resource) GetTarget() string { + if m != nil { + return m.Target + } + return "" +} + +func (m *Resource) GetMajor() uint64 { + if m != nil { + return m.Major + } + return 0 +} + +func (m *Resource) GetMinor() uint64 { + if m != nil { + return m.Minor + } + return 0 +} + func (m *Resource) GetXattr() []*XAttr { if m != nil { return m.Xattr @@ -124,6 +200,20 @@ func (*XAttr) ProtoMessage() {} func (*XAttr) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *XAttr) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *XAttr) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + // ADSEntry encodes information for a Windows Alternate Data Stream. type ADSEntry struct { // Name specifices the stream name. @@ -147,6 +237,27 @@ func (*ADSEntry) ProtoMessage() {} func (*ADSEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (m *ADSEntry) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ADSEntry) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *ADSEntry) GetDigest() string { + if m != nil { + return m.Digest + } + return "" +} + func init() { proto1.RegisterType((*Manifest)(nil), "proto.Manifest") proto1.RegisterType((*Resource)(nil), "proto.Resource") @@ -158,7 +269,7 @@ var fileDescriptor0 = []byte{ // 317 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x90, 0x4f, 0x4b, 0xf3, 0x40, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0x4f, 0x4b, 0xf3, 0x40, 0x10, 0xc6, 0x49, 0x93, 0xf4, 0x4d, 0xa7, 0xed, 0xab, 0x2c, 0x52, 0xe6, 0x18, 0x73, 0x0a, 0x08, 0x15, 0xf4, 0xe0, 0xb9, 0xa2, 0x17, 0xc1, 0xcb, 0x7a, 0xf1, 0xba, 0xba, 0x6b, 0x5c, 0x21, 0xd9, 0xb0, 0xd9, 0x80, 0xfa, 0xe5, 0xfc, 0x6a, 0x32, 0xb3, 0x69, 0xd1, 0x9b, 0xa7, 0x3c, 0xcf, 0x6f, diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/README.md containerd-1.5.9/vendor/github.com/containerd/continuity/README.md --- containerd-1.2.6/vendor/github.com/containerd/continuity/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -63,6 +63,10 @@ $ ./bin/continuity verify . /tmp/a.pb ``` +## Platforms + +continuity primarily targets Linux. continuity may compile for and work on +other operating systems, but those platforms are not tested. ## Contribution Guide ### Building Proto Package @@ -72,3 +76,13 @@ ```console $ go generate ./proto ``` + +## Project details + +continuity is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/syscallx/syscall_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/syscallx/syscall_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/syscallx/syscall_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/syscallx/syscall_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -// +build !windows - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package syscallx - -import "syscall" - -// Readlink returns the destination of the named symbolic link. -func Readlink(path string, buf []byte) (n int, err error) { - return syscall.Readlink(path, buf) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/syscallx/syscall_windows.go containerd-1.5.9/vendor/github.com/containerd/continuity/syscallx/syscall_windows.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/syscallx/syscall_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/syscallx/syscall_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package syscallx - -import ( - "syscall" - "unsafe" -) - -type reparseDataBuffer struct { - ReparseTag uint32 - ReparseDataLength uint16 - Reserved uint16 - - // GenericReparseBuffer - reparseBuffer byte -} - -type mountPointReparseBuffer struct { - SubstituteNameOffset uint16 - SubstituteNameLength uint16 - PrintNameOffset uint16 - PrintNameLength uint16 - PathBuffer [1]uint16 -} - -type symbolicLinkReparseBuffer struct { - SubstituteNameOffset uint16 - SubstituteNameLength uint16 - PrintNameOffset uint16 - PrintNameLength uint16 - Flags uint32 - PathBuffer [1]uint16 -} - -const ( - _IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 - _SYMLINK_FLAG_RELATIVE = 1 -) - -// Readlink returns the destination of the named symbolic link. -func Readlink(path string, buf []byte) (n int, err error) { - fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING, - syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) - if err != nil { - return -1, err - } - defer syscall.CloseHandle(fd) - - rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE) - var bytesReturned uint32 - err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) - if err != nil { - return -1, err - } - - rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) - var s string - switch rdb.ReparseTag { - case syscall.IO_REPARSE_TAG_SYMLINK: - data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) - p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) - s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) - if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 { - if len(s) >= 4 && s[:4] == `\??\` { - s = s[4:] - switch { - case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar - // do nothing - case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar - s = `\\` + s[4:] - default: - // unexpected; do nothing - } - } else { - // unexpected; do nothing - } - } - case _IO_REPARSE_TAG_MOUNT_POINT: - data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) - p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) - s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) - if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar - if len(s) < 48 || s[:11] != `\??\Volume{` { - s = s[4:] - } - } else { - // unexpected; do nothing - } - default: - // the path is not a symlink or junction but another type of reparse - // point - return -1, syscall.ENOENT - } - n = copy(buf, []byte(s)) - - return n, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/file_posix.go containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/file_posix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/file_posix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/file_posix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package sysx - -import ( - "os" - "path/filepath" - - "github.com/containerd/continuity/syscallx" -) - -// Readlink returns the destination of the named symbolic link. -// If there is an error, it will be of type *PathError. -func Readlink(name string) (string, error) { - for len := 128; ; len *= 2 { - b := make([]byte, len) - n, e := fixCount(syscallx.Readlink(fixLongPath(name), b)) - if e != nil { - return "", &os.PathError{Op: "readlink", Path: name, Err: e} - } - if n < len { - return string(b[0:n]), nil - } - } -} - -// Many functions in package syscall return a count of -1 instead of 0. -// Using fixCount(call()) instead of call() corrects the count. -func fixCount(n int, err error) (int, error) { - if n < 0 { - n = 0 - } - return n, err -} - -// fixLongPath returns the extended-length (\\?\-prefixed) form of -// path when needed, in order to avoid the default 260 character file -// path limit imposed by Windows. If path is not easily converted to -// the extended-length form (for example, if path is a relative path -// or contains .. elements), or is short enough, fixLongPath returns -// path unmodified. -// -// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath -func fixLongPath(path string) string { - // Do nothing (and don't allocate) if the path is "short". - // Empirically (at least on the Windows Server 2013 builder), - // the kernel is arbitrarily okay with < 248 bytes. That - // matches what the docs above say: - // "When using an API to create a directory, the specified - // path cannot be so long that you cannot append an 8.3 file - // name (that is, the directory name cannot exceed MAX_PATH - // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. - // - // The MSDN docs appear to say that a normal path that is 248 bytes long - // will work; empirically the path must be less then 248 bytes long. - if len(path) < 248 { - // Don't fix. (This is how Go 1.7 and earlier worked, - // not automatically generating the \\?\ form) - return path - } - - // The extended form begins with \\?\, as in - // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. - // The extended form disables evaluation of . and .. path - // elements and disables the interpretation of / as equivalent - // to \. The conversion here rewrites / to \ and elides - // . elements as well as trailing or duplicate separators. For - // simplicity it avoids the conversion entirely for relative - // paths or paths containing .. elements. For now, - // \\server\share paths are not converted to - // \\?\UNC\server\share paths because the rules for doing so - // are less well-specified. - if len(path) >= 2 && path[:2] == `\\` { - // Don't canonicalize UNC paths. - return path - } - if !filepath.IsAbs(path) { - // Relative path - return path - } - - const prefix = `\\?` - - pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) - copy(pathbuf, prefix) - n := len(path) - r, w := 0, len(prefix) - for r < n { - switch { - case os.IsPathSeparator(path[r]): - // empty block - r++ - case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): - // /./ - r++ - case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): - // /../ is currently unhandled - return path - default: - pathbuf[w] = '\\' - w++ - for ; r < n && !os.IsPathSeparator(path[r]); r++ { - pathbuf[w] = path[r] - w++ - } - } - } - // A drive's root directory needs a trailing \ - if w == len(`\\?\c:`) { - pathbuf[w] = '\\' - w++ - } - return string(pathbuf[:w]) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/generate.sh containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/generate.sh --- containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/generate.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/generate.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +#!/bin/bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -e + +mksyscall="$(go env GOROOT)/src/syscall/mksyscall.pl" + +fix() { + sed 's,^package syscall$,package sysx,' \ + | sed 's,^import "unsafe"$,import (\n\t"syscall"\n\t"unsafe"\n),' \ + | gofmt -r='BytePtrFromString -> syscall.BytePtrFromString' \ + | gofmt -r='Syscall6 -> syscall.Syscall6' \ + | gofmt -r='Syscall -> syscall.Syscall' \ + | gofmt -r='SYS_GETXATTR -> syscall.SYS_GETXATTR' \ + | gofmt -r='SYS_LISTXATTR -> syscall.SYS_LISTXATTR' \ + | gofmt -r='SYS_SETXATTR -> syscall.SYS_SETXATTR' \ + | gofmt -r='SYS_REMOVEXATTR -> syscall.SYS_REMOVEXATTR' \ + | gofmt -r='SYS_LGETXATTR -> syscall.SYS_LGETXATTR' \ + | gofmt -r='SYS_LLISTXATTR -> syscall.SYS_LLISTXATTR' \ + | gofmt -r='SYS_LSETXATTR -> syscall.SYS_LSETXATTR' \ + | gofmt -r='SYS_LREMOVEXATTR -> syscall.SYS_LREMOVEXATTR' +} + +if [ "$GOARCH" == "" ] || [ "$GOOS" == "" ]; then + echo "Must specify \$GOARCH and \$GOOS" + exit 1 +fi + +mkargs="" + +if [ "$GOARCH" == "386" ] || [ "$GOARCH" == "arm" ]; then + mkargs="-l32" +fi + +for f in "$@"; do + $mksyscall $mkargs "${f}_${GOOS}.go" | fix > "${f}_${GOOS}_${GOARCH}.go" +done + diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/nodata_unix.go containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/nodata_unix.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/nodata_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/nodata_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build darwin freebsd +// +build darwin freebsd openbsd /* Copyright The containerd Authors. diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/xattr.go containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/xattr.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/xattr.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/xattr.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,6 @@ import ( "bytes" - "syscall" "golang.org/x/sys/unix" ) @@ -66,60 +65,53 @@ return getxattrAll(path, attr, unix.Lgetxattr) } -const defaultXattrBufferSize = 5 +const defaultXattrBufferSize = 128 type listxattrFunc func(path string, dest []byte) (int, error) func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) { - var p []byte // nil on first execution - - for { - n, err := listFunc(path, p) // first call gets buffer size. + buf := make([]byte, defaultXattrBufferSize) + n, err := listFunc(path, buf) + for err == unix.ERANGE { + // Buffer too small, use zero-sized buffer to get the actual size + n, err = listFunc(path, []byte{}) if err != nil { return nil, err } + buf = make([]byte, n) + n, err = listFunc(path, buf) + } + if err != nil { + return nil, err + } - if n > len(p) { - p = make([]byte, n) - continue - } - - p = p[:n] - - ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0}) - var entries []string - for _, p := range ps { - s := string(p) - if s != "" { - entries = append(entries, s) - } + ps := bytes.Split(bytes.TrimSuffix(buf[:n], []byte{0}), []byte{0}) + var entries []string + for _, p := range ps { + if len(p) > 0 { + entries = append(entries, string(p)) } - - return entries, nil } + + return entries, nil } type getxattrFunc func(string, string, []byte) (int, error) func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) { - p := make([]byte, defaultXattrBufferSize) - for { - n, err := getFunc(path, attr, p) + buf := make([]byte, defaultXattrBufferSize) + n, err := getFunc(path, attr, buf) + for err == unix.ERANGE { + // Buffer too small, use zero-sized buffer to get the actual size + n, err = getFunc(path, attr, []byte{}) if err != nil { - if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE { - p = make([]byte, len(p)*2) // this can't be ideal. - continue // try again! - } - return nil, err } - - // realloc to correct size and repeat - if n > len(p) { - p = make([]byte, n) - continue - } - - return p[:n], nil + buf = make([]byte, n) + n, err = getFunc(path, attr, buf) + } + if err != nil { + return nil, err } + return buf[:n], nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,7 +23,7 @@ "runtime" ) -var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS) +var errUnsupported = errors.New("extended attributes unsupported on " + runtime.GOOS) // Listxattr calls syscall listxattr and reads all content // and returns a string array @@ -33,17 +33,17 @@ // Removexattr calls syscall removexattr func Removexattr(path string, attr string) (err error) { - return unsupported + return errUnsupported } // Setxattr calls syscall setxattr func Setxattr(path string, attr string, data []byte, flags int) (err error) { - return unsupported + return errUnsupported } // Getxattr calls syscall getxattr func Getxattr(path, attr string) ([]byte, error) { - return []byte{}, unsupported + return []byte{}, errUnsupported } // LListxattr lists xattrs, not following symlinks @@ -53,12 +53,12 @@ // LRemovexattr removes an xattr, not following symlinks func LRemovexattr(path string, attr string) (err error) { - return unsupported + return errUnsupported } // LSetxattr sets an xattr, not following symlinks func LSetxattr(path string, attr string, data []byte, flags int) (err error) { - return unsupported + return errUnsupported } // LGetxattr gets an xattr, not following symlinks diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go containerd-1.5.9/vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go --- containerd-1.2.6/vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,23 +23,24 @@ "os" "os/exec" "strings" + "syscall" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -// New creates a loopback device, and returns its device name (/dev/loopX), and its clean-up function. -func New(size int64) (string, func() error, error) { +// New creates a loopback device +func New(size int64) (*Loopback, error) { // create temporary file for the disk image file, err := ioutil.TempFile("", "containerd-test-loopback") if err != nil { - return "", nil, errors.Wrap(err, "could not create temporary file for loopback") + return nil, errors.Wrap(err, "could not create temporary file for loopback") } if err := file.Truncate(size); err != nil { file.Close() os.Remove(file.Name()) - return "", nil, errors.Wrap(err, "failed to resize temp file") + return nil, errors.Wrap(err, "failed to resize temp file") } file.Close() @@ -48,7 +49,7 @@ p, err := losetup.Output() if err != nil { os.Remove(file.Name()) - return "", nil, errors.Wrap(err, "loopback setup failed") + return nil, errors.Wrap(err, "loopback setup failed") } deviceName := strings.TrimSpace(string(p)) @@ -68,5 +69,47 @@ return os.Remove(file.Name()) } - return deviceName, cleanup, nil + l := Loopback{ + File: file.Name(), + Device: deviceName, + close: cleanup, + } + return &l, nil +} + +// Loopback device +type Loopback struct { + // File is the underlying sparse file + File string + // Device is /dev/loopX + Device string + close func() error +} + +// SoftSize returns st_size +func (l *Loopback) SoftSize() (int64, error) { + st, err := os.Stat(l.File) + if err != nil { + return 0, err + } + return st.Size(), nil +} + +// HardSize returns st_blocks * 512; see stat(2) +func (l *Loopback) HardSize() (int64, error) { + st, err := os.Stat(l.File) + if err != nil { + return 0, err + } + st2, ok := st.Sys().(*syscall.Stat_t) + if !ok { + return 0, errors.New("st.Sys() is not a *syscall.Stat_t") + } + // NOTE: st_blocks has nothing to do with st_blksize; see stat(2) + return st2.Blocks * 512, nil +} + +// Close detaches the device and removes the underlying file +func (l *Loopback) Close() error { + return l.close() } diff -Nru containerd-1.2.6/vendor/github.com/containerd/continuity/vendor.conf containerd-1.5.9/vendor/github.com/containerd/continuity/vendor.conf --- containerd-1.2.6/vendor/github.com/containerd/continuity/vendor.conf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/continuity/vendor.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -bazil.org/fuse 371fbbdaa8987b715bdd21d6adc4c9b20155f748 -github.com/dustin/go-humanize bb3d318650d48840a39aa21a027c6630e198e626 -github.com/golang/protobuf 1e59b77b52bf8e4b449a57e6f79f21226d571845 -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -github.com/opencontainers/go-digest 279bed98673dd5bef374d3b6e4b09e2af76183bf -github.com/pkg/errors f15c970de5b76fac0b59abb32d62c17cc7bed265 -github.com/sirupsen/logrus 89742aefa4b206dcf400792f3bd35b542998eb3b -github.com/spf13/cobra 2da4a54c5ceefcee7ca5dd0eea1e18a3b6366489 -github.com/spf13/pflag 4c012f6dcd9546820e378d0bdda4d8fc772cdfea -golang.org/x/crypto 9f005a07e0d31d45e6656d241bb5c0f2efd4bc94 -golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2 -golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c -golang.org/x/sys 77b0e4315053a57ed2962443614bdb28db152054 diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/cli/cli.go containerd-1.5.9/vendor/github.com/containerd/cri/cli/cli.go --- containerd-1.2.6/vendor/github.com/containerd/cri/cli/cli.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/cli/cli.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* -Copyright 2018 The containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cli - -import ( - gocontext "context" - "fmt" - "path/filepath" - - api "github.com/containerd/cri/pkg/api/v1" - "github.com/containerd/cri/pkg/client" - "github.com/pkg/errors" - "github.com/urfave/cli" -) - -// Command is the cli command for cri plugin. -var Command = cli.Command{ - Name: "cri", - Usage: "interact with cri plugin", - Subcommands: cli.Commands{ - loadCommand, - }, -} - -var loadCommand = cli.Command{ - Name: "load", - Usage: "load one or more images from tar archives.", - ArgsUsage: "[flags] TAR [TAR, ...]", - Description: "load one or more images from tar archives.", - Flags: []cli.Flag{}, - Action: func(context *cli.Context) error { - var ( - ctx = gocontext.Background() - address = context.GlobalString("address") - timeout = context.GlobalDuration("timeout") - cancel gocontext.CancelFunc - ) - if timeout > 0 { - ctx, cancel = gocontext.WithTimeout(gocontext.Background(), timeout) - } else { - ctx, cancel = gocontext.WithCancel(ctx) - } - defer cancel() - cl, err := client.NewCRIPluginClient(ctx, address) - if err != nil { - return errors.Wrap(err, "failed to create grpc client") - } - for _, path := range context.Args() { - absPath, err := filepath.Abs(path) - if err != nil { - return errors.Wrap(err, "failed to get absolute path") - } - res, err := cl.LoadImage(ctx, &api.LoadImageRequest{FilePath: absPath}) - if err != nil { - return errors.Wrap(err, "failed to load image") - } - images := res.GetImages() - for _, image := range images { - fmt.Println("Loaded image:", image) - } - } - return nil - }, -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/cri.go containerd-1.5.9/vendor/github.com/containerd/cri/cri.go --- containerd-1.2.6/vendor/github.com/containerd/cri/cri.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/cri.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cri - -import ( - "flag" - "path/filepath" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/api/services/containers/v1" - "github.com/containerd/containerd/api/services/diff/v1" - "github.com/containerd/containerd/api/services/images/v1" - "github.com/containerd/containerd/api/services/namespaces/v1" - "github.com/containerd/containerd/api/services/tasks/v1" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/leases" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" - "github.com/containerd/containerd/services" - "github.com/containerd/containerd/snapshots" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - - criconfig "github.com/containerd/cri/pkg/config" - "github.com/containerd/cri/pkg/constants" - "github.com/containerd/cri/pkg/server" -) - -// TODO(random-liu): Use github.com/pkg/errors for our errors. -// Register CRI service plugin -func init() { - config := criconfig.DefaultConfig() - plugin.Register(&plugin.Registration{ - Type: plugin.GRPCPlugin, - ID: "cri", - Config: &config, - Requires: []plugin.Type{ - plugin.ServicePlugin, - }, - InitFn: initCRIService, - }) -} - -func initCRIService(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = []imagespec.Platform{platforms.DefaultSpec()} - ic.Meta.Exports = map[string]string{"CRIVersion": constants.CRIVersion} - ctx := ic.Context - pluginConfig := ic.Config.(*criconfig.PluginConfig) - c := criconfig.Config{ - PluginConfig: *pluginConfig, - ContainerdRootDir: filepath.Dir(ic.Root), - ContainerdEndpoint: ic.Address, - RootDir: ic.Root, - StateDir: ic.State, - } - log.G(ctx).Infof("Start cri plugin with config %+v", c) - - if err := validateConfig(&c); err != nil { - return nil, errors.Wrap(err, "invalid config") - } - - if err := setGLogLevel(); err != nil { - return nil, errors.Wrap(err, "failed to set glog level") - } - - servicesOpts, err := getServicesOpts(ic) - if err != nil { - return nil, errors.Wrap(err, "failed to get services") - } - - log.G(ctx).Info("Connect containerd service") - client, err := containerd.New( - "", - containerd.WithDefaultNamespace(constants.K8sContainerdNamespace), - containerd.WithServices(servicesOpts...), - ) - if err != nil { - return nil, errors.Wrap(err, "failed to create containerd client") - } - - s, err := server.NewCRIService(c, client) - if err != nil { - return nil, errors.Wrap(err, "failed to create CRI service") - } - - go func() { - if err := s.Run(); err != nil { - log.G(ctx).WithError(err).Fatal("Failed to run CRI service") - } - // TODO(random-liu): Whether and how we can stop containerd. - }() - return s, nil -} - -// validateConfig validates the given configuration. -func validateConfig(c *criconfig.Config) error { - // It is an error to provide both an UntrustedWorkloadRuntime & define an 'untrusted' runtime. - if _, ok := c.ContainerdConfig.Runtimes[criconfig.RuntimeUntrusted]; ok { - if c.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { - return errors.New("conflicting definitions: configuration includes untrusted_workload_runtime and runtimes['untrusted']") - } - } - - return nil -} - -// getServicesOpts get service options from plugin context. -func getServicesOpts(ic *plugin.InitContext) ([]containerd.ServicesOpt, error) { - plugins, err := ic.GetByType(plugin.ServicePlugin) - if err != nil { - return nil, errors.Wrap(err, "failed to get service plugin") - } - - opts := []containerd.ServicesOpt{ - containerd.WithEventService(ic.Events), - } - for s, fn := range map[string]func(interface{}) containerd.ServicesOpt{ - services.ContentService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithContentStore(s.(content.Store)) - }, - services.ImagesService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithImageService(s.(images.ImagesClient)) - }, - services.SnapshotsService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithSnapshotters(s.(map[string]snapshots.Snapshotter)) - }, - services.ContainersService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithContainerService(s.(containers.ContainersClient)) - }, - services.TasksService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithTaskService(s.(tasks.TasksClient)) - }, - services.DiffService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithDiffService(s.(diff.DiffClient)) - }, - services.NamespacesService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithNamespaceService(s.(namespaces.NamespacesClient)) - }, - services.LeasesService: func(s interface{}) containerd.ServicesOpt { - return containerd.WithLeasesService(s.(leases.Manager)) - }, - } { - p := plugins[s] - if p == nil { - return nil, errors.Errorf("service %q not found", s) - } - i, err := p.Instance() - if err != nil { - return nil, errors.Wrapf(err, "failed to get instance of service %q", s) - } - if i == nil { - return nil, errors.Errorf("instance of service %q not found", s) - } - opts = append(opts, fn(i)) - } - return opts, nil -} - -// Set glog level. -func setGLogLevel() error { - l := logrus.GetLevel() - if err := flag.Set("logtostderr", "true"); err != nil { - return err - } - switch l { - case log.TraceLevel: - return flag.Set("v", "5") - case logrus.DebugLevel: - return flag.Set("v", "4") - case logrus.InfoLevel: - return flag.Set("v", "2") - // glog doesn't support following filters. Defaults to v=0. - case logrus.WarnLevel: - case logrus.ErrorLevel: - case logrus.FatalLevel: - case logrus.PanicLevel: - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/LICENSE containerd-1.5.9/vendor/github.com/containerd/cri/LICENSE --- containerd-1.2.6/vendor/github.com/containerd/cri/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/annotations/annotations.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/annotations/annotations.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/annotations/annotations.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/annotations/annotations.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package annotations - -// ContainerType values -// Following OCI annotations are used by katacontainers now. -// We'll switch to standard secure pod API after it is defined in CRI. -const ( - // ContainerTypeSandbox represents a pod sandbox container - ContainerTypeSandbox = "sandbox" - - // ContainerTypeContainer represents a container running within a pod - ContainerTypeContainer = "container" - - // ContainerType is the container type (sandbox or container) annotation - ContainerType = "io.kubernetes.cri.container-type" - - // SandboxID is the sandbox ID annotation - SandboxID = "io.kubernetes.cri.sandbox-id" - - // SandboxLogDir is the pod log directory annotation. - // If the sandbox needs to generate any log, it will put it into this directory. - // Kubelet will be responsible for: - // 1) Monitoring the disk usage of the log, and including it as part of the pod - // ephemeral storage usage. - // 2) Cleaning up the logs when the pod is deleted. - // NOTE: Kubelet is not responsible for rotating the logs. - SandboxLogDir = "io.kubernetes.cri.sandbox-log-directory" - - // UntrustedWorkload is the sandbox annotation for untrusted workload. Untrusted - // workload can only run on dedicated runtime for untrusted workload. - UntrustedWorkload = "io.kubernetes.cri.untrusted-workload" -) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/api/v1/api.pb.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/api/v1/api.pb.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/api/v1/api.pb.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/api/v1/api.pb.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,597 +0,0 @@ -/* -Copyright 2018 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. -// source: api.proto -// DO NOT EDIT! - -/* -Package api_v1 is a generated protocol buffer package. - -It is generated from these files: - api.proto - -It has these top-level messages: - LoadImageRequest - LoadImageResponse -*/ -package api_v1 - -import proto "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/gogo/protobuf/gogoproto" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -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 LoadImageRequest struct { - // FilePath is the absolute path of docker image tarball. - FilePath string `protobuf:"bytes,1,opt,name=FilePath,proto3" json:"FilePath,omitempty"` -} - -func (m *LoadImageRequest) Reset() { *m = LoadImageRequest{} } -func (*LoadImageRequest) ProtoMessage() {} -func (*LoadImageRequest) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{0} } - -func (m *LoadImageRequest) GetFilePath() string { - if m != nil { - return m.FilePath - } - return "" -} - -type LoadImageResponse struct { - // Images have been loaded. - Images []string `protobuf:"bytes,1,rep,name=Images" json:"Images,omitempty"` -} - -func (m *LoadImageResponse) Reset() { *m = LoadImageResponse{} } -func (*LoadImageResponse) ProtoMessage() {} -func (*LoadImageResponse) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{1} } - -func (m *LoadImageResponse) GetImages() []string { - if m != nil { - return m.Images - } - return nil -} - -func init() { - proto.RegisterType((*LoadImageRequest)(nil), "api.v1.LoadImageRequest") - proto.RegisterType((*LoadImageResponse)(nil), "api.v1.LoadImageResponse") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// Client API for CRIPluginService service - -type CRIPluginServiceClient interface { - // LoadImage loads a image into containerd. - LoadImage(ctx context.Context, in *LoadImageRequest, opts ...grpc.CallOption) (*LoadImageResponse, error) -} - -type cRIPluginServiceClient struct { - cc *grpc.ClientConn -} - -func NewCRIPluginServiceClient(cc *grpc.ClientConn) CRIPluginServiceClient { - return &cRIPluginServiceClient{cc} -} - -func (c *cRIPluginServiceClient) LoadImage(ctx context.Context, in *LoadImageRequest, opts ...grpc.CallOption) (*LoadImageResponse, error) { - out := new(LoadImageResponse) - err := grpc.Invoke(ctx, "/api.v1.CRIPluginService/LoadImage", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// Server API for CRIPluginService service - -type CRIPluginServiceServer interface { - // LoadImage loads a image into containerd. - LoadImage(context.Context, *LoadImageRequest) (*LoadImageResponse, error) -} - -func RegisterCRIPluginServiceServer(s *grpc.Server, srv CRIPluginServiceServer) { - s.RegisterService(&_CRIPluginService_serviceDesc, srv) -} - -func _CRIPluginService_LoadImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LoadImageRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(CRIPluginServiceServer).LoadImage(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/api.v1.CRIPluginService/LoadImage", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CRIPluginServiceServer).LoadImage(ctx, req.(*LoadImageRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _CRIPluginService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "api.v1.CRIPluginService", - HandlerType: (*CRIPluginServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "LoadImage", - Handler: _CRIPluginService_LoadImage_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "api.proto", -} - -func (m *LoadImageRequest) 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 *LoadImageRequest) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.FilePath) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintApi(dAtA, i, uint64(len(m.FilePath))) - i += copy(dAtA[i:], m.FilePath) - } - return i, nil -} - -func (m *LoadImageResponse) 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 *LoadImageResponse) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.Images) > 0 { - for _, s := range m.Images { - dAtA[i] = 0xa - i++ - l = len(s) - for l >= 1<<7 { - dAtA[i] = uint8(uint64(l)&0x7f | 0x80) - l >>= 7 - i++ - } - dAtA[i] = uint8(l) - i++ - i += copy(dAtA[i:], s) - } - } - 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 { - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return offset + 1 -} -func (m *LoadImageRequest) Size() (n int) { - var l int - _ = l - l = len(m.FilePath) - if l > 0 { - n += 1 + l + sovApi(uint64(l)) - } - return n -} - -func (m *LoadImageResponse) Size() (n int) { - var l int - _ = l - if len(m.Images) > 0 { - for _, s := range m.Images { - l = len(s) - 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 *LoadImageRequest) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&LoadImageRequest{`, - `FilePath:` + fmt.Sprintf("%v", this.FilePath) + `,`, - `}`, - }, "") - return s -} -func (this *LoadImageResponse) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&LoadImageResponse{`, - `Images:` + fmt.Sprintf("%v", this.Images) + `,`, - `}`, - }, "") - 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 *LoadImageRequest) 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: LoadImageRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LoadImageRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FilePath", 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.FilePath = 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 (m *LoadImageResponse) 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: LoadImageResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: LoadImageResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Images", 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.Images = append(m.Images, 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{ - // 219 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, 0x62, 0x03, 0x31, 0xcb, 0x0c, 0xa5, 0x74, 0xd3, 0x33, 0x4b, - 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0xd2, 0x49, - 0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0xb4, 0x29, 0xe9, 0x71, 0x09, 0xf8, 0xe4, 0x27, - 0xa6, 0x78, 0xe6, 0x26, 0xa6, 0xa7, 0x06, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x49, 0x71, - 0x71, 0xb8, 0x65, 0xe6, 0xa4, 0x06, 0x24, 0x96, 0x64, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, - 0xc1, 0xf9, 0x4a, 0xda, 0x5c, 0x82, 0x48, 0xea, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0xc4, - 0xb8, 0xd8, 0xc0, 0x02, 0xc5, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x50, 0x9e, 0x51, 0x18, - 0x97, 0x80, 0x73, 0x90, 0x67, 0x40, 0x4e, 0x69, 0x7a, 0x66, 0x5e, 0x70, 0x6a, 0x51, 0x59, 0x66, - 0x72, 0xaa, 0x90, 0x13, 0x17, 0x27, 0xdc, 0x00, 0x21, 0x09, 0x3d, 0x88, 0xab, 0xf5, 0xd0, 0xdd, - 0x20, 0x25, 0x89, 0x45, 0x06, 0x62, 0x9b, 0x12, 0x83, 0x93, 0xcc, 0x89, 0x87, 0x72, 0x8c, 0x37, - 0x1e, 0xca, 0x31, 0x34, 0x3c, 0x92, 0x63, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, - 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xcc, 0x18, 0x10, 0x00, - 0x00, 0xff, 0xff, 0xfc, 0x6f, 0xec, 0xf4, 0x1d, 0x01, 0x00, 0x00, -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/api/v1/api.proto containerd-1.5.9/vendor/github.com/containerd/cri/pkg/api/v1/api.proto --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/api/v1/api.proto 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/api/v1/api.proto 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -// To regenerate api.pb.go run `make proto`hack/update-generated-runtime.sh -syntax = 'proto3'; - -package api.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; - -// CRIPluginService defines non-CRI APIs for cri plugin. -service CRIPluginService{ - // LoadImage loads a image into containerd. - rpc LoadImage(LoadImageRequest) returns (LoadImageResponse) {} -} - -message LoadImageRequest { - // FilePath is the absolute path of docker image tarball. - string FilePath = 1; -} - -message LoadImageResponse { - // Images have been loaded. - repeated string Images = 1; -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/atomic/atomic_boolean.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/atomic/atomic_boolean.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/atomic/atomic_boolean.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/atomic/atomic_boolean.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package atomic - -import "sync/atomic" - -// Bool is an atomic Boolean, -// Its methods are all atomic, thus safe to be called by -// multiple goroutines simultaneously. -type Bool interface { - Set() - Unset() - IsSet() bool -} - -// NewBool creates an Bool with given default value -func NewBool(ok bool) Bool { - ab := new(atomicBool) - if ok { - ab.Set() - } - return ab -} - -type atomicBool int32 - -// Set sets the Boolean to true -func (ab *atomicBool) Set() { - atomic.StoreInt32((*int32)(ab), 1) -} - -// Unset sets the Boolean to false -func (ab *atomicBool) Unset() { - atomic.StoreInt32((*int32)(ab), 0) -} - -// IsSet returns whether the Boolean is true -func (ab *atomicBool) IsSet() bool { - return atomic.LoadInt32((*int32)(ab)) == 1 -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/client/client.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/client/client.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/client/client.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/client/client.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package client - -import ( - "context" - - "github.com/pkg/errors" - "google.golang.org/grpc" - "k8s.io/kubernetes/pkg/kubelet/util" - - api "github.com/containerd/cri/pkg/api/v1" -) - -// NewCRIPluginClient creates grpc client of cri plugin -// TODO(random-liu): Wrap grpc functions. -func NewCRIPluginClient(ctx context.Context, endpoint string) (api.CRIPluginServiceClient, error) { - addr, dialer, err := util.GetAddressAndDialer(endpoint) - if err != nil { - return nil, errors.Wrap(err, "failed to get dialer") - } - conn, err := grpc.DialContext(ctx, addr, - grpc.WithBlock(), - grpc.WithInsecure(), - grpc.WithDialer(dialer), - ) - if err != nil { - return nil, errors.Wrap(err, "failed to dial") - } - return api.NewCRIPluginServiceClient(conn), nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/config/config.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/config/config.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/config/config.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/config/config.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,212 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "github.com/BurntSushi/toml" - "github.com/containerd/containerd" -) - -// Runtime struct to contain the type(ID), engine, and root variables for a default runtime -// and a runtime for untrusted worload. -type Runtime struct { - // Type is the runtime type to use in containerd e.g. io.containerd.runtime.v1.linux - Type string `toml:"runtime_type" json:"runtimeType"` - // Engine is the name of the runtime engine used by containerd. - // This only works for runtime type "io.containerd.runtime.v1.linux". - // DEPRECATED: use Options instead. Remove when shim v1 is deprecated. - Engine string `toml:"runtime_engine" json:"runtimeEngine"` - // Root is the directory used by containerd for runtime state. - // DEPRECATED: use Options instead. Remove when shim v1 is deprecated. - // This only works for runtime type "io.containerd.runtime.v1.linux". - Root string `toml:"runtime_root" json:"runtimeRoot"` - // Options are config options for the runtime. If options is loaded - // from toml config, it will be toml.Primitive. - Options *toml.Primitive `toml:"options" json:"options"` -} - -// ContainerdConfig contains toml config related to containerd -type ContainerdConfig struct { - // Snapshotter is the snapshotter used by containerd. - Snapshotter string `toml:"snapshotter" json:"snapshotter"` - // DefaultRuntime is the default runtime to use in containerd. - // This runtime is used when no runtime handler (or the empty string) is provided. - DefaultRuntime Runtime `toml:"default_runtime" json:"defaultRuntime"` - // UntrustedWorkloadRuntime is a runtime to run untrusted workloads on it. - // DEPRECATED: use Runtimes instead. If provided, this runtime is mapped to the runtime handler - // named 'untrusted'. It is a configuration error to provide both the (now deprecated) - // UntrustedWorkloadRuntime and a handler in the Runtimes handler map (below) for 'untrusted' - // workloads at the same time. Please provide one or the other. - UntrustedWorkloadRuntime Runtime `toml:"untrusted_workload_runtime" json:"untrustedWorkloadRuntime"` - // Runtimes is a map from CRI RuntimeHandler strings, which specify types of runtime - // configurations, to the matching configurations. - Runtimes map[string]Runtime `toml:"runtimes" json:"runtimes"` - // NoPivot disables pivot-root (linux only), required when running a container in a RamDisk with runc - // This only works for runtime type "io.containerd.runtime.v1.linux". - // DEPRECATED: use Runtime.Options instead. Remove when shim v1 is deprecated. - NoPivot bool `toml:"no_pivot" json:"noPivot"` -} - -// CniConfig contains toml config related to cni -type CniConfig struct { - // NetworkPluginBinDir is the directory in which the binaries for the plugin is kept. - NetworkPluginBinDir string `toml:"bin_dir" json:"binDir"` - // NetworkPluginConfDir is the directory in which the admin places a CNI conf. - NetworkPluginConfDir string `toml:"conf_dir" json:"confDir"` - // NetworkPluginConfTemplate is the file path of golang template used to generate - // cni config. - // When it is set, containerd will get cidr from kubelet to replace {{.PodCIDR}} in - // the template, and write the config into NetworkPluginConfDir. - // Ideally the cni config should be placed by system admin or cni daemon like calico, - // weaveworks etc. However, there are still users using kubenet - // (https://kubernetes.io/docs/concepts/cluster-administration/network-plugins/#kubenet) - // today, who don't have a cni daemonset in production. NetworkPluginConfTemplate is - // a temporary backward-compatible solution for them. - // TODO(random-liu): Deprecate this option when kubenet is deprecated. - NetworkPluginConfTemplate string `toml:"conf_template" json:"confTemplate"` -} - -// Mirror contains the config related to the registry mirror -type Mirror struct { - // Endpoints are endpoints for a namespace. CRI plugin will try the endpoints - // one by one until a working one is found. The endpoint must be a valid url - // with host specified. - Endpoints []string `toml:"endpoint" json:"endpoint"` -} - -// AuthConfig contains the config related to authentication to a specific registry -type AuthConfig struct { - // Username is the username to login the registry. - Username string `toml:"username" json:"username"` - // Password is the password to login the registry. - Password string `toml:"password" json:"password"` - // Auth is a base64 encoded string from the concatenation of the username, - // a colon, and the password. - Auth string `toml:"auth" json:"auth"` - // IdentityToken is used to authenticate the user and get - // an access token for the registry. - IdentityToken string `toml:"identitytoken" json:"identitytoken"` -} - -// Registry is registry settings configured -type Registry struct { - // Mirrors are namespace to mirror mapping for all namespaces. - Mirrors map[string]Mirror `toml:"mirrors" json:"mirrors"` - // Auths are registry endpoint to auth config mapping. The registry endpoint must - // be a valid url with host specified. - Auths map[string]AuthConfig `toml:"auths" json:"auths"` -} - -// PluginConfig contains toml config related to CRI plugin, -// it is a subset of Config. -type PluginConfig struct { - // ContainerdConfig contains config related to containerd - ContainerdConfig `toml:"containerd" json:"containerd"` - // CniConfig contains config related to cni - CniConfig `toml:"cni" json:"cni"` - // Registry contains config related to the registry - Registry Registry `toml:"registry" json:"registry"` - // StreamServerAddress is the ip address streaming server is listening on. - StreamServerAddress string `toml:"stream_server_address" json:"streamServerAddress"` - // StreamServerPort is the port streaming server is listening on. - StreamServerPort string `toml:"stream_server_port" json:"streamServerPort"` - // EnableSelinux indicates to enable the selinux support. - EnableSelinux bool `toml:"enable_selinux" json:"enableSelinux"` - // SandboxImage is the image used by sandbox container. - SandboxImage string `toml:"sandbox_image" json:"sandboxImage"` - // StatsCollectPeriod is the period (in seconds) of snapshots stats collection. - StatsCollectPeriod int `toml:"stats_collect_period" json:"statsCollectPeriod"` - // SystemdCgroup enables systemd cgroup support. - // This only works for runtime type "io.containerd.runtime.v1.linux". - // DEPRECATED: config runc runtime handler instead. Remove when shim v1 is deprecated. - SystemdCgroup bool `toml:"systemd_cgroup" json:"systemdCgroup"` - // EnableTLSStreaming indicates to enable the TLS streaming support. - EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"` - // X509KeyPairStreaming is a x509 key pair used for TLS streaming - X509KeyPairStreaming `toml:"x509_key_pair_streaming" json:"x509KeyPairStreaming"` - // MaxContainerLogLineSize is the maximum log line size in bytes for a container. - // Log line longer than the limit will be split into multiple lines. Non-positive - // value means no limit. - MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"` -} - -// X509KeyPairStreaming contains the x509 configuration for streaming -type X509KeyPairStreaming struct { - // TLSCertFile is the path to a certificate file - TLSCertFile string `toml:"tls_cert_file" json:"tlsCertFile"` - // TLSKeyFile is the path to a private key file - TLSKeyFile string `toml:"tls_key_file" json:"tlsKeyFile"` -} - -// Config contains all configurations for cri server. -type Config struct { - // PluginConfig is the config for CRI plugin. - PluginConfig - // ContainerdRootDir is the root directory path for containerd. - ContainerdRootDir string `json:"containerdRootDir"` - // ContainerdEndpoint is the containerd endpoint path. - ContainerdEndpoint string `json:"containerdEndpoint"` - // RootDir is the root directory path for managing cri plugin files - // (metadata checkpoint etc.) - RootDir string `json:"rootDir"` - // StateDir is the root directory path for managing volatile pod/container data - StateDir string `json:"stateDir"` -} - -// DefaultConfig returns default configurations of cri plugin. -func DefaultConfig() PluginConfig { - return PluginConfig{ - CniConfig: CniConfig{ - NetworkPluginBinDir: "/opt/cni/bin", - NetworkPluginConfDir: "/etc/cni/net.d", - NetworkPluginConfTemplate: "", - }, - ContainerdConfig: ContainerdConfig{ - Snapshotter: containerd.DefaultSnapshotter, - DefaultRuntime: Runtime{ - Type: "io.containerd.runtime.v1.linux", - Engine: "", - Root: "", - }, - NoPivot: false, - }, - StreamServerAddress: "127.0.0.1", - StreamServerPort: "0", - EnableSelinux: false, - EnableTLSStreaming: false, - X509KeyPairStreaming: X509KeyPairStreaming{ - TLSKeyFile: "", - TLSCertFile: "", - }, - SandboxImage: "k8s.gcr.io/pause:3.1", - StatsCollectPeriod: 10, - SystemdCgroup: false, - MaxContainerLogLineSize: 16 * 1024, - Registry: Registry{ - Mirrors: map[string]Mirror{ - "docker.io": { - Endpoints: []string{"https://registry-1.docker.io"}, - }, - }, - }, - } -} - -const ( - // RuntimeUntrusted is the implicit runtime defined for ContainerdConfig.UntrustedWorkloadRuntime - RuntimeUntrusted = "untrusted" -) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/constants/constants.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/constants/constants.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/constants/constants.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/constants/constants.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package constants - -// TODO(random-liu): Merge annotations package into this package. - -const ( - // K8sContainerdNamespace is the namespace we use to connect containerd. - K8sContainerdNamespace = "k8s.io" - // CRIVersion is the CRI version supported by the CRI plugin. - CRIVersion = "v1alpha2" -) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/importer/importer.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/importer/importer.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/importer/importer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/importer/importer.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,356 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package importer - -import ( - "archive/tar" - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "strings" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/leases" - "github.com/containerd/containerd/log" - "github.com/opencontainers/go-digest" - "github.com/opencontainers/image-spec/specs-go" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - "github.com/containerd/cri/pkg/util" -) - -// This code reuses the docker import code from containerd/containerd#1602. -// It has been simplified a bit and garbage collection support was added. -// If a library/helper is added to containerd in the future, we should switch to it. - -// manifestDotJSON is an entry in manifest.json. -type manifestDotJSON struct { - Config string - RepoTags []string - Layers []string - // Parent is unsupported - Parent string -} - -// isLayerTar returns true if name is like "foobar/layer.tar" -func isLayerTar(name string) bool { - slashes := len(strings.Split(name, "/")) - return slashes == 2 && strings.HasSuffix(name, "/layer.tar") -} - -// followSymlinkLayer returns actual layer name of the symlink layer. -// It returns "foobar/layer.tar" if the name is like -// "../foobar/layer.tar", and returns error if the name -// is not in "../foobar/layer.tar" format. -func followSymlinkLayer(name string) (string, error) { - parts := strings.Split(name, "/") - if len(parts) != 3 || parts[0] != ".." { - return "", errors.New("invalid symlink layer") - } - name = strings.TrimPrefix(name, "../") - if !isLayerTar(name) { - return "", errors.New("invalid layer tar") - } - return name, nil -} - -// isDotJSON returns true if name is like "foobar.json" -func isDotJSON(name string) bool { - slashes := len(strings.Split(name, "/")) - return slashes == 1 && strings.HasSuffix(name, ".json") -} - -type imageConfig struct { - desc ocispec.Descriptor - img ocispec.Image -} - -type importConfig struct { - unpack bool - snapshotter string -} - -// ImportOption configures import behavior. -type ImportOption func(*importConfig) - -// WithUnpack is used to unpack image after import. -func WithUnpack(snapshotter string) ImportOption { - return func(c *importConfig) { - c.unpack = true - c.snapshotter = snapshotter - } -} - -// Import implements Docker Image Spec v1.1. -// An image MUST have `manifest.json`. -// `repositories` file in Docker Image Spec v1.0 is not supported (yet). -// Also, the current implementation assumes the implicit file name convention, -// which is not explicitly documented in the spec. (e.g. foobar/layer.tar) -// It returns a group of image references successfully loaded. -func Import(ctx context.Context, client *containerd.Client, reader io.Reader, opts ...ImportOption) (_ []string, retErr error) { - c := &importConfig{} - for _, o := range opts { - o(c) - } - ctx, done, err := client.WithLease(ctx) - if err != nil { - return nil, err - } - defer func() { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - if err := done(deferCtx); err != nil { - // Get lease id from context still works after context is done. - leaseID, _ := leases.FromContext(ctx) - log.G(ctx).WithError(err).Errorf("Failed to release lease %q", leaseID) - } - }() - - cs := client.ContentStore() - is := client.ImageService() - - tr := tar.NewReader(reader) - var ( - mfsts []manifestDotJSON - symlinkLayers = make(map[string]string) // key: filename (foobar/layer.tar), value: linkname (targetlayerid/layer.tar) - layers = make(map[string]ocispec.Descriptor) // key: filename (foobar/layer.tar) - configs = make(map[string]imageConfig) // key: filename (foobar.json) - ) - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return nil, errors.Wrap(err, "get next file") - } - if hdr.Typeflag == tar.TypeSymlink && isLayerTar(hdr.Name) { - linkname, err := followSymlinkLayer(hdr.Linkname) - if err != nil { - return nil, errors.Wrapf(err, "follow symlink layer from %q to %q", hdr.Name, hdr.Linkname) - } - symlinkLayers[hdr.Name] = linkname - continue - } - if hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA { - continue - } - if hdr.Name == "manifest.json" { - mfsts, err = onUntarManifestJSON(tr) - if err != nil { - return nil, errors.Wrapf(err, "untar manifest %q", hdr.Name) - } - continue - } - if isLayerTar(hdr.Name) { - desc, err := onUntarLayerTar(ctx, tr, cs, hdr.Name, hdr.Size) - if err != nil { - return nil, errors.Wrapf(err, "untar layer %q", hdr.Name) - } - layers[hdr.Name] = *desc - continue - } - if isDotJSON(hdr.Name) { - c, err := onUntarDotJSON(ctx, tr, cs, hdr.Name, hdr.Size) - if err != nil { - return nil, errors.Wrapf(err, "untar config %q", hdr.Name) - } - configs[hdr.Name] = *c - continue - } - } - for name, linkname := range symlinkLayers { - desc, ok := layers[linkname] - if !ok { - return nil, errors.Errorf("no target for symlink layer from %q to %q", name, linkname) - } - layers[name] = desc - } - var refs []string - defer func() { - if retErr == nil { - return - } - // TODO(random-liu): Consider whether we should keep images already imported - // even when there is an error. - for _, ref := range refs { - func() { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - if err := is.Delete(deferCtx, ref); err != nil { - log.G(ctx).WithError(err).Errorf("Failed to remove image %q", ref) - } - }() - } - }() - for _, mfst := range mfsts { - config, ok := configs[mfst.Config] - if !ok { - return refs, errors.Errorf("image config %q not found", mfst.Config) - } - schema2Manifest, err := makeDockerSchema2Manifest(mfst, config, layers) - if err != nil { - return refs, errors.Wrap(err, "create docker manifest") - } - desc, err := writeDockerSchema2Manifest(ctx, cs, *schema2Manifest, config.img.Architecture, config.img.OS) - if err != nil { - return refs, errors.Wrap(err, "write docker manifest") - } - - for _, ref := range mfst.RepoTags { - normalized, err := util.NormalizeImageRef(ref) - if err != nil { - return refs, errors.Wrapf(err, "normalize image ref %q", ref) - } - ref = normalized.String() - imgrec := images.Image{ - Name: ref, - Target: *desc, - } - if c.unpack { - img := containerd.NewImage(client, imgrec) - if err := img.Unpack(ctx, c.snapshotter); err != nil { - return refs, errors.Wrapf(err, "unpack image %q", ref) - } - } - if _, err := is.Create(ctx, imgrec); err != nil { - if !errdefs.IsAlreadyExists(err) { - return refs, errors.Wrapf(err, "create image ref %+v", imgrec) - } - - _, err := is.Update(ctx, imgrec) - if err != nil { - return refs, errors.Wrapf(err, "update image ref %+v", imgrec) - } - } - refs = append(refs, ref) - } - } - return refs, nil -} - -func makeDockerSchema2Manifest(mfst manifestDotJSON, config imageConfig, layers map[string]ocispec.Descriptor) (*ocispec.Manifest, error) { - manifest := ocispec.Manifest{ - Versioned: specs.Versioned{ - SchemaVersion: 2, - }, - Config: config.desc, - } - for _, f := range mfst.Layers { - desc, ok := layers[f] - if !ok { - return nil, errors.Errorf("layer %q not found", f) - } - manifest.Layers = append(manifest.Layers, desc) - } - return &manifest, nil -} - -func writeDockerSchema2Manifest(ctx context.Context, cs content.Ingester, manifest ocispec.Manifest, arch, os string) (*ocispec.Descriptor, error) { - manifestBytes, err := json.Marshal(manifest) - if err != nil { - return nil, err - } - manifestBytesR := bytes.NewReader(manifestBytes) - manifestDigest := digest.FromBytes(manifestBytes) - labels := map[string]string{} - labels["containerd.io/gc.ref.content.0"] = manifest.Config.Digest.String() - for i, ch := range manifest.Layers { - labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String() - } - - desc := ocispec.Descriptor{ - MediaType: images.MediaTypeDockerSchema2Manifest, - Digest: manifestDigest, - Size: int64(len(manifestBytes)), - } - if err := content.WriteBlob(ctx, cs, "manifest-"+manifestDigest.String(), manifestBytesR, - desc, content.WithLabels(labels)); err != nil { - return nil, err - } - - if arch != "" || os != "" { - desc.Platform = &ocispec.Platform{ - Architecture: arch, - OS: os, - } - } - return &desc, nil -} - -func onUntarManifestJSON(r io.Reader) ([]manifestDotJSON, error) { - // name: "manifest.json" - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - var mfsts []manifestDotJSON - if err := json.Unmarshal(b, &mfsts); err != nil { - return nil, err - } - return mfsts, nil -} - -func onUntarLayerTar(ctx context.Context, r io.Reader, cs content.Ingester, name string, size int64) (*ocispec.Descriptor, error) { - // name is like "foobar/layer.tar" ( guaranteed by isLayerTar() ) - split := strings.Split(name, "/") - // note: split[0] is not expected digest here - cw, err := cs.Writer(ctx, content.WithRef("layer-"+split[0]), content.WithDescriptor(ocispec.Descriptor{Size: size})) - if err != nil { - return nil, err - } - defer cw.Close() - if err := content.Copy(ctx, cw, r, size, ""); err != nil { - return nil, err - } - return &ocispec.Descriptor{ - MediaType: images.MediaTypeDockerSchema2Layer, - Size: size, - Digest: cw.Digest(), - }, nil -} - -func onUntarDotJSON(ctx context.Context, r io.Reader, cs content.Ingester, name string, size int64) (*imageConfig, error) { - config := imageConfig{} - config.desc.MediaType = images.MediaTypeDockerSchema2Config - config.desc.Size = size - // name is like "foobar.json" ( guaranteed by is DotJSON() ) - split := strings.Split(name, ".") - cw, err := cs.Writer(ctx, content.WithRef("config-"+split[0]), content.WithDescriptor(ocispec.Descriptor{Size: size})) - if err != nil { - return nil, err - } - defer cw.Close() - var buf bytes.Buffer - tr := io.TeeReader(r, &buf) - if err := content.Copy(ctx, cw, tr, size, ""); err != nil { - return nil, err - } - config.desc.Digest = cw.Digest() - if err := json.Unmarshal(buf.Bytes(), &config.img); err != nil { - return nil, err - } - return &config, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/container.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/container.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/container.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/container.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package opts - -import ( - "context" - "io/ioutil" - "os" - "path/filepath" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/mount" - "github.com/containerd/continuity/fs" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// WithNewSnapshot wraps `containerd.WithNewSnapshot` so that if creating the -// snapshot fails we make sure the image is actually unpacked and and retry. -func WithNewSnapshot(id string, i containerd.Image) containerd.NewContainerOpts { - f := containerd.WithNewSnapshot(id, i) - return func(ctx context.Context, client *containerd.Client, c *containers.Container) error { - if err := f(ctx, client, c); err != nil { - if !errdefs.IsNotFound(err) { - return err - } - - if err := i.Unpack(ctx, c.Snapshotter); err != nil { - return errors.Wrap(err, "error unpacking image") - } - return f(ctx, client, c) - } - return nil - } -} - -// WithVolumes copies ownership of volume in rootfs to its corresponding host path. -// It doesn't update runtime spec. -// The passed in map is a host path to container path map for all volumes. -func WithVolumes(volumeMounts map[string]string) containerd.NewContainerOpts { - return func(ctx context.Context, client *containerd.Client, c *containers.Container) (err error) { - if c.Snapshotter == "" { - return errors.New("no snapshotter set for container") - } - if c.SnapshotKey == "" { - return errors.New("rootfs not created for container") - } - snapshotter := client.SnapshotService(c.Snapshotter) - mounts, err := snapshotter.Mounts(ctx, c.SnapshotKey) - if err != nil { - return err - } - root, err := ioutil.TempDir("", "ctd-volume") - if err != nil { - return err - } - // We change RemoveAll to Remove so that we either leak a temp dir - // if it fails but not RM snapshot data. - // refer to https://github.com/containerd/containerd/pull/1868 - // https://github.com/containerd/containerd/pull/1785 - defer os.Remove(root) // nolint: errcheck - if err := mount.All(mounts, root); err != nil { - return errors.Wrap(err, "failed to mount") - } - defer func() { - if uerr := mount.Unmount(root, 0); uerr != nil { - logrus.WithError(uerr).Errorf("Failed to unmount snapshot %q", c.SnapshotKey) - if err == nil { - err = uerr - } - } - }() - - for host, volume := range volumeMounts { - src := filepath.Join(root, volume) - if _, err := os.Stat(src); err != nil { - if os.IsNotExist(err) { - // Skip copying directory if it does not exist. - continue - } - return errors.Wrap(err, "stat volume in rootfs") - } - if err := copyExistingContents(src, host); err != nil { - return errors.Wrap(err, "taking runtime copy of volume") - } - } - return nil - } -} - -// copyExistingContents copies from the source to the destination and -// ensures the ownership is appropriately set. -func copyExistingContents(source, destination string) error { - dstList, err := ioutil.ReadDir(destination) - if err != nil { - return err - } - if len(dstList) != 0 { - return errors.Errorf("volume at %q is not initially empty", destination) - } - return fs.CopyDir(destination, source) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/spec.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/spec.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/spec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/spec.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* -Copyright 2018 The containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package opts - -import ( - "context" - - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/oci" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" -) - -// WithAdditionalGIDs adds any additional groups listed for a particular user in the -// /etc/groups file of the image's root filesystem to the OCI spec's additionalGids array. -func WithAdditionalGIDs(userstr string) oci.SpecOpts { - return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) (err error) { - gids := s.Process.User.AdditionalGids - if err := oci.WithAdditionalGIDs(userstr)(ctx, client, c, s); err != nil { - return err - } - // Merge existing gids and new gids. - s.Process.User.AdditionalGids = mergeGids(s.Process.User.AdditionalGids, gids) - return nil - } -} - -func mergeGids(gids1, gids2 []uint32) []uint32 { - for _, gid1 := range gids1 { - for i, gid2 := range gids2 { - if gid1 == gid2 { - gids2 = append(gids2[:i], gids2[i+1:]...) - break - } - } - } - return append(gids1, gids2...) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/task.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/task.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/opts/task.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/opts/task.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package opts - -import ( - "context" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/runtime/linux/runctypes" -) - -// WithContainerdShimCgroup returns function that sets the containerd -// shim cgroup path -func WithContainerdShimCgroup(path string) containerd.NewTaskOpts { - return func(_ context.Context, _ *containerd.Client, r *containerd.TaskInfo) error { - r.Options = &runctypes.CreateOptions{ - ShimCgroup: path, - } - return nil - } -} - -//TODO: Since Options is an interface different WithXXX will be needed to set different -// combinations of CreateOptions. diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/util/util.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/util/util.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/containerd/util/util.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/containerd/util/util.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,46 +0,0 @@ -/* -Copyright 2018 The containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "time" - - "github.com/containerd/containerd/namespaces" - "golang.org/x/net/context" - - "github.com/containerd/cri/pkg/constants" -) - -// deferCleanupTimeout is the default timeout for containerd cleanup operations -// in defer. -const deferCleanupTimeout = 1 * time.Minute - -// DeferContext returns a context for containerd cleanup operations in defer. -// A default timeout is applied to avoid cleanup operation pending forever. -func DeferContext() (context.Context, context.CancelFunc) { - return context.WithTimeout(NamespacedContext(), deferCleanupTimeout) -} - -// NamespacedContext returns a context with kubernetes namespace set. -func NamespacedContext() context.Context { - return WithNamespace(context.Background()) -} - -// WithNamespace adds kubernetes namespace to the context. -func WithNamespace(ctx context.Context) context.Context { - return namespaces.WithNamespace(ctx, constants.K8sContainerdNamespace) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/read_closer.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/read_closer.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/read_closer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/read_closer.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ioutil - -import "io" - -// writeCloseInformer wraps a reader with a close function. -type wrapReadCloser struct { - reader *io.PipeReader - writer *io.PipeWriter -} - -// NewWrapReadCloser creates a wrapReadCloser from a reader. -// NOTE(random-liu): To avoid goroutine leakage, the reader passed in -// must be eventually closed by the caller. -func NewWrapReadCloser(r io.Reader) io.ReadCloser { - pr, pw := io.Pipe() - go func() { - _, _ = io.Copy(pw, r) - pr.Close() - pw.Close() - }() - return &wrapReadCloser{ - reader: pr, - writer: pw, - } -} - -// Read reads up to len(p) bytes into p. -func (w *wrapReadCloser) Read(p []byte) (int, error) { - n, err := w.reader.Read(p) - if err == io.ErrClosedPipe { - return n, io.EOF - } - return n, err -} - -// Close closes read closer. -func (w *wrapReadCloser) Close() error { - w.reader.Close() - w.writer.Close() - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/write_closer.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/write_closer.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/write_closer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/write_closer.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ioutil - -import ( - "io" - "sync" -) - -// writeCloseInformer wraps passed in write closer with a close channel. -// Caller could wait on the close channel for the write closer to be -// closed. -type writeCloseInformer struct { - close chan struct{} - wc io.WriteCloser -} - -// NewWriteCloseInformer creates the writeCloseInformer from a write closer. -func NewWriteCloseInformer(wc io.WriteCloser) (io.WriteCloser, <-chan struct{}) { - close := make(chan struct{}) - return &writeCloseInformer{ - close: close, - wc: wc, - }, close -} - -// Write passes through the data into the internal write closer. -func (w *writeCloseInformer) Write(p []byte) (int, error) { - return w.wc.Write(p) -} - -// Close closes the internal write closer and inform the close channel. -func (w *writeCloseInformer) Close() error { - err := w.wc.Close() - close(w.close) - return err -} - -// nopWriteCloser wraps passed in writer with a nop close function. -type nopWriteCloser struct { - w io.Writer -} - -// NewNopWriteCloser creates the nopWriteCloser from a writer. -func NewNopWriteCloser(w io.Writer) io.WriteCloser { - return &nopWriteCloser{w: w} -} - -// Write passes through the data into the internal writer. -func (n *nopWriteCloser) Write(p []byte) (int, error) { - return n.w.Write(p) -} - -// Close is a nop close function. -func (n *nopWriteCloser) Close() error { - return nil -} - -// serialWriteCloser wraps a write closer and makes sure all writes -// are done in serial. -// Parallel write won't intersect with each other. Use case: -// 1) Pipe: Write content longer than PIPE_BUF. -// See http://man7.org/linux/man-pages/man7/pipe.7.html -// 2) <3.14 Linux Kernel: write is not atomic -// See http://man7.org/linux/man-pages/man2/write.2.html -type serialWriteCloser struct { - mu sync.Mutex - wc io.WriteCloser -} - -// NewSerialWriteCloser creates a SerialWriteCloser from a write closer. -func NewSerialWriteCloser(wc io.WriteCloser) io.WriteCloser { - return &serialWriteCloser{wc: wc} -} - -// Write writes a group of byte arrays in order atomically. -func (s *serialWriteCloser) Write(data []byte) (int, error) { - s.mu.Lock() - defer s.mu.Unlock() - return s.wc.Write(data) -} - -// Close closes the write closer. -func (s *serialWriteCloser) Close() error { - s.mu.Lock() - defer s.mu.Unlock() - return s.wc.Close() -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/writer_group.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/writer_group.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/ioutil/writer_group.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/ioutil/writer_group.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ioutil - -import ( - "errors" - "io" - "sync" -) - -// WriterGroup is a group of writers. Writer could be dynamically -// added and removed. -type WriterGroup struct { - mu sync.Mutex - writers map[string]io.WriteCloser - closed bool -} - -var _ io.Writer = &WriterGroup{} - -// NewWriterGroup creates an empty writer group. -func NewWriterGroup() *WriterGroup { - return &WriterGroup{ - writers: make(map[string]io.WriteCloser), - } -} - -// Add adds a writer into the group. The writer will be closed -// if the writer group is closed. -func (g *WriterGroup) Add(key string, w io.WriteCloser) { - g.mu.Lock() - defer g.mu.Unlock() - if g.closed { - w.Close() - return - } - g.writers[key] = w -} - -// Get gets a writer from the group, returns nil if the writer -// doesn't exist. -func (g *WriterGroup) Get(key string) io.WriteCloser { - g.mu.Lock() - defer g.mu.Unlock() - return g.writers[key] -} - -// Remove removes a writer from the group. -func (g *WriterGroup) Remove(key string) { - g.mu.Lock() - defer g.mu.Unlock() - w, ok := g.writers[key] - if !ok { - return - } - w.Close() - delete(g.writers, key) -} - -// Write writes data into each writer. If a writer returns error, -// it will be closed and removed from the writer group. It returns -// error if writer group is empty. -func (g *WriterGroup) Write(p []byte) (int, error) { - g.mu.Lock() - defer g.mu.Unlock() - for k, w := range g.writers { - n, err := w.Write(p) - if err == nil && len(p) == n { - continue - } - // The writer is closed or in bad state, remove it. - w.Close() - delete(g.writers, k) - } - if len(g.writers) == 0 { - return 0, errors.New("writer group is empty") - } - return len(p), nil -} - -// Close closes the writer group. Write will return error after -// closed. -func (g *WriterGroup) Close() { - g.mu.Lock() - defer g.mu.Unlock() - for _, w := range g.writers { - w.Close() - } - g.writers = nil - g.closed = true -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/log/log.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/log/log.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/log/log.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/log/log.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package log - -import "github.com/containerd/containerd/log" - -// Trace logs a message at level Trace on the standard logger. -func Trace(args ...interface{}) { - log.Trace(log.L, args...) -} - -// Tracef logs a message at level Trace on the standard logger. -func Tracef(format string, args ...interface{}) { - log.Tracef(log.L, format, args...) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/netns/netns.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/netns/netns.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/netns/netns.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/netns/netns.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -/* -Copyright 2018 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. -*/ - -// Copyright 2018 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package netns - -import ( - "crypto/rand" - "fmt" - "os" - "path" - "runtime" - "sync" - - cnins "github.com/containernetworking/plugins/pkg/ns" - "github.com/docker/docker/pkg/symlink" - "github.com/pkg/errors" - "golang.org/x/sys/unix" - - osinterface "github.com/containerd/cri/pkg/os" -) - -const nsRunDir = "/var/run/netns" - -// Some of the following functions are migrated from -// https://github.com/containernetworking/plugins/blob/master/pkg/testutils/netns_linux.go - -// newNS creates a new persistent (bind-mounted) network namespace and returns the -// path to the network namespace. -func newNS() (nsPath string, err error) { - b := make([]byte, 16) - if _, err := rand.Reader.Read(b); err != nil { - return "", errors.Wrap(err, "failed to generate random netns name") - } - - // Create the directory for mounting network namespaces - // This needs to be a shared mountpoint in case it is mounted in to - // other namespaces (containers) - if err := os.MkdirAll(nsRunDir, 0755); err != nil { - return "", err - } - - // create an empty file at the mount point - nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) - nsPath = path.Join(nsRunDir, nsName) - mountPointFd, err := os.Create(nsPath) - if err != nil { - return "", err - } - mountPointFd.Close() - - defer func() { - // Ensure the mount point is cleaned up on errors - if err != nil { - os.RemoveAll(nsPath) // nolint: errcheck - } - }() - - var wg sync.WaitGroup - wg.Add(1) - - // do namespace work in a dedicated goroutine, so that we can safely - // Lock/Unlock OSThread without upsetting the lock/unlock state of - // the caller of this function - go (func() { - defer wg.Done() - runtime.LockOSThread() - // Don't unlock. By not unlocking, golang will kill the OS thread when the - // goroutine is done (for go1.10+) - - var origNS cnins.NetNS - origNS, err = cnins.GetNS(getCurrentThreadNetNSPath()) - if err != nil { - return - } - defer origNS.Close() - - // create a new netns on the current thread - err = unix.Unshare(unix.CLONE_NEWNET) - if err != nil { - return - } - - // Put this thread back to the orig ns, since it might get reused (pre go1.10) - defer origNS.Set() // nolint: errcheck - - // bind mount the netns from the current thread (from /proc) onto the - // mount point. This causes the namespace to persist, even when there - // are no threads in the ns. - err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "") - if err != nil { - err = errors.Wrapf(err, "failed to bind mount ns at %s", nsPath) - } - })() - wg.Wait() - - if err != nil { - return "", errors.Wrap(err, "failed to create namespace") - } - - return nsPath, nil -} - -// unmountNS unmounts the NS held by the netns object. unmountNS is idempotent. -func unmountNS(path string) error { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - return nil - } - return errors.Wrap(err, "failed to stat netns") - } - path, err := symlink.FollowSymlinkInScope(path, "/") - if err != nil { - return errors.Wrap(err, "failed to follow symlink") - } - if err := osinterface.Unmount(path); err != nil && !os.IsNotExist(err) { - return errors.Wrap(err, "failed to umount netns") - } - if err := os.RemoveAll(path); err != nil { - return errors.Wrap(err, "failed to remove netns") - } - return nil -} - -// getCurrentThreadNetNSPath copied from pkg/ns -func getCurrentThreadNetNSPath() string { - // /proc/self/ns/net returns the namespace of the main thread, not - // of whatever thread this goroutine is running on. Make sure we - // use the thread's net namespace since the thread is switching around - return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()) -} - -// NetNS holds network namespace. -type NetNS struct { - path string -} - -// NewNetNS creates a network namespace. -func NewNetNS() (*NetNS, error) { - path, err := newNS() - if err != nil { - return nil, errors.Wrap(err, "failed to setup netns") - } - return &NetNS{path: path}, nil -} - -// LoadNetNS loads existing network namespace. -func LoadNetNS(path string) *NetNS { - return &NetNS{path: path} -} - -// Remove removes network namepace. Remove is idempotent, meaning it might -// be invoked multiple times and provides consistent result. -func (n *NetNS) Remove() error { - return unmountNS(n.path) -} - -// Closed checks whether the network namespace has been closed. -func (n *NetNS) Closed() (bool, error) { - ns, err := cnins.GetNS(n.path) - if err != nil { - if _, ok := err.(cnins.NSPathNotExistErr); ok { - // The network namespace has already been removed. - return true, nil - } - if _, ok := err.(cnins.NSPathNotNSErr); ok { - // The network namespace is not mounted, remove it. - if err := os.RemoveAll(n.path); err != nil { - return false, errors.Wrap(err, "remove netns") - } - return true, nil - } - return false, errors.Wrap(err, "get netns fd") - } - if err := ns.Close(); err != nil { - return false, errors.Wrap(err, "close netns fd") - } - return false, nil -} - -// GetPath returns network namespace path for sandbox container -func (n *NetNS) GetPath() string { - return n.path -} - -// Do runs a function in the network namespace. -func (n *NetNS) Do(f func(cnins.NetNS) error) error { - ns, err := cnins.GetNS(n.path) - if err != nil { - return errors.Wrap(err, "get netns fd") - } - defer ns.Close() // nolint: errcheck - return ns.Do(f) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/os/os.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/os/os.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/os/os.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/os/os.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package os - -import ( - "io" - "io/ioutil" - "os" - "path/filepath" - - "github.com/containerd/containerd/mount" - "github.com/containerd/fifo" - "github.com/docker/docker/pkg/symlink" - "golang.org/x/net/context" - "golang.org/x/sys/unix" -) - -// OS collects system level operations that need to be mocked out -// during tests. -type OS interface { - MkdirAll(path string, perm os.FileMode) error - RemoveAll(path string) error - OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) - Stat(name string) (os.FileInfo, error) - ResolveSymbolicLink(name string) (string, error) - FollowSymlinkInScope(path, scope string) (string, error) - CopyFile(src, dest string, perm os.FileMode) error - WriteFile(filename string, data []byte, perm os.FileMode) error - Mount(source string, target string, fstype string, flags uintptr, data string) error - Unmount(target string) error - LookupMount(path string) (mount.Info, error) - Hostname() (string, error) -} - -// RealOS is used to dispatch the real system level operations. -type RealOS struct{} - -// MkdirAll will call os.MkdirAll to create a directory. -func (RealOS) MkdirAll(path string, perm os.FileMode) error { - return os.MkdirAll(path, perm) -} - -// RemoveAll will call os.RemoveAll to remove the path and its children. -func (RealOS) RemoveAll(path string) error { - return os.RemoveAll(path) -} - -// OpenFifo will call fifo.OpenFifo to open a fifo. -func (RealOS) OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) { - return fifo.OpenFifo(ctx, fn, flag, perm) -} - -// Stat will call os.Stat to get the status of the given file. -func (RealOS) Stat(name string) (os.FileInfo, error) { - return os.Stat(name) -} - -// ResolveSymbolicLink will follow any symbolic links -func (RealOS) ResolveSymbolicLink(path string) (string, error) { - info, err := os.Lstat(path) - if err != nil { - return "", err - } - if info.Mode()&os.ModeSymlink != os.ModeSymlink { - return path, nil - } - return filepath.EvalSymlinks(path) -} - -// FollowSymlinkInScope will call symlink.FollowSymlinkInScope. -func (RealOS) FollowSymlinkInScope(path, scope string) (string, error) { - return symlink.FollowSymlinkInScope(path, scope) -} - -// CopyFile will copy src file to dest file -func (RealOS) CopyFile(src, dest string, perm os.FileMode) error { - in, err := os.Open(src) - if err != nil { - return err - } - defer in.Close() - - out, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - defer out.Close() - - _, err = io.Copy(out, in) - return err -} - -// WriteFile will call ioutil.WriteFile to write data into a file. -func (RealOS) WriteFile(filename string, data []byte, perm os.FileMode) error { - return ioutil.WriteFile(filename, data, perm) -} - -// Mount will call unix.Mount to mount the file. -func (RealOS) Mount(source string, target string, fstype string, flags uintptr, data string) error { - return unix.Mount(source, target, fstype, flags, data) -} - -// Unmount will call Unmount to unmount the file. -func (RealOS) Unmount(target string) error { - return Unmount(target) -} - -// LookupMount gets mount info of a given path. -func (RealOS) LookupMount(path string) (mount.Info, error) { - return mount.Lookup(path) -} - -// Unmount unmounts the target. It does not return an error in case the target is not mounted. -// In case the target does not exist, the appropriate error is returned. -func Unmount(target string) error { - err := unix.Unmount(target, unix.MNT_DETACH) - if err == unix.EINVAL { - // ignore "not mounted" error - err = nil - } - - return err -} - -// Hostname will call os.Hostname to get the hostname of the host. -func (RealOS) Hostname() (string, error) { - return os.Hostname() -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/registrar/registrar.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/registrar/registrar.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/registrar/registrar.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/registrar/registrar.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package registrar - -import ( - "sync" - - "github.com/pkg/errors" -) - -// Registrar stores one-to-one name<->key mappings. -// Names and keys must be unique. -// Registrar is safe for concurrent access. -type Registrar struct { - lock sync.Mutex - nameToKey map[string]string - keyToName map[string]string -} - -// NewRegistrar creates a new Registrar with the empty indexes. -func NewRegistrar() *Registrar { - return &Registrar{ - nameToKey: make(map[string]string), - keyToName: make(map[string]string), - } -} - -// Reserve registers a name<->key mapping, name or key must not -// be empty. -// Reserve is idempotent. -// Attempting to reserve a conflict key<->name mapping results -// in an error. -// A name<->key reservation is globally unique. -func (r *Registrar) Reserve(name, key string) error { - r.lock.Lock() - defer r.lock.Unlock() - - if name == "" || key == "" { - return errors.Errorf("invalid name %q or key %q", name, key) - } - - if k, exists := r.nameToKey[name]; exists { - if k != key { - return errors.Errorf("name %q is reserved for %q", name, k) - } - return nil - } - - if n, exists := r.keyToName[key]; exists { - if n != name { - return errors.Errorf("key %q is reserved for %q", key, n) - } - return nil - } - - r.nameToKey[name] = key - r.keyToName[key] = name - return nil -} - -// ReleaseByName releases the reserved name<->key mapping by name. -// Once released, the name and the key can be reserved again. -func (r *Registrar) ReleaseByName(name string) { - r.lock.Lock() - defer r.lock.Unlock() - - key, exists := r.nameToKey[name] - if !exists { - return - } - - delete(r.nameToKey, name) - delete(r.keyToName, key) -} - -// ReleaseByKey release the reserved name<->key mapping by key. -func (r *Registrar) ReleaseByKey(key string) { - r.lock.Lock() - defer r.lock.Unlock() - - name, exists := r.keyToName[key] - if !exists { - return - } - - delete(r.nameToKey, name) - delete(r.keyToName, key) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_attach.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_attach.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_attach.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_attach.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "io" - - "github.com/containerd/containerd" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "k8s.io/client-go/tools/remotecommand" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - cio "github.com/containerd/cri/pkg/server/io" -) - -// Attach prepares a streaming endpoint to attach to a running container, and returns the address. -func (c *criService) Attach(ctx context.Context, r *runtime.AttachRequest) (*runtime.AttachResponse, error) { - cntr, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrap(err, "failed to find container in store") - } - state := cntr.Status.Get().State() - if state != runtime.ContainerState_CONTAINER_RUNNING { - return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) - } - return c.streamServer.GetAttach(r) -} - -func (c *criService) attachContainer(ctx context.Context, id string, stdin io.Reader, stdout, stderr io.WriteCloser, - tty bool, resize <-chan remotecommand.TerminalSize) error { - // Get container from our container store. - cntr, err := c.containerStore.Get(id) - if err != nil { - return errors.Wrapf(err, "failed to find container %q in store", id) - } - id = cntr.ID - - state := cntr.Status.Get().State() - if state != runtime.ContainerState_CONTAINER_RUNNING { - return errors.Errorf("container is in %s state", criContainerStateToString(state)) - } - - task, err := cntr.Container.Task(ctx, nil) - if err != nil { - return errors.Wrap(err, "failed to load task") - } - handleResizing(resize, func(size remotecommand.TerminalSize) { - if err := task.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil { - logrus.WithError(err).Errorf("Failed to resize task %q console", id) - } - }) - - opts := cio.AttachOptions{ - Stdin: stdin, - Stdout: stdout, - Stderr: stderr, - Tty: tty, - StdinOnce: cntr.Config.StdinOnce, - CloseStdin: func() error { - return task.CloseIO(ctx, containerd.WithStdinCloser) - }, - } - // TODO(random-liu): Figure out whether we need to support historical output. - cntr.IO.Attach(opts) - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_create.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_create.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_create.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_create.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,1059 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/contrib/apparmor" - "github.com/containerd/containerd/contrib/seccomp" - "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/oci" - "github.com/containerd/typeurl" - "github.com/davecgh/go-spew/spew" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/opencontainers/runc/libcontainer/devices" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/validate" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/syndtr/gocapability/capability" - "golang.org/x/net/context" - "golang.org/x/sys/unix" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/annotations" - customopts "github.com/containerd/cri/pkg/containerd/opts" - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - cio "github.com/containerd/cri/pkg/server/io" - containerstore "github.com/containerd/cri/pkg/store/container" - "github.com/containerd/cri/pkg/util" -) - -const ( - // profileNamePrefix is the prefix for loading profiles on a localhost. Eg. AppArmor localhost/profileName. - profileNamePrefix = "localhost/" // TODO (mikebrow): get localhost/ & runtime/default from CRI kubernetes/kubernetes#51747 - // runtimeDefault indicates that we should use or create a runtime default profile. - runtimeDefault = "runtime/default" - // dockerDefault indicates that we should use or create a docker default profile. - dockerDefault = "docker/default" - // appArmorDefaultProfileName is name to use when creating a default apparmor profile. - appArmorDefaultProfileName = "cri-containerd.apparmor.d" - // unconfinedProfile is a string indicating one should run a pod/containerd without a security profile - unconfinedProfile = "unconfined" - // seccompDefaultProfile is the default seccomp profile. - seccompDefaultProfile = dockerDefault -) - -func init() { - typeurl.Register(&containerstore.Metadata{}, - "github.com/containerd/cri/pkg/store/container", "Metadata") -} - -// CreateContainer creates a new container in the given PodSandbox. -func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateContainerRequest) (_ *runtime.CreateContainerResponse, retErr error) { - config := r.GetConfig() - logrus.Debugf("Container config %+v", config) - sandboxConfig := r.GetSandboxConfig() - sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) - if err != nil { - return nil, errors.Wrapf(err, "failed to find sandbox id %q", r.GetPodSandboxId()) - } - sandboxID := sandbox.ID - s, err := sandbox.Container.Task(ctx, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox container task") - } - sandboxPid := s.Pid() - - // Generate unique id and name for the container and reserve the name. - // Reserve the container name to avoid concurrent `CreateContainer` request creating - // the same container. - id := util.GenerateID() - name := makeContainerName(config.GetMetadata(), sandboxConfig.GetMetadata()) - logrus.Debugf("Generated id %q for container %q", id, name) - if err = c.containerNameIndex.Reserve(name, id); err != nil { - return nil, errors.Wrapf(err, "failed to reserve container name %q", name) - } - defer func() { - // Release the name if the function returns with an error. - if retErr != nil { - c.containerNameIndex.ReleaseByName(name) - } - }() - - // Create initial internal container metadata. - meta := containerstore.Metadata{ - ID: id, - Name: name, - SandboxID: sandboxID, - Config: config, - } - - // Prepare container image snapshot. For container, the image should have - // been pulled before creating the container, so do not ensure the image. - image, err := c.localResolve(config.GetImage().GetImage()) - if err != nil { - return nil, errors.Wrapf(err, "failed to resolve image %q", config.GetImage().GetImage()) - } - - // Run container using the same runtime with sandbox. - sandboxInfo, err := sandbox.Container.Info(ctx) - if err != nil { - return nil, errors.Wrapf(err, "failed to get sandbox %q info", sandboxID) - } - - // Create container root directory. - containerRootDir := c.getContainerRootDir(id) - if err = c.os.MkdirAll(containerRootDir, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create container root directory %q", - containerRootDir) - } - defer func() { - if retErr != nil { - // Cleanup the container root directory. - if err = c.os.RemoveAll(containerRootDir); err != nil { - logrus.WithError(err).Errorf("Failed to remove container root directory %q", - containerRootDir) - } - } - }() - volatileContainerRootDir := c.getVolatileContainerRootDir(id) - if err = c.os.MkdirAll(volatileContainerRootDir, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create volatile container root directory %q", - volatileContainerRootDir) - } - defer func() { - if retErr != nil { - // Cleanup the volatile container root directory. - if err = c.os.RemoveAll(volatileContainerRootDir); err != nil { - logrus.WithError(err).Errorf("Failed to remove volatile container root directory %q", - volatileContainerRootDir) - } - } - }() - - // Create container volumes mounts. - volumeMounts := c.generateVolumeMounts(containerRootDir, config.GetMounts(), &image.ImageSpec.Config) - - // Generate container runtime spec. - mounts := c.generateContainerMounts(sandboxID, config) - - spec, err := c.generateContainerSpec(id, sandboxID, sandboxPid, config, sandboxConfig, &image.ImageSpec.Config, append(mounts, volumeMounts...)) - if err != nil { - return nil, errors.Wrapf(err, "failed to generate container %q spec", id) - } - - logrus.Debugf("Container %q spec: %#+v", id, spew.NewFormatter(spec)) - - // Set snapshotter before any other options. - opts := []containerd.NewContainerOpts{ - containerd.WithSnapshotter(c.config.ContainerdConfig.Snapshotter), - // Prepare container rootfs. This is always writeable even if - // the container wants a readonly rootfs since we want to give - // the runtime (runc) a chance to modify (e.g. to create mount - // points corresponding to spec.Mounts) before making the - // rootfs readonly (requested by spec.Root.Readonly). - customopts.WithNewSnapshot(id, image.Image), - } - - if len(volumeMounts) > 0 { - mountMap := make(map[string]string) - for _, v := range volumeMounts { - mountMap[filepath.Clean(v.HostPath)] = v.ContainerPath - } - opts = append(opts, customopts.WithVolumes(mountMap)) - } - meta.ImageRef = image.ID - meta.StopSignal = image.ImageSpec.Config.StopSignal - - // Get container log path. - if config.GetLogPath() != "" { - meta.LogPath = filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath()) - } - - containerIO, err := cio.NewContainerIO(id, - cio.WithNewFIFOs(volatileContainerRootDir, config.GetTty(), config.GetStdin())) - if err != nil { - return nil, errors.Wrap(err, "failed to create container io") - } - defer func() { - if retErr != nil { - if err := containerIO.Close(); err != nil { - logrus.WithError(err).Errorf("Failed to close container io %q", id) - } - } - }() - - var specOpts []oci.SpecOpts - securityContext := config.GetLinux().GetSecurityContext() - // Set container username. This could only be done by containerd, because it needs - // access to the container rootfs. Pass user name to containerd, and let it overwrite - // the spec for us. - userstr, err := generateUserString( - securityContext.GetRunAsUsername(), - securityContext.GetRunAsUser(), - securityContext.GetRunAsGroup(), - ) - if err != nil { - return nil, errors.Wrap(err, "failed to generate user string") - } - if userstr != "" { - specOpts = append(specOpts, oci.WithUser(userstr)) - } - - if securityContext.GetRunAsUsername() != "" { - userstr = securityContext.GetRunAsUsername() - } else { - // Even if RunAsUser is not set, we still call `GetValue` to get uid 0. - // Because it is still useful to get additional gids for uid 0. - userstr = strconv.FormatInt(securityContext.GetRunAsUser().GetValue(), 10) - } - specOpts = append(specOpts, customopts.WithAdditionalGIDs(userstr)) - - apparmorSpecOpts, err := generateApparmorSpecOpts( - securityContext.GetApparmorProfile(), - securityContext.GetPrivileged(), - c.apparmorEnabled) - if err != nil { - return nil, errors.Wrap(err, "failed to generate apparmor spec opts") - } - if apparmorSpecOpts != nil { - specOpts = append(specOpts, apparmorSpecOpts) - } - - seccompSpecOpts, err := generateSeccompSpecOpts( - securityContext.GetSeccompProfilePath(), - securityContext.GetPrivileged(), - c.seccompEnabled) - if err != nil { - return nil, errors.Wrap(err, "failed to generate seccomp spec opts") - } - if seccompSpecOpts != nil { - specOpts = append(specOpts, seccompSpecOpts) - } - containerLabels := buildLabels(config.Labels, containerKindContainer) - - runtimeOptions, err := getRuntimeOptions(sandboxInfo) - if err != nil { - return nil, errors.Wrap(err, "failed to get runtime options") - } - opts = append(opts, - containerd.WithSpec(spec, specOpts...), - containerd.WithRuntime(sandboxInfo.Runtime.Name, runtimeOptions), - containerd.WithContainerLabels(containerLabels), - containerd.WithContainerExtension(containerMetadataExtension, &meta)) - var cntr containerd.Container - if cntr, err = c.client.NewContainer(ctx, id, opts...); err != nil { - return nil, errors.Wrap(err, "failed to create containerd container") - } - defer func() { - if retErr != nil { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - if err := cntr.Delete(deferCtx, containerd.WithSnapshotCleanup); err != nil { - logrus.WithError(err).Errorf("Failed to delete containerd container %q", id) - } - } - }() - - status := containerstore.Status{CreatedAt: time.Now().UnixNano()} - container, err := containerstore.NewContainer(meta, - containerstore.WithStatus(status, containerRootDir), - containerstore.WithContainer(cntr), - containerstore.WithContainerIO(containerIO), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to create internal container object for %q", id) - } - defer func() { - if retErr != nil { - // Cleanup container checkpoint on error. - if err := container.Delete(); err != nil { - logrus.WithError(err).Errorf("Failed to cleanup container checkpoint for %q", id) - } - } - }() - - // Add container into container store. - if err := c.containerStore.Add(container); err != nil { - return nil, errors.Wrapf(err, "failed to add container %q into store", id) - } - - return &runtime.CreateContainerResponse{ContainerId: id}, nil -} - -func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxPid uint32, config *runtime.ContainerConfig, - sandboxConfig *runtime.PodSandboxConfig, imageConfig *imagespec.ImageConfig, extraMounts []*runtime.Mount) (*runtimespec.Spec, error) { - // Creates a spec Generator with the default spec. - spec, err := defaultRuntimeSpec(id) - if err != nil { - return nil, err - } - g := newSpecGenerator(spec) - - // Set the relative path to the rootfs of the container from containerd's - // pre-defined directory. - g.SetRootPath(relativeRootfsPath) - - if err := setOCIProcessArgs(&g, config, imageConfig); err != nil { - return nil, err - } - - if config.GetWorkingDir() != "" { - g.SetProcessCwd(config.GetWorkingDir()) - } else if imageConfig.WorkingDir != "" { - g.SetProcessCwd(imageConfig.WorkingDir) - } - - g.SetProcessTerminal(config.GetTty()) - if config.GetTty() { - g.AddProcessEnv("TERM", "xterm") - } - - // Add HOSTNAME env. - hostname := sandboxConfig.GetHostname() - if sandboxConfig.GetHostname() == "" { - hostname, err = c.os.Hostname() - if err != nil { - return nil, err - } - } - g.AddProcessEnv(hostnameEnv, hostname) - - // Apply envs from image config first, so that envs from container config - // can override them. - if err := addImageEnvs(&g, imageConfig.Env); err != nil { - return nil, err - } - for _, e := range config.GetEnvs() { - g.AddProcessEnv(e.GetKey(), e.GetValue()) - } - - securityContext := config.GetLinux().GetSecurityContext() - selinuxOpt := securityContext.GetSelinuxOptions() - processLabel, mountLabel, err := initSelinuxOpts(selinuxOpt) - if err != nil { - return nil, errors.Wrapf(err, "failed to init selinux options %+v", securityContext.GetSelinuxOptions()) - } - - // Merge extra mounts and CRI mounts. - mounts := mergeMounts(config.GetMounts(), extraMounts) - if err := c.addOCIBindMounts(&g, mounts, mountLabel); err != nil { - return nil, errors.Wrapf(err, "failed to set OCI bind mounts %+v", mounts) - } - - // Apply masked paths if specified. - // When `MaskedPaths` is not specified, keep runtime default for backward compatibility; - // When `MaskedPaths` is specified, but length is zero, clear masked path list. - if securityContext.GetMaskedPaths() != nil { - g.Config.Linux.MaskedPaths = nil - for _, path := range securityContext.GetMaskedPaths() { - g.AddLinuxMaskedPaths(path) - } - } - - // Apply readonly paths if specified. - if securityContext.GetReadonlyPaths() != nil { - g.Config.Linux.ReadonlyPaths = nil - for _, path := range securityContext.GetReadonlyPaths() { - g.AddLinuxReadonlyPaths(path) - } - } - - if securityContext.GetPrivileged() { - if !sandboxConfig.GetLinux().GetSecurityContext().GetPrivileged() { - return nil, errors.New("no privileged container allowed in sandbox") - } - if err := setOCIPrivileged(&g, config); err != nil { - return nil, err - } - } else { // not privileged - if err := c.addOCIDevices(&g, config.GetDevices()); err != nil { - return nil, errors.Wrapf(err, "failed to set devices mapping %+v", config.GetDevices()) - } - - if err := setOCICapabilities(&g, securityContext.GetCapabilities()); err != nil { - return nil, errors.Wrapf(err, "failed to set capabilities %+v", - securityContext.GetCapabilities()) - } - } - // Clear all ambient capabilities. The implication of non-root + caps - // is not clearly defined in Kubernetes. - // See https://github.com/kubernetes/kubernetes/issues/56374 - // Keep docker's behavior for now. - g.Config.Process.Capabilities.Ambient = []string{} - - g.SetProcessSelinuxLabel(processLabel) - g.SetLinuxMountLabel(mountLabel) - - // TODO: Figure out whether we should set no new privilege for sandbox container by default - g.SetProcessNoNewPrivileges(securityContext.GetNoNewPrivs()) - - // TODO(random-liu): [P1] Set selinux options (privileged or not). - - g.SetRootReadonly(securityContext.GetReadonlyRootfs()) - - setOCILinuxResource(&g, config.GetLinux().GetResources()) - - if sandboxConfig.GetLinux().GetCgroupParent() != "" { - cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id, - c.config.SystemdCgroup) - g.SetLinuxCgroupsPath(cgroupsPath) - } - - // Set namespaces, share namespace with sandbox container. - setOCINamespaces(&g, securityContext.GetNamespaceOptions(), sandboxPid) - - supplementalGroups := securityContext.GetSupplementalGroups() - for _, group := range supplementalGroups { - g.AddProcessAdditionalGid(uint32(group)) - } - - g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeContainer) - g.AddAnnotation(annotations.SandboxID, sandboxID) - - return g.Config, nil -} - -// generateVolumeMounts sets up image volumes for container. Rely on the removal of container -// root directory to do cleanup. Note that image volume will be skipped, if there is criMounts -// specified with the same destination. -func (c *criService) generateVolumeMounts(containerRootDir string, criMounts []*runtime.Mount, config *imagespec.ImageConfig) []*runtime.Mount { - if len(config.Volumes) == 0 { - return nil - } - var mounts []*runtime.Mount - for dst := range config.Volumes { - if isInCRIMounts(dst, criMounts) { - // Skip the image volume, if there is CRI defined volume mapping. - // TODO(random-liu): This should be handled by Kubelet in the future. - // Kubelet should decide what to use for image volume, and also de-duplicate - // the image volume and user mounts. - continue - } - volumeID := util.GenerateID() - src := filepath.Join(containerRootDir, "volumes", volumeID) - // addOCIBindMounts will create these volumes. - mounts = append(mounts, &runtime.Mount{ - ContainerPath: dst, - HostPath: src, - // Use default mount propagation. - // TODO(random-liu): What about selinux relabel? - }) - } - return mounts -} - -// generateContainerMounts sets up necessary container mounts including /dev/shm, /etc/hosts -// and /etc/resolv.conf. -func (c *criService) generateContainerMounts(sandboxID string, config *runtime.ContainerConfig) []*runtime.Mount { - var mounts []*runtime.Mount - securityContext := config.GetLinux().GetSecurityContext() - if !isInCRIMounts(etcHostname, config.GetMounts()) { - // /etc/hostname is added since 1.1.6, 1.2.4 and 1.3. - // For in-place upgrade, the old sandbox doesn't have the hostname file, - // do not mount this in that case. - // TODO(random-liu): Remove the check and always mount this when - // containerd 1.1 and 1.2 are deprecated. - hostpath := c.getSandboxHostname(sandboxID) - if _, err := c.os.Stat(hostpath); err == nil { - mounts = append(mounts, &runtime.Mount{ - ContainerPath: etcHostname, - HostPath: hostpath, - Readonly: securityContext.GetReadonlyRootfs(), - }) - } - } - - if !isInCRIMounts(etcHosts, config.GetMounts()) { - mounts = append(mounts, &runtime.Mount{ - ContainerPath: etcHosts, - HostPath: c.getSandboxHosts(sandboxID), - Readonly: securityContext.GetReadonlyRootfs(), - }) - } - - // Mount sandbox resolv.config. - // TODO: Need to figure out whether we should always mount it as read-only - if !isInCRIMounts(resolvConfPath, config.GetMounts()) { - mounts = append(mounts, &runtime.Mount{ - ContainerPath: resolvConfPath, - HostPath: c.getResolvPath(sandboxID), - Readonly: securityContext.GetReadonlyRootfs(), - }) - } - - if !isInCRIMounts(devShm, config.GetMounts()) { - sandboxDevShm := c.getSandboxDevShm(sandboxID) - if securityContext.GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE { - sandboxDevShm = devShm - } - mounts = append(mounts, &runtime.Mount{ - ContainerPath: devShm, - HostPath: sandboxDevShm, - Readonly: false, - }) - } - return mounts -} - -// setOCIProcessArgs sets process args. It returns error if the final arg list -// is empty. -func setOCIProcessArgs(g *generator, config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) error { - command, args := config.GetCommand(), config.GetArgs() - // The following logic is migrated from https://github.com/moby/moby/blob/master/daemon/commit.go - // TODO(random-liu): Clearly define the commands overwrite behavior. - if len(command) == 0 { - // Copy array to avoid data race. - if len(args) == 0 { - args = append([]string{}, imageConfig.Cmd...) - } - if command == nil { - command = append([]string{}, imageConfig.Entrypoint...) - } - } - if len(command) == 0 && len(args) == 0 { - return errors.New("no command specified") - } - g.SetProcessArgs(append(command, args...)) - return nil -} - -// addImageEnvs adds environment variables from image config. It returns error if -// an invalid environment variable is encountered. -func addImageEnvs(g *generator, imageEnvs []string) error { - for _, e := range imageEnvs { - kv := strings.SplitN(e, "=", 2) - if len(kv) != 2 { - return errors.Errorf("invalid environment variable %q", e) - } - g.AddProcessEnv(kv[0], kv[1]) - } - return nil -} - -func setOCIPrivileged(g *generator, config *runtime.ContainerConfig) error { - // Add all capabilities in privileged mode. - g.SetupPrivileged(true) - setOCIBindMountsPrivileged(g) - if err := setOCIDevicesPrivileged(g); err != nil { - return errors.Wrapf(err, "failed to set devices mapping %+v", config.GetDevices()) - } - return nil -} - -func clearReadOnly(m *runtimespec.Mount) { - var opt []string - for _, o := range m.Options { - if o != "ro" { - opt = append(opt, o) - } - } - m.Options = append(opt, "rw") -} - -// addDevices set device mapping without privilege. -func (c *criService) addOCIDevices(g *generator, devs []*runtime.Device) error { - spec := g.Config - for _, device := range devs { - path, err := c.os.ResolveSymbolicLink(device.HostPath) - if err != nil { - return err - } - dev, err := devices.DeviceFromPath(path, device.Permissions) - if err != nil { - return err - } - rd := runtimespec.LinuxDevice{ - Path: device.ContainerPath, - Type: string(dev.Type), - Major: dev.Major, - Minor: dev.Minor, - UID: &dev.Uid, - GID: &dev.Gid, - } - g.AddDevice(rd) - spec.Linux.Resources.Devices = append(spec.Linux.Resources.Devices, runtimespec.LinuxDeviceCgroup{ - Allow: true, - Type: string(dev.Type), - Major: &dev.Major, - Minor: &dev.Minor, - Access: dev.Permissions, - }) - } - return nil -} - -// addDevices set device mapping with privilege. -func setOCIDevicesPrivileged(g *generator) error { - spec := g.Config - hostDevices, err := devices.HostDevices() - if err != nil { - return err - } - for _, hostDevice := range hostDevices { - rd := runtimespec.LinuxDevice{ - Path: hostDevice.Path, - Type: string(hostDevice.Type), - Major: hostDevice.Major, - Minor: hostDevice.Minor, - UID: &hostDevice.Uid, - GID: &hostDevice.Gid, - } - if hostDevice.Major == 0 && hostDevice.Minor == 0 { - // Invalid device, most likely a symbolic link, skip it. - continue - } - g.AddDevice(rd) - } - spec.Linux.Resources.Devices = []runtimespec.LinuxDeviceCgroup{ - { - Allow: true, - Access: "rwm", - }, - } - return nil -} - -// addOCIBindMounts adds bind mounts. -func (c *criService) addOCIBindMounts(g *generator, mounts []*runtime.Mount, mountLabel string) error { - // Sort mounts in number of parts. This ensures that high level mounts don't - // shadow other mounts. - sort.Sort(orderedMounts(mounts)) - - // Mount cgroup into the container as readonly, which inherits docker's behavior. - g.AddMount(runtimespec.Mount{ - Source: "cgroup", - Destination: "/sys/fs/cgroup", - Type: "cgroup", - Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"}, - }) - - // Copy all mounts from default mounts, except for - // - mounts overriden by supplied mount; - // - all mounts under /dev if a supplied /dev is present. - mountSet := make(map[string]struct{}) - for _, m := range mounts { - mountSet[filepath.Clean(m.ContainerPath)] = struct{}{} - } - defaultMounts := g.Mounts() - g.ClearMounts() - for _, m := range defaultMounts { - dst := filepath.Clean(m.Destination) - if _, ok := mountSet[dst]; ok { - // filter out mount overridden by a supplied mount - continue - } - if _, mountDev := mountSet["/dev"]; mountDev && strings.HasPrefix(dst, "/dev/") { - // filter out everything under /dev if /dev is a supplied mount - continue - } - g.AddMount(m) - } - - for _, mount := range mounts { - dst := mount.GetContainerPath() - src := mount.GetHostPath() - // Create the host path if it doesn't exist. - // TODO(random-liu): Add CRI validation test for this case. - if _, err := c.os.Stat(src); err != nil { - if !os.IsNotExist(err) { - return errors.Wrapf(err, "failed to stat %q", src) - } - if err := c.os.MkdirAll(src, 0755); err != nil { - return errors.Wrapf(err, "failed to mkdir %q", src) - } - } - // TODO(random-liu): Add cri-containerd integration test or cri validation test - // for this. - src, err := c.os.ResolveSymbolicLink(src) - if err != nil { - return errors.Wrapf(err, "failed to resolve symlink %q", src) - } - - options := []string{"rbind"} - switch mount.GetPropagation() { - case runtime.MountPropagation_PROPAGATION_PRIVATE: - options = append(options, "rprivate") - // Since default root propogation in runc is rprivate ignore - // setting the root propagation - case runtime.MountPropagation_PROPAGATION_BIDIRECTIONAL: - if err := ensureShared(src, c.os.LookupMount); err != nil { - return err - } - options = append(options, "rshared") - g.SetLinuxRootPropagation("rshared") // nolint: errcheck - case runtime.MountPropagation_PROPAGATION_HOST_TO_CONTAINER: - if err := ensureSharedOrSlave(src, c.os.LookupMount); err != nil { - return err - } - options = append(options, "rslave") - if g.Config.Linux.RootfsPropagation != "rshared" && - g.Config.Linux.RootfsPropagation != "rslave" { - g.SetLinuxRootPropagation("rslave") // nolint: errcheck - } - default: - logrus.Warnf("Unknown propagation mode for hostPath %q", mount.HostPath) - options = append(options, "rprivate") - } - - // NOTE(random-liu): we don't change all mounts to `ro` when root filesystem - // is readonly. This is different from docker's behavior, but make more sense. - if mount.GetReadonly() { - options = append(options, "ro") - } else { - options = append(options, "rw") - } - - if mount.GetSelinuxRelabel() { - if err := label.Relabel(src, mountLabel, true); err != nil && err != unix.ENOTSUP { - return errors.Wrapf(err, "relabel %q with %q failed", src, mountLabel) - } - } - g.AddMount(runtimespec.Mount{ - Source: src, - Destination: dst, - Type: "bind", - Options: options, - }) - } - - return nil -} - -func setOCIBindMountsPrivileged(g *generator) { - spec := g.Config - // clear readonly for /sys and cgroup - for i, m := range spec.Mounts { - if filepath.Clean(spec.Mounts[i].Destination) == "/sys" { - clearReadOnly(&spec.Mounts[i]) - } - if m.Type == "cgroup" { - clearReadOnly(&spec.Mounts[i]) - } - } - spec.Linux.ReadonlyPaths = nil - spec.Linux.MaskedPaths = nil -} - -// setOCILinuxResource set container resource limit. -func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResources) { - if resources == nil { - return - } - g.SetLinuxResourcesCPUPeriod(uint64(resources.GetCpuPeriod())) - g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota()) - g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares())) - g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes()) - g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj())) - g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus()) - g.SetLinuxResourcesCPUMems(resources.GetCpusetMems()) -} - -// getOCICapabilitiesList returns a list of all available capabilities. -func getOCICapabilitiesList() []string { - var caps []string - for _, cap := range capability.List() { - if cap > validate.LastCap() { - continue - } - caps = append(caps, "CAP_"+strings.ToUpper(cap.String())) - } - return caps -} - -// Adds capabilities to all sets relevant to root (bounding, permitted, effective, inheritable) -func addProcessRootCapability(g *generator, c string) error { - if err := g.AddProcessCapabilityBounding(c); err != nil { - return err - } - if err := g.AddProcessCapabilityPermitted(c); err != nil { - return err - } - if err := g.AddProcessCapabilityEffective(c); err != nil { - return err - } - if err := g.AddProcessCapabilityInheritable(c); err != nil { - return err - } - return nil -} - -// Drops capabilities to all sets relevant to root (bounding, permitted, effective, inheritable) -func dropProcessRootCapability(g *generator, c string) error { - if err := g.DropProcessCapabilityBounding(c); err != nil { - return err - } - if err := g.DropProcessCapabilityPermitted(c); err != nil { - return err - } - if err := g.DropProcessCapabilityEffective(c); err != nil { - return err - } - if err := g.DropProcessCapabilityInheritable(c); err != nil { - return err - } - return nil -} - -// setOCICapabilities adds/drops process capabilities. -func setOCICapabilities(g *generator, capabilities *runtime.Capability) error { - if capabilities == nil { - return nil - } - - // Add/drop all capabilities if "all" is specified, so that - // following individual add/drop could still work. E.g. - // AddCapabilities: []string{"ALL"}, DropCapabilities: []string{"CHOWN"} - // will be all capabilities without `CAP_CHOWN`. - if util.InStringSlice(capabilities.GetAddCapabilities(), "ALL") { - for _, c := range getOCICapabilitiesList() { - if err := addProcessRootCapability(g, c); err != nil { - return err - } - } - } - if util.InStringSlice(capabilities.GetDropCapabilities(), "ALL") { - for _, c := range getOCICapabilitiesList() { - if err := dropProcessRootCapability(g, c); err != nil { - return err - } - } - } - - for _, c := range capabilities.GetAddCapabilities() { - if strings.ToUpper(c) == "ALL" { - continue - } - // Capabilities in CRI doesn't have `CAP_` prefix, so add it. - if err := addProcessRootCapability(g, "CAP_"+strings.ToUpper(c)); err != nil { - return err - } - } - - for _, c := range capabilities.GetDropCapabilities() { - if strings.ToUpper(c) == "ALL" { - continue - } - if err := dropProcessRootCapability(g, "CAP_"+strings.ToUpper(c)); err != nil { - return err - } - } - return nil -} - -// setOCINamespaces sets namespaces. -func setOCINamespaces(g *generator, namespaces *runtime.NamespaceOption, sandboxPid uint32) { - g.AddOrReplaceLinuxNamespace(string(runtimespec.NetworkNamespace), getNetworkNamespace(sandboxPid)) // nolint: errcheck - g.AddOrReplaceLinuxNamespace(string(runtimespec.IPCNamespace), getIPCNamespace(sandboxPid)) // nolint: errcheck - g.AddOrReplaceLinuxNamespace(string(runtimespec.UTSNamespace), getUTSNamespace(sandboxPid)) // nolint: errcheck - // Do not share pid namespace if namespace mode is CONTAINER. - if namespaces.GetPid() != runtime.NamespaceMode_CONTAINER { - g.AddOrReplaceLinuxNamespace(string(runtimespec.PIDNamespace), getPIDNamespace(sandboxPid)) // nolint: errcheck - } -} - -// defaultRuntimeSpec returns a default runtime spec used in cri-containerd. -func defaultRuntimeSpec(id string) (*runtimespec.Spec, error) { - // GenerateSpec needs namespace. - ctx := ctrdutil.NamespacedContext() - spec, err := oci.GenerateSpec(ctx, nil, &containers.Container{ID: id}) - if err != nil { - return nil, err - } - - // Remove `/run` mount - // TODO(random-liu): Mount tmpfs for /run and handle copy-up. - var mounts []runtimespec.Mount - for _, mount := range spec.Mounts { - if filepath.Clean(mount.Destination) == "/run" { - continue - } - mounts = append(mounts, mount) - } - spec.Mounts = mounts - - // Make sure no default seccomp/apparmor is specified - if spec.Process != nil { - spec.Process.ApparmorProfile = "" - } - if spec.Linux != nil { - spec.Linux.Seccomp = nil - } - - // Remove default rlimits (See issue #515) - spec.Process.Rlimits = nil - - return spec, nil -} - -// generateSeccompSpecOpts generates containerd SpecOpts for seccomp. -func generateSeccompSpecOpts(seccompProf string, privileged, seccompEnabled bool) (oci.SpecOpts, error) { - if privileged { - // Do not set seccomp profile when container is privileged - return nil, nil - } - // Set seccomp profile - if seccompProf == runtimeDefault || seccompProf == dockerDefault { - // use correct default profile (Eg. if not configured otherwise, the default is docker/default) - seccompProf = seccompDefaultProfile - } - if !seccompEnabled { - if seccompProf != "" && seccompProf != unconfinedProfile { - return nil, errors.New("seccomp is not supported") - } - return nil, nil - } - switch seccompProf { - case "", unconfinedProfile: - // Do not set seccomp profile. - return nil, nil - case dockerDefault: - // Note: WithDefaultProfile specOpts must be added after capabilities - return seccomp.WithDefaultProfile(), nil - default: - // Require and Trim default profile name prefix - if !strings.HasPrefix(seccompProf, profileNamePrefix) { - return nil, errors.Errorf("invalid seccomp profile %q", seccompProf) - } - return seccomp.WithProfile(strings.TrimPrefix(seccompProf, profileNamePrefix)), nil - } -} - -// generateApparmorSpecOpts generates containerd SpecOpts for apparmor. -func generateApparmorSpecOpts(apparmorProf string, privileged, apparmorEnabled bool) (oci.SpecOpts, error) { - if !apparmorEnabled { - // Should fail loudly if user try to specify apparmor profile - // but we don't support it. - if apparmorProf != "" && apparmorProf != unconfinedProfile { - return nil, errors.New("apparmor is not supported") - } - return nil, nil - } - switch apparmorProf { - case runtimeDefault: - // TODO (mikebrow): delete created apparmor default profile - return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil - case unconfinedProfile: - return nil, nil - case "": - // Based on kubernetes#51746, default apparmor profile should be applied - // for non-privileged container when apparmor is not specified. - if privileged { - return nil, nil - } - return apparmor.WithDefaultProfile(appArmorDefaultProfileName), nil - default: - // Require and Trim default profile name prefix - if !strings.HasPrefix(apparmorProf, profileNamePrefix) { - return nil, errors.Errorf("invalid apparmor profile %q", apparmorProf) - } - return apparmor.WithProfile(strings.TrimPrefix(apparmorProf, profileNamePrefix)), nil - } -} - -// Ensure mount point on which path is mounted, is shared. -func ensureShared(path string, lookupMount func(string) (mount.Info, error)) error { - mountInfo, err := lookupMount(path) - if err != nil { - return err - } - - // Make sure source mount point is shared. - optsSplit := strings.Split(mountInfo.Optional, " ") - for _, opt := range optsSplit { - if strings.HasPrefix(opt, "shared:") { - return nil - } - } - - return errors.Errorf("path %q is mounted on %q but it is not a shared mount", path, mountInfo.Mountpoint) -} - -// Ensure mount point on which path is mounted, is either shared or slave. -func ensureSharedOrSlave(path string, lookupMount func(string) (mount.Info, error)) error { - mountInfo, err := lookupMount(path) - if err != nil { - return err - } - // Make sure source mount point is shared. - optsSplit := strings.Split(mountInfo.Optional, " ") - for _, opt := range optsSplit { - if strings.HasPrefix(opt, "shared:") { - return nil - } else if strings.HasPrefix(opt, "master:") { - return nil - } - } - return errors.Errorf("path %q is mounted on %q but it is not a shared or slave mount", path, mountInfo.Mountpoint) -} - -// generateUserString generates valid user string based on OCI Image Spec v1.0.0. -// TODO(random-liu): Add group name support in CRI. -func generateUserString(username string, uid, gid *runtime.Int64Value) (string, error) { - var userstr, groupstr string - if uid != nil { - userstr = strconv.FormatInt(uid.GetValue(), 10) - } - if username != "" { - userstr = username - } - if gid != nil { - groupstr = strconv.FormatInt(gid.GetValue(), 10) - } - if userstr == "" { - if groupstr != "" { - return "", errors.Errorf("user group %q is specified without user", groupstr) - } - return "", nil - } - if groupstr != "" { - userstr = userstr + ":" + groupstr - } - return userstr, nil -} - -// mergeMounts merge CRI mounts with extra mounts. If a mount destination -// is mounted by both a CRI mount and an extra mount, the CRI mount will -// be kept. -func mergeMounts(criMounts, extraMounts []*runtime.Mount) []*runtime.Mount { - var mounts []*runtime.Mount - mounts = append(mounts, criMounts...) - // Copy all mounts from extra mounts, except for mounts overriden by CRI. - for _, e := range extraMounts { - found := false - for _, c := range criMounts { - if filepath.Clean(e.ContainerPath) == filepath.Clean(c.ContainerPath) { - found = true - break - } - } - if !found { - mounts = append(mounts, e) - } - } - return mounts -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_exec.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_exec.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_exec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_exec.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// Exec prepares a streaming endpoint to execute a command in the container, and returns the address. -func (c *criService) Exec(ctx context.Context, r *runtime.ExecRequest) (*runtime.ExecResponse, error) { - cntr, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrapf(err, "failed to find container %q in store", r.GetContainerId()) - } - state := cntr.Status.Get().State() - if state != runtime.ContainerState_CONTAINER_RUNNING { - return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) - } - return c.streamServer.GetExec(r) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_execsync.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_execsync.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_execsync.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_execsync.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "bytes" - "io" - "time" - - "github.com/containerd/containerd" - containerdio "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "golang.org/x/sys/unix" - "k8s.io/client-go/tools/remotecommand" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - cioutil "github.com/containerd/cri/pkg/ioutil" - cio "github.com/containerd/cri/pkg/server/io" - "github.com/containerd/cri/pkg/util" -) - -// ExecSync executes a command in the container, and returns the stdout output. -// If command exits with a non-zero exit code, an error is returned. -func (c *criService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (*runtime.ExecSyncResponse, error) { - var stdout, stderr bytes.Buffer - exitCode, err := c.execInContainer(ctx, r.GetContainerId(), execOptions{ - cmd: r.GetCmd(), - stdout: cioutil.NewNopWriteCloser(&stdout), - stderr: cioutil.NewNopWriteCloser(&stderr), - timeout: time.Duration(r.GetTimeout()) * time.Second, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to exec in container") - } - - return &runtime.ExecSyncResponse{ - Stdout: stdout.Bytes(), - Stderr: stderr.Bytes(), - ExitCode: int32(*exitCode), - }, nil -} - -// execOptions specifies how to execute command in container. -type execOptions struct { - cmd []string - stdin io.Reader - stdout io.WriteCloser - stderr io.WriteCloser - tty bool - resize <-chan remotecommand.TerminalSize - timeout time.Duration -} - -// execInContainer executes a command inside the container synchronously, and -// redirects stdio stream properly. -func (c *criService) execInContainer(ctx context.Context, id string, opts execOptions) (*uint32, error) { - // Cancel the context before returning to ensure goroutines are stopped. - // This is important, because if `Start` returns error, `Wait` will hang - // forever unless we cancel the context. - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // Get container from our container store. - cntr, err := c.containerStore.Get(id) - if err != nil { - return nil, errors.Wrapf(err, "failed to find container %q in store", id) - } - id = cntr.ID - - state := cntr.Status.Get().State() - if state != runtime.ContainerState_CONTAINER_RUNNING { - return nil, errors.Errorf("container is in %s state", criContainerStateToString(state)) - } - - container := cntr.Container - spec, err := container.Spec(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get container spec") - } - task, err := container.Task(ctx, nil) - if err != nil { - return nil, errors.Wrap(err, "failed to load task") - } - if opts.tty { - g := newSpecGenerator(spec) - g.AddProcessEnv("TERM", "xterm") - spec = g.Config - } - pspec := spec.Process - pspec.Args = opts.cmd - pspec.Terminal = opts.tty - - if opts.stdout == nil { - opts.stdout = cio.NewDiscardLogger() - } - if opts.stderr == nil { - opts.stderr = cio.NewDiscardLogger() - } - execID := util.GenerateID() - logrus.Debugf("Generated exec id %q for container %q", execID, id) - volatileRootDir := c.getVolatileContainerRootDir(id) - var execIO *cio.ExecIO - process, err := task.Exec(ctx, execID, pspec, - func(id string) (containerdio.IO, error) { - var err error - execIO, err = cio.NewExecIO(id, volatileRootDir, opts.tty, opts.stdin != nil) - return execIO, err - }, - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to create exec %q", execID) - } - defer func() { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - if _, err := process.Delete(deferCtx); err != nil { - logrus.WithError(err).Errorf("Failed to delete exec process %q for container %q", execID, id) - } - }() - - exitCh, err := process.Wait(ctx) - if err != nil { - return nil, errors.Wrapf(err, "failed to wait for process %q", execID) - } - if err := process.Start(ctx); err != nil { - return nil, errors.Wrapf(err, "failed to start exec %q", execID) - } - - handleResizing(opts.resize, func(size remotecommand.TerminalSize) { - if err := process.Resize(ctx, uint32(size.Width), uint32(size.Height)); err != nil { - logrus.WithError(err).Errorf("Failed to resize process %q console for container %q", execID, id) - } - }) - - attachDone := execIO.Attach(cio.AttachOptions{ - Stdin: opts.stdin, - Stdout: opts.stdout, - Stderr: opts.stderr, - Tty: opts.tty, - StdinOnce: true, - CloseStdin: func() error { - return process.CloseIO(ctx, containerd.WithStdinCloser) - }, - }) - - var timeoutCh <-chan time.Time - if opts.timeout == 0 { - // Do not set timeout if it's 0. - timeoutCh = make(chan time.Time) - } else { - timeoutCh = time.After(opts.timeout) - } - select { - case <-timeoutCh: - //TODO(Abhi) Use context.WithDeadline instead of timeout. - // Ignore the not found error because the process may exit itself before killing. - if err := process.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) { - return nil, errors.Wrapf(err, "failed to kill exec %q", execID) - } - // Wait for the process to be killed. - exitRes := <-exitCh - logrus.Infof("Timeout received while waiting for exec process kill %q code %d and error %v", - execID, exitRes.ExitCode(), exitRes.Error()) - <-attachDone - logrus.Debugf("Stream pipe for exec process %q done", execID) - return nil, errors.Errorf("timeout %v exceeded", opts.timeout) - case exitRes := <-exitCh: - code, _, err := exitRes.Result() - logrus.Infof("Exec process %q exits with exit code %d and error %v", execID, code, err) - if err != nil { - return nil, errors.Wrapf(err, "failed while waiting for exec %q", execID) - } - <-attachDone - logrus.Debugf("Stream pipe for exec process %q done", execID) - return &code, nil - } -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_list.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_list.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_list.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_list.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "golang.org/x/net/context" - - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - containerstore "github.com/containerd/cri/pkg/store/container" -) - -// ListContainers lists all containers matching the filter. -func (c *criService) ListContainers(ctx context.Context, r *runtime.ListContainersRequest) (*runtime.ListContainersResponse, error) { - // List all containers from store. - containersInStore := c.containerStore.List() - - var containers []*runtime.Container - for _, container := range containersInStore { - containers = append(containers, toCRIContainer(container)) - } - - containers = c.filterCRIContainers(containers, r.GetFilter()) - return &runtime.ListContainersResponse{Containers: containers}, nil -} - -// toCRIContainer converts internal container object into CRI container. -func toCRIContainer(container containerstore.Container) *runtime.Container { - status := container.Status.Get() - return &runtime.Container{ - Id: container.ID, - PodSandboxId: container.SandboxID, - Metadata: container.Config.GetMetadata(), - Image: container.Config.GetImage(), - ImageRef: container.ImageRef, - State: status.State(), - CreatedAt: status.CreatedAt, - Labels: container.Config.GetLabels(), - Annotations: container.Config.GetAnnotations(), - } -} - -func (c *criService) normalizeContainerFilter(filter *runtime.ContainerFilter) { - if cntr, err := c.containerStore.Get(filter.GetId()); err == nil { - filter.Id = cntr.ID - } - if sb, err := c.sandboxStore.Get(filter.GetPodSandboxId()); err == nil { - filter.PodSandboxId = sb.ID - } -} - -// filterCRIContainers filters CRIContainers. -func (c *criService) filterCRIContainers(containers []*runtime.Container, filter *runtime.ContainerFilter) []*runtime.Container { - if filter == nil { - return containers - } - - c.normalizeContainerFilter(filter) - filtered := []*runtime.Container{} - for _, cntr := range containers { - if filter.GetId() != "" && filter.GetId() != cntr.Id { - continue - } - if filter.GetPodSandboxId() != "" && filter.GetPodSandboxId() != cntr.PodSandboxId { - continue - } - if filter.GetState() != nil && filter.GetState().GetState() != cntr.State { - continue - } - if filter.GetLabelSelector() != nil { - match := true - for k, v := range filter.GetLabelSelector() { - got, ok := cntr.Labels[k] - if !ok || got != v { - match = false - break - } - } - if !match { - continue - } - } - filtered = append(filtered, cntr) - } - - return filtered -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_log_reopen.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_log_reopen.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_log_reopen.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_log_reopen.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/pkg/errors" - "golang.org/x/net/context" - - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// ReopenContainerLog asks the cri plugin to reopen the stdout/stderr log file for the container. -// This is often called after the log file has been rotated. -func (c *criService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (*runtime.ReopenContainerLogResponse, error) { - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) - } - - if container.Status.Get().State() != runtime.ContainerState_CONTAINER_RUNNING { - return nil, errors.New("container is not running") - } - - // Create new container logger and replace the existing ones. - stdoutWC, stderrWC, err := c.createContainerLoggers(container.LogPath, container.Config.GetTty()) - if err != nil { - return nil, err - } - oldStdoutWC, oldStderrWC := container.IO.AddOutput("log", stdoutWC, stderrWC) - if oldStdoutWC != nil { - oldStdoutWC.Close() - } - if oldStderrWC != nil { - oldStderrWC.Close() - } - return &runtime.ReopenContainerLogResponse{}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_remove.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_remove.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_remove.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_remove.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/containerd/containerd" - "github.com/containerd/containerd/errdefs" - "github.com/docker/docker/pkg/system" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/log" - "github.com/containerd/cri/pkg/store" - containerstore "github.com/containerd/cri/pkg/store/container" -) - -// RemoveContainer removes the container. -// TODO(random-liu): Forcibly stop container if it's running. -func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (_ *runtime.RemoveContainerResponse, retErr error) { - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - if err != store.ErrNotExist { - return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) - } - // Do not return error if container metadata doesn't exist. - log.Tracef("RemoveContainer called for container %q that does not exist", r.GetContainerId()) - return &runtime.RemoveContainerResponse{}, nil - } - id := container.ID - - // Set removing state to prevent other start/remove operations against this container - // while it's being removed. - if err := setContainerRemoving(container); err != nil { - return nil, errors.Wrapf(err, "failed to set removing state for container %q", id) - } - defer func() { - if retErr != nil { - // Reset removing if remove failed. - if err := resetContainerRemoving(container); err != nil { - logrus.WithError(err).Errorf("failed to reset removing state for container %q", id) - } - } - }() - - // NOTE(random-liu): Docker set container to "Dead" state when start removing the - // container so as to avoid start/restart the container again. However, for current - // kubelet implementation, we'll never start a container once we decide to remove it, - // so we don't need the "Dead" state for now. - - // Delete containerd container. - if err := container.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil { - if !errdefs.IsNotFound(err) { - return nil, errors.Wrapf(err, "failed to delete containerd container %q", id) - } - log.Tracef("Remove called for containerd container %q that does not exist", id) - } - - // Delete container checkpoint. - if err := container.Delete(); err != nil { - return nil, errors.Wrapf(err, "failed to delete container checkpoint for %q", id) - } - - containerRootDir := c.getContainerRootDir(id) - if err := system.EnsureRemoveAll(containerRootDir); err != nil { - return nil, errors.Wrapf(err, "failed to remove container root directory %q", - containerRootDir) - } - volatileContainerRootDir := c.getVolatileContainerRootDir(id) - if err := system.EnsureRemoveAll(volatileContainerRootDir); err != nil { - return nil, errors.Wrapf(err, "failed to remove volatile container root directory %q", - volatileContainerRootDir) - } - - c.containerStore.Delete(id) - - c.containerNameIndex.ReleaseByKey(id) - - return &runtime.RemoveContainerResponse{}, nil -} - -// setContainerRemoving sets the container into removing state. In removing state, the -// container will not be started or removed again. -func setContainerRemoving(container containerstore.Container) error { - return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { - // Do not remove container if it's still running or unknown. - if status.State() == runtime.ContainerState_CONTAINER_RUNNING { - return status, errors.New("container is still running, to stop first") - } - if status.State() == runtime.ContainerState_CONTAINER_UNKNOWN { - return status, errors.New("container state is unknown, to stop first") - } - if status.Removing { - return status, errors.New("container is already in removing state") - } - status.Removing = true - return status, nil - }) -} - -// resetContainerRemoving resets the container removing state on remove failure. So -// that we could remove the container again. -func resetContainerRemoving(container containerstore.Container) error { - return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { - status.Removing = false - return status, nil - }) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_start.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_start.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_start.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_start.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "io" - "os" - "time" - - "github.com/containerd/containerd" - containerdio "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - cioutil "github.com/containerd/cri/pkg/ioutil" - cio "github.com/containerd/cri/pkg/server/io" - containerstore "github.com/containerd/cri/pkg/store/container" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// StartContainer starts the container. -func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (retRes *runtime.StartContainerResponse, retErr error) { - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) - } - - var startErr error - // update container status in one transaction to avoid race with event monitor. - if err := container.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { - // Always apply status change no matter startContainer fails or not. Because startContainer - // may change container state no matter it fails or succeeds. - startErr = c.startContainer(ctx, container, &status) - return status, nil - }); startErr != nil { - return nil, startErr - } else if err != nil { - return nil, errors.Wrapf(err, "failed to update container %q metadata", container.ID) - } - return &runtime.StartContainerResponse{}, nil -} - -// startContainer actually starts the container. The function needs to be run in one transaction. Any updates -// to the status passed in will be applied no matter the function returns error or not. -func (c *criService) startContainer(ctx context.Context, - cntr containerstore.Container, - status *containerstore.Status) (retErr error) { - id := cntr.ID - meta := cntr.Metadata - container := cntr.Container - config := meta.Config - - // Return error if container is not in created state. - if status.State() != runtime.ContainerState_CONTAINER_CREATED { - return errors.Errorf("container %q is in %s state", id, criContainerStateToString(status.State())) - } - // Do not start the container when there is a removal in progress. - if status.Removing { - return errors.Errorf("container %q is in removing state", id) - } - - defer func() { - if retErr != nil { - // Set container to exited if fail to start. - status.Pid = 0 - status.FinishedAt = time.Now().UnixNano() - status.ExitCode = errorStartExitCode - status.Reason = errorStartReason - status.Message = retErr.Error() - } - }() - - // Get sandbox config from sandbox store. - sandbox, err := c.sandboxStore.Get(meta.SandboxID) - if err != nil { - return errors.Wrapf(err, "sandbox %q not found", meta.SandboxID) - } - sandboxID := meta.SandboxID - if sandbox.Status.Get().State != sandboxstore.StateReady { - return errors.Errorf("sandbox container %q is not running", sandboxID) - } - - ioCreation := func(id string) (_ containerdio.IO, err error) { - stdoutWC, stderrWC, err := c.createContainerLoggers(meta.LogPath, config.GetTty()) - if err != nil { - return nil, errors.Wrap(err, "failed to create container loggers") - } - cntr.IO.AddOutput("log", stdoutWC, stderrWC) - cntr.IO.Pipe() - return cntr.IO, nil - } - - ctrInfo, err := container.Info(ctx) - if err != nil { - return errors.Wrap(err, "failed to get container info") - } - - var taskOpts []containerd.NewTaskOpts - // TODO(random-liu): Remove this after shim v1 is deprecated. - if c.config.NoPivot && ctrInfo.Runtime.Name == linuxRuntime { - taskOpts = append(taskOpts, containerd.WithNoPivotRoot) - } - task, err := container.NewTask(ctx, ioCreation, taskOpts...) - if err != nil { - return errors.Wrap(err, "failed to create containerd task") - } - defer func() { - if retErr != nil { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - // It's possible that task is deleted by event monitor. - if _, err := task.Delete(deferCtx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { - logrus.WithError(err).Errorf("Failed to delete containerd task %q", id) - } - } - }() - - // Start containerd task. - if err := task.Start(ctx); err != nil { - return errors.Wrapf(err, "failed to start containerd task %q", id) - } - - // Update container start timestamp. - status.Pid = task.Pid() - status.StartedAt = time.Now().UnixNano() - return nil -} - -// createContainerLoggers creates container loggers and return write closer for stdout and stderr. -func (c *criService) createContainerLoggers(logPath string, tty bool) (stdout io.WriteCloser, stderr io.WriteCloser, err error) { - if logPath != "" { - // Only generate container log when log path is specified. - f, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to create and open log file") - } - defer func() { - if err != nil { - f.Close() - } - }() - var stdoutCh, stderrCh <-chan struct{} - wc := cioutil.NewSerialWriteCloser(f) - stdout, stdoutCh = cio.NewCRILogger(logPath, wc, cio.Stdout, c.config.MaxContainerLogLineSize) - // Only redirect stderr when there is no tty. - if !tty { - stderr, stderrCh = cio.NewCRILogger(logPath, wc, cio.Stderr, c.config.MaxContainerLogLineSize) - } - go func() { - if stdoutCh != nil { - <-stdoutCh - } - if stderrCh != nil { - <-stderrCh - } - logrus.Debugf("Finish redirecting log file %q, closing it", logPath) - f.Close() - }() - } else { - stdout = cio.NewDiscardLogger() - stderr = cio.NewDiscardLogger() - } - return -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stats.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stats.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stats.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stats.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - tasks "github.com/containerd/containerd/api/services/tasks/v1" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// ContainerStats returns stats of the container. If the container does not -// exist, the call returns an error. -func (c *criService) ContainerStats(ctx context.Context, in *runtime.ContainerStatsRequest) (*runtime.ContainerStatsResponse, error) { - cntr, err := c.containerStore.Get(in.GetContainerId()) - if err != nil { - return nil, errors.Wrap(err, "failed to find container") - } - request := &tasks.MetricsRequest{Filters: []string{"id==" + cntr.ID}} - resp, err := c.client.TaskService().Metrics(ctx, request) - if err != nil { - return nil, errors.Wrap(err, "failed to fetch metrics for task") - } - if len(resp.Metrics) != 1 { - return nil, errors.Errorf("unexpected metrics response: %+v", resp.Metrics) - } - - cs, err := c.getContainerMetrics(cntr.Metadata, resp.Metrics[0]) - if err != nil { - return nil, errors.Wrap(err, "failed to decode container metrics") - } - return &runtime.ContainerStatsResponse{Stats: cs}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stats_list.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stats_list.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stats_list.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stats_list.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/containerd/cgroups" - tasks "github.com/containerd/containerd/api/services/tasks/v1" - "github.com/containerd/containerd/api/types" - "github.com/containerd/typeurl" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - containerstore "github.com/containerd/cri/pkg/store/container" -) - -// ListContainerStats returns stats of all running containers. -func (c *criService) ListContainerStats( - ctx context.Context, - in *runtime.ListContainerStatsRequest, -) (*runtime.ListContainerStatsResponse, error) { - request, containers, err := c.buildTaskMetricsRequest(in) - if err != nil { - return nil, errors.Wrap(err, "failed to build metrics request") - } - resp, err := c.client.TaskService().Metrics(ctx, &request) - if err != nil { - return nil, errors.Wrap(err, "failed to fetch metrics for tasks") - } - criStats, err := c.toCRIContainerStats(resp.Metrics, containers) - if err != nil { - return nil, errors.Wrap(err, "failed to convert to cri containerd stats format") - } - return criStats, nil -} - -func (c *criService) toCRIContainerStats( - stats []*types.Metric, - containers []containerstore.Container, -) (*runtime.ListContainerStatsResponse, error) { - statsMap := make(map[string]*types.Metric) - for _, stat := range stats { - statsMap[stat.ID] = stat - } - containerStats := new(runtime.ListContainerStatsResponse) - for _, cntr := range containers { - cs, err := c.getContainerMetrics(cntr.Metadata, statsMap[cntr.ID]) - if err != nil { - return nil, errors.Wrapf(err, "failed to decode container metrics for %q", cntr.ID) - } - containerStats.Stats = append(containerStats.Stats, cs) - } - return containerStats, nil -} - -func (c *criService) getContainerMetrics( - meta containerstore.Metadata, - stats *types.Metric, -) (*runtime.ContainerStats, error) { - var cs runtime.ContainerStats - var usedBytes, inodesUsed uint64 - sn, err := c.snapshotStore.Get(meta.ID) - // If snapshotstore doesn't have cached snapshot information - // set WritableLayer usage to zero - if err == nil { - usedBytes = sn.Size - inodesUsed = sn.Inodes - } - cs.WritableLayer = &runtime.FilesystemUsage{ - Timestamp: sn.Timestamp, - FsId: &runtime.FilesystemIdentifier{ - Mountpoint: c.imageFSPath, - }, - UsedBytes: &runtime.UInt64Value{Value: usedBytes}, - InodesUsed: &runtime.UInt64Value{Value: inodesUsed}, - } - cs.Attributes = &runtime.ContainerAttributes{ - Id: meta.ID, - Metadata: meta.Config.GetMetadata(), - Labels: meta.Config.GetLabels(), - Annotations: meta.Config.GetAnnotations(), - } - - if stats != nil { - s, err := typeurl.UnmarshalAny(stats.Data) - if err != nil { - return nil, errors.Wrap(err, "failed to extract container metrics") - } - metrics := s.(*cgroups.Metrics) - if metrics.CPU != nil && metrics.CPU.Usage != nil { - cs.Cpu = &runtime.CpuUsage{ - Timestamp: stats.Timestamp.UnixNano(), - UsageCoreNanoSeconds: &runtime.UInt64Value{Value: metrics.CPU.Usage.Total}, - } - } - if metrics.Memory != nil && metrics.Memory.Usage != nil { - cs.Memory = &runtime.MemoryUsage{ - Timestamp: stats.Timestamp.UnixNano(), - WorkingSetBytes: &runtime.UInt64Value{ - Value: getWorkingSet(metrics.Memory), - }, - } - } - } - - return &cs, nil -} - -func (c *criService) normalizeContainerStatsFilter(filter *runtime.ContainerStatsFilter) { - if cntr, err := c.containerStore.Get(filter.GetId()); err == nil { - filter.Id = cntr.ID - } - if sb, err := c.sandboxStore.Get(filter.GetPodSandboxId()); err == nil { - filter.PodSandboxId = sb.ID - } -} - -// buildTaskMetricsRequest constructs a tasks.MetricsRequest based on -// the information in the stats request and the containerStore -func (c *criService) buildTaskMetricsRequest( - r *runtime.ListContainerStatsRequest, -) (tasks.MetricsRequest, []containerstore.Container, error) { - var req tasks.MetricsRequest - if r.GetFilter() == nil { - return req, nil, nil - } - c.normalizeContainerStatsFilter(r.GetFilter()) - var containers []containerstore.Container - for _, cntr := range c.containerStore.List() { - if r.GetFilter().GetId() != "" && cntr.ID != r.GetFilter().GetId() { - continue - } - if r.GetFilter().GetPodSandboxId() != "" && cntr.SandboxID != r.GetFilter().GetPodSandboxId() { - continue - } - if r.GetFilter().GetLabelSelector() != nil && - !matchLabelSelector(r.GetFilter().GetLabelSelector(), cntr.Config.GetLabels()) { - continue - } - containers = append(containers, cntr) - req.Filters = append(req.Filters, "id=="+cntr.ID) - } - return req, containers, nil -} - -func matchLabelSelector(selector, labels map[string]string) bool { - for k, v := range selector { - if val, ok := labels[k]; ok { - if v != val { - return false - } - } else { - return false - } - } - return true -} - -// getWorkingSet calculates workingset memory from cgroup memory stats. -// The caller should make sure memory is not nil. -// workingset = usage - total_inactive_file -func getWorkingSet(memory *cgroups.MemoryStat) uint64 { - if memory.Usage == nil { - return 0 - } - var workingSet uint64 - if memory.TotalInactiveFile < memory.Usage.Usage { - workingSet = memory.Usage.Usage - memory.TotalInactiveFile - } - return workingSet -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,173 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "encoding/json" - - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/store" - containerstore "github.com/containerd/cri/pkg/store/container" -) - -// ContainerStatus inspects the container and returns the status. -func (c *criService) ContainerStatus(ctx context.Context, r *runtime.ContainerStatusRequest) (*runtime.ContainerStatusResponse, error) { - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) - } - - // TODO(random-liu): Clean up the following logic in CRI. - // Current assumption: - // * ImageSpec in container config is image ID. - // * ImageSpec in container status is image tag. - // * ImageRef in container status is repo digest. - spec := container.Config.GetImage() - imageRef := container.ImageRef - image, err := c.imageStore.Get(imageRef) - if err != nil { - if err != store.ErrNotExist { - return nil, errors.Wrapf(err, "failed to get image %q", imageRef) - } - } else { - repoTags, repoDigests := parseImageReferences(image.References) - if len(repoTags) > 0 { - // Based on current behavior of dockershim, this field should be - // image tag. - spec = &runtime.ImageSpec{Image: repoTags[0]} - } - if len(repoDigests) > 0 { - // Based on the CRI definition, this field will be consumed by user. - imageRef = repoDigests[0] - } - } - status := toCRIContainerStatus(container, spec, imageRef) - if status.GetCreatedAt() == 0 { - // CRI doesn't allow CreatedAt == 0. - info, err := container.Container.Info(ctx) - if err != nil { - return nil, errors.Wrapf(err, "failed to get CreatedAt in %q state", status.State) - } - status.CreatedAt = info.CreatedAt.UnixNano() - } - - info, err := toCRIContainerInfo(ctx, container, r.GetVerbose()) - if err != nil { - return nil, errors.Wrap(err, "failed to get verbose container info") - } - - return &runtime.ContainerStatusResponse{ - Status: status, - Info: info, - }, nil -} - -// toCRIContainerStatus converts internal container object to CRI container status. -func toCRIContainerStatus(container containerstore.Container, spec *runtime.ImageSpec, imageRef string) *runtime.ContainerStatus { - meta := container.Metadata - status := container.Status.Get() - reason := status.Reason - if status.State() == runtime.ContainerState_CONTAINER_EXITED && reason == "" { - if status.ExitCode == 0 { - reason = completeExitReason - } else { - reason = errorExitReason - } - } - - return &runtime.ContainerStatus{ - Id: meta.ID, - Metadata: meta.Config.GetMetadata(), - State: status.State(), - CreatedAt: status.CreatedAt, - StartedAt: status.StartedAt, - FinishedAt: status.FinishedAt, - ExitCode: status.ExitCode, - Image: spec, - ImageRef: imageRef, - Reason: reason, - Message: status.Message, - Labels: meta.Config.GetLabels(), - Annotations: meta.Config.GetAnnotations(), - Mounts: meta.Config.GetMounts(), - LogPath: meta.LogPath, - } -} - -// ContainerInfo is extra information for a container. -type ContainerInfo struct { - // TODO(random-liu): Add sandboxID in CRI container status. - SandboxID string `json:"sandboxID"` - Pid uint32 `json:"pid"` - Removing bool `json:"removing"` - SnapshotKey string `json:"snapshotKey"` - Snapshotter string `json:"snapshotter"` - RuntimeType string `json:"runtimeType"` - RuntimeOptions interface{} `json:"runtimeOptions"` - Config *runtime.ContainerConfig `json:"config"` - RuntimeSpec *runtimespec.Spec `json:"runtimeSpec"` -} - -// toCRIContainerInfo converts internal container object information to CRI container status response info map. -func toCRIContainerInfo(ctx context.Context, container containerstore.Container, verbose bool) (map[string]string, error) { - if !verbose { - return nil, nil - } - - meta := container.Metadata - status := container.Status.Get() - - // TODO(random-liu): Change CRI status info to use array instead of map. - ci := &ContainerInfo{ - SandboxID: container.SandboxID, - Pid: status.Pid, - Removing: status.Removing, - Config: meta.Config, - } - - var err error - ci.RuntimeSpec, err = container.Container.Spec(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get container runtime spec") - } - - ctrInfo, err := container.Container.Info(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get container info") - } - ci.SnapshotKey = ctrInfo.SnapshotKey - ci.Snapshotter = ctrInfo.Snapshotter - - runtimeOptions, err := getRuntimeOptions(ctrInfo) - if err != nil { - return nil, errors.Wrap(err, "failed to get runtime options") - } - ci.RuntimeType = ctrInfo.Runtime.Name - ci.RuntimeOptions = runtimeOptions - - infoBytes, err := json.Marshal(ci) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal info %v", ci) - } - return map[string]string{ - "info": string(infoBytes), - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stop.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stop.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_stop.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_stop.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "time" - - "github.com/containerd/containerd" - eventtypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/errdefs" - "github.com/docker/docker/pkg/signal" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "golang.org/x/sys/unix" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/store" - containerstore "github.com/containerd/cri/pkg/store/container" -) - -// killContainerTimeout is the timeout that we wait for the container to -// be SIGKILLed. -// The timeout is set to 1 min, because the default CRI operation timeout -// for StopContainer is (2 min + stop timeout). Set to 1 min, so that we -// have enough time for kill(all=true) and kill(all=false). -const killContainerTimeout = 1 * time.Minute - -// StopContainer stops a running container with a grace period (i.e., timeout). -func (c *criService) StopContainer(ctx context.Context, r *runtime.StopContainerRequest) (*runtime.StopContainerResponse, error) { - // Get container config from container store. - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrapf(err, "an error occurred when try to find container %q", r.GetContainerId()) - } - - if err := c.stopContainer(ctx, container, time.Duration(r.GetTimeout())*time.Second); err != nil { - return nil, err - } - - return &runtime.StopContainerResponse{}, nil -} - -// stopContainer stops a container based on the container metadata. -func (c *criService) stopContainer(ctx context.Context, container containerstore.Container, timeout time.Duration) error { - id := container.ID - - // Return without error if container is not running. This makes sure that - // stop only takes real action after the container is started. - state := container.Status.Get().State() - if state != runtime.ContainerState_CONTAINER_RUNNING && - state != runtime.ContainerState_CONTAINER_UNKNOWN { - logrus.Infof("Container to stop %q must be in running or unknown state, current state %q", - id, criContainerStateToString(state)) - return nil - } - - task, err := container.Container.Task(ctx, nil) - if err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrapf(err, "failed to get task for container %q", id) - } - // Don't return for unknown state, some cleanup needs to be done. - if state != runtime.ContainerState_CONTAINER_UNKNOWN { - return nil - } - // Task is an interface, explicitly set it to nil just in case. - task = nil - } - - // Handle unknown state. - if state == runtime.ContainerState_CONTAINER_UNKNOWN { - status, err := getTaskStatus(ctx, task) - if err != nil { - return errors.Wrapf(err, "failed to get task status for %q", id) - } - switch status.Status { - case containerd.Running, containerd.Created: - // The task is still running, continue stopping the task. - case containerd.Stopped: - // The task has exited. If the task exited after containerd - // started, the event monitor will receive its exit event; if it - // exited before containerd started, the event monitor will never - // receive its exit event. - // However, we can't tell that because the task state was not - // successfully loaded during containerd start (container is - // in UNKNOWN state). - // So always do cleanup here, just in case that we've missed the - // exit event. - return cleanupUnknownContainer(ctx, id, status, container) - default: - return errors.Wrapf(err, "unsupported task status %q", status.Status) - } - } - - // We only need to kill the task. The event handler will Delete the - // task from containerd after it handles the Exited event. - if timeout > 0 { - stopSignal := "SIGTERM" - if container.StopSignal != "" { - stopSignal = container.StopSignal - } else { - // The image may have been deleted, and the `StopSignal` field is - // just introduced to handle that. - // However, for containers created before the `StopSignal` field is - // introduced, still try to get the stop signal from the image config. - // If the image has been deleted, logging an error and using the - // default SIGTERM is still better than returning error and leaving - // the container unstoppable. (See issue #990) - // TODO(random-liu): Remove this logic when containerd 1.2 is deprecated. - image, err := c.imageStore.Get(container.ImageRef) - if err != nil { - if err != store.ErrNotExist { - return errors.Wrapf(err, "failed to get image %q", container.ImageRef) - } - logrus.Warningf("Image %q not found, stop container with signal %q", container.ImageRef, stopSignal) - } else { - if image.ImageSpec.Config.StopSignal != "" { - stopSignal = image.ImageSpec.Config.StopSignal - } - } - } - sig, err := signal.ParseSignal(stopSignal) - if err != nil { - return errors.Wrapf(err, "failed to parse stop signal %q", stopSignal) - } - logrus.Infof("Stop container %q with signal %v", id, sig) - if err = task.Kill(ctx, sig); err != nil && !errdefs.IsNotFound(err) { - return errors.Wrapf(err, "failed to stop container %q", id) - } - - if err = c.waitContainerStop(ctx, container, timeout); err == nil || errors.Cause(err) == ctx.Err() { - // Do not SIGKILL container if the context is cancelled. - return err - } - logrus.WithError(err).Errorf("An error occurs during waiting for container %q to be stopped", id) - } - - logrus.Infof("Kill container %q", id) - if err = task.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) { - return errors.Wrapf(err, "failed to kill container %q", id) - } - - // Wait for a fixed timeout until container stop is observed by event monitor. - if err = c.waitContainerStop(ctx, container, killContainerTimeout); err == nil { - return nil - } - return errors.Wrapf(err, "an error occurs during waiting for container %q to be killed", id) -} - -// waitContainerStop waits for container to be stopped until timeout exceeds or context is cancelled. -func (c *criService) waitContainerStop(ctx context.Context, container containerstore.Container, timeout time.Duration) error { - timeoutTimer := time.NewTimer(timeout) - defer timeoutTimer.Stop() - select { - case <-ctx.Done(): - return errors.Wrapf(ctx.Err(), "wait container %q is cancelled", container.ID) - case <-timeoutTimer.C: - return errors.Errorf("wait container %q stop timeout", container.ID) - case <-container.Stopped(): - return nil - } -} - -// cleanupUnknownContainer cleanup stopped container in unknown state. -func cleanupUnknownContainer(ctx context.Context, id string, status containerd.Status, - cntr containerstore.Container) error { - // Reuse handleContainerExit to do the cleanup. - // NOTE(random-liu): If the task did exit after containerd started, both - // the event monitor and the cleanup function would update the container - // state. The final container state will be whatever being updated first. - // There is no way to completely avoid this race condition, and for best - // effort unknown state container cleanup, this seems acceptable. - return handleContainerExit(ctx, &eventtypes.TaskExit{ - ContainerID: id, - ID: id, - Pid: 0, - ExitStatus: status.ExitStatus, - ExitedAt: status.ExitTime, - }, cntr) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_update_resources.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_update_resources.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/container_update_resources.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/container_update_resources.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - gocontext "context" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/typeurl" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - containerstore "github.com/containerd/cri/pkg/store/container" - "github.com/containerd/cri/pkg/util" -) - -// UpdateContainerResources updates ContainerConfig of the container. -func (c *criService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (retRes *runtime.UpdateContainerResourcesResponse, retErr error) { - container, err := c.containerStore.Get(r.GetContainerId()) - if err != nil { - return nil, errors.Wrap(err, "failed to find container") - } - // Update resources in status update transaction, so that: - // 1) There won't be race condition with container start. - // 2) There won't be concurrent resource update to the same container. - if err := container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) { - return status, c.updateContainerResources(ctx, container, r.GetLinux(), status) - }); err != nil { - return nil, errors.Wrap(err, "failed to update resources") - } - return &runtime.UpdateContainerResourcesResponse{}, nil -} - -func (c *criService) updateContainerResources(ctx context.Context, - cntr containerstore.Container, - resources *runtime.LinuxContainerResources, - status containerstore.Status) (retErr error) { - id := cntr.ID - // Do not update the container when there is a removal in progress. - if status.Removing { - return errors.Errorf("container %q is in removing state", id) - } - - // Update container spec. If the container is not started yet, updating - // spec makes sure that the resource limits are correct when start; - // if the container is already started, updating spec is still required, - // the spec will become our source of truth for resource limits. - oldSpec, err := cntr.Container.Spec(ctx) - if err != nil { - return errors.Wrap(err, "failed to get container spec") - } - newSpec, err := updateOCILinuxResource(oldSpec, resources) - if err != nil { - return errors.Wrap(err, "failed to update resource in spec") - } - - if err := updateContainerSpec(ctx, cntr.Container, newSpec); err != nil { - return err - } - defer func() { - if retErr != nil { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - // Reset spec on error. - if err := updateContainerSpec(deferCtx, cntr.Container, oldSpec); err != nil { - logrus.WithError(err).Errorf("Failed to update spec %+v for container %q", oldSpec, id) - } - } - }() - - // If container is not running, only update spec is enough, new resource - // limit will be applied when container start. - if status.State() != runtime.ContainerState_CONTAINER_RUNNING { - return nil - } - - task, err := cntr.Container.Task(ctx, nil) - if err != nil { - if errdefs.IsNotFound(err) { - // Task exited already. - return nil - } - return errors.Wrap(err, "failed to get task") - } - // newSpec.Linux won't be nil - if err := task.Update(ctx, containerd.WithResources(newSpec.Linux.Resources)); err != nil { - if errdefs.IsNotFound(err) { - // Task exited already. - return nil - } - return errors.Wrap(err, "failed to update resources") - } - return nil -} - -// updateContainerSpec updates container spec. -func updateContainerSpec(ctx context.Context, cntr containerd.Container, spec *runtimespec.Spec) error { - any, err := typeurl.MarshalAny(spec) - if err != nil { - return errors.Wrapf(err, "failed to marshal spec %+v", spec) - } - if err := cntr.Update(ctx, func(ctx gocontext.Context, client *containerd.Client, c *containers.Container) error { - c.Spec = any - return nil - }); err != nil { - return errors.Wrap(err, "failed to update container spec") - } - return nil -} - -// updateOCILinuxResource updates container resource limit. -func updateOCILinuxResource(spec *runtimespec.Spec, new *runtime.LinuxContainerResources) (*runtimespec.Spec, error) { - // Copy to make sure old spec is not changed. - var cloned runtimespec.Spec - if err := util.DeepCopy(&cloned, spec); err != nil { - return nil, errors.Wrap(err, "failed to deep copy") - } - g := newSpecGenerator(&cloned) - - if new.GetCpuPeriod() != 0 { - g.SetLinuxResourcesCPUPeriod(uint64(new.GetCpuPeriod())) - } - if new.GetCpuQuota() != 0 { - g.SetLinuxResourcesCPUQuota(new.GetCpuQuota()) - } - if new.GetCpuShares() != 0 { - g.SetLinuxResourcesCPUShares(uint64(new.GetCpuShares())) - } - if new.GetMemoryLimitInBytes() != 0 { - g.SetLinuxResourcesMemoryLimit(new.GetMemoryLimitInBytes()) - } - // OOMScore is not updatable. - if new.GetCpusetCpus() != "" { - g.SetLinuxResourcesCPUCpus(new.GetCpusetCpus()) - } - if new.GetCpusetMems() != "" { - g.SetLinuxResourcesCPUMems(new.GetCpusetMems()) - } - - return g.Config, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/events.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/events.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/events.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/events.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,428 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "sync" - "time" - - "github.com/containerd/containerd" - eventtypes "github.com/containerd/containerd/api/events" - containerdio "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/events" - "github.com/containerd/typeurl" - gogotypes "github.com/gogo/protobuf/types" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "k8s.io/apimachinery/pkg/util/clock" - - "github.com/containerd/cri/pkg/constants" - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - "github.com/containerd/cri/pkg/store" - containerstore "github.com/containerd/cri/pkg/store/container" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -const ( - backOffInitDuration = 1 * time.Second - backOffMaxDuration = 5 * time.Minute - backOffExpireCheckDuration = 1 * time.Second - - // handleEventTimeout is the timeout for handling 1 event. Event monitor - // handles events in serial, if one event blocks the event monitor, no - // other events can be handled. - // Add a timeout for each event handling, events that timeout will be requeued and - // handled again in the future. - handleEventTimeout = 10 * time.Second -) - -// eventMonitor monitors containerd event and updates internal state correspondingly. -// TODO(random-liu): Handle event for each container in a separate goroutine. -type eventMonitor struct { - c *criService - ch <-chan *events.Envelope - errCh <-chan error - ctx context.Context - cancel context.CancelFunc - backOff *backOff -} - -type backOff struct { - queuePool map[string]*backOffQueue - // tickerMu is mutex used to protect the ticker. - tickerMu sync.Mutex - ticker *time.Ticker - minDuration time.Duration - maxDuration time.Duration - checkDuration time.Duration - clock clock.Clock -} - -type backOffQueue struct { - events []interface{} - expireTime time.Time - duration time.Duration - clock clock.Clock -} - -// Create new event monitor. New event monitor will start subscribing containerd event. All events -// happen after it should be monitored. -func newEventMonitor(c *criService) *eventMonitor { - ctx, cancel := context.WithCancel(context.Background()) - return &eventMonitor{ - c: c, - ctx: ctx, - cancel: cancel, - backOff: newBackOff(), - } -} - -// subscribe starts to subscribe containerd events. -func (em *eventMonitor) subscribe(subscriber events.Subscriber) { - // note: filters are any match, if you want any match but not in namespace foo - // then you have to manually filter namespace foo - filters := []string{ - `topic=="/tasks/exit"`, - `topic=="/tasks/oom"`, - `topic~="/images/"`, - } - em.ch, em.errCh = subscriber.Subscribe(em.ctx, filters...) -} - -func convertEvent(e *gogotypes.Any) (string, interface{}, error) { - id := "" - evt, err := typeurl.UnmarshalAny(e) - if err != nil { - return "", nil, errors.Wrap(err, "failed to unmarshalany") - } - - switch e := evt.(type) { - case *eventtypes.TaskExit: - id = e.ContainerID - case *eventtypes.TaskOOM: - id = e.ContainerID - case *eventtypes.ImageCreate: - id = e.Name - case *eventtypes.ImageUpdate: - id = e.Name - case *eventtypes.ImageDelete: - id = e.Name - default: - return "", nil, errors.New("unsupported event") - } - return id, evt, nil -} - -// start starts the event monitor which monitors and handles all subscribed events. It returns -// an error channel for the caller to wait for stop errors from the event monitor. -// start must be called after subscribe. -func (em *eventMonitor) start() <-chan error { - errCh := make(chan error) - if em.ch == nil || em.errCh == nil { - panic("event channel is nil") - } - backOffCheckCh := em.backOff.start() - go func() { - defer close(errCh) - for { - select { - case e := <-em.ch: - logrus.Debugf("Received containerd event timestamp - %v, namespace - %q, topic - %q", e.Timestamp, e.Namespace, e.Topic) - if e.Namespace != constants.K8sContainerdNamespace { - logrus.Debugf("Ignoring events in namespace - %q", e.Namespace) - break - } - id, evt, err := convertEvent(e.Event) - if err != nil { - logrus.WithError(err).Errorf("Failed to convert event %+v", e) - break - } - if em.backOff.isInBackOff(id) { - logrus.Infof("Events for %q is in backoff, enqueue event %+v", id, evt) - em.backOff.enBackOff(id, evt) - break - } - if err := em.handleEvent(evt); err != nil { - logrus.WithError(err).Errorf("Failed to handle event %+v for %s", evt, id) - em.backOff.enBackOff(id, evt) - } - case err := <-em.errCh: - // Close errCh in defer directly if there is no error. - if err != nil { - logrus.WithError(err).Errorf("Failed to handle event stream") - errCh <- err - } - return - case <-backOffCheckCh: - ids := em.backOff.getExpiredIDs() - for _, id := range ids { - queue := em.backOff.deBackOff(id) - for i, any := range queue.events { - if err := em.handleEvent(any); err != nil { - logrus.WithError(err).Errorf("Failed to handle backOff event %+v for %s", any, id) - em.backOff.reBackOff(id, queue.events[i:], queue.duration) - break - } - } - } - } - } - }() - return errCh -} - -// stop stops the event monitor. It will close the event channel. -// Once event monitor is stopped, it can't be started. -func (em *eventMonitor) stop() { - em.backOff.stop() - em.cancel() -} - -// handleEvent handles a containerd event. -func (em *eventMonitor) handleEvent(any interface{}) error { - ctx := ctrdutil.NamespacedContext() - ctx, cancel := context.WithTimeout(ctx, handleEventTimeout) - defer cancel() - - switch e := any.(type) { - // If containerd-shim exits unexpectedly, there will be no corresponding event. - // However, containerd could not retrieve container state in that case, so it's - // fine to leave out that case for now. - // TODO(random-liu): [P2] Handle containerd-shim exit. - case *eventtypes.TaskExit: - logrus.Infof("TaskExit event %+v", e) - // Use ID instead of ContainerID to rule out TaskExit event for exec. - cntr, err := em.c.containerStore.Get(e.ID) - if err == nil { - if err := handleContainerExit(ctx, e, cntr); err != nil { - return errors.Wrap(err, "failed to handle container TaskExit event") - } - return nil - } else if err != store.ErrNotExist { - return errors.Wrap(err, "can't find container for TaskExit event") - } - // Use GetAll to include sandbox in init state. - sb, err := em.c.sandboxStore.GetAll(e.ID) - if err == nil { - if err := handleSandboxExit(ctx, e, sb); err != nil { - return errors.Wrap(err, "failed to handle sandbox TaskExit event") - } - return nil - } else if err != store.ErrNotExist { - return errors.Wrap(err, "can't find sandbox for TaskExit event") - } - return nil - case *eventtypes.TaskOOM: - logrus.Infof("TaskOOM event %+v", e) - // For TaskOOM, we only care which container it belongs to. - cntr, err := em.c.containerStore.Get(e.ContainerID) - if err != nil { - if err != store.ErrNotExist { - return errors.Wrap(err, "can't find container for TaskOOM event") - } - return nil - } - err = cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { - status.Reason = oomExitReason - return status, nil - }) - if err != nil { - return errors.Wrap(err, "failed to update container status for TaskOOM event") - } - case *eventtypes.ImageCreate: - logrus.Infof("ImageCreate event %+v", e) - return em.c.updateImage(ctx, e.Name) - case *eventtypes.ImageUpdate: - logrus.Infof("ImageUpdate event %+v", e) - return em.c.updateImage(ctx, e.Name) - case *eventtypes.ImageDelete: - logrus.Infof("ImageDelete event %+v", e) - return em.c.updateImage(ctx, e.Name) - } - - return nil -} - -// handleContainerExit handles TaskExit event for container. -func handleContainerExit(ctx context.Context, e *eventtypes.TaskExit, cntr containerstore.Container) error { - // Attach container IO so that `Delete` could cleanup the stream properly. - task, err := cntr.Container.Task(ctx, - func(*containerdio.FIFOSet) (containerdio.IO, error) { - // We can't directly return cntr.IO here, because - // even if cntr.IO is nil, the cio.IO interface - // is not. - // See https://tour.golang.org/methods/12: - // Note that an interface value that holds a nil - // concrete value is itself non-nil. - if cntr.IO != nil { - return cntr.IO, nil - } - return nil, nil - }, - ) - if err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrapf(err, "failed to load task for container") - } - } else { - // TODO(random-liu): [P1] This may block the loop, we may want to spawn a worker - if _, err = task.Delete(ctx, containerd.WithProcessKill); err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to stop container") - } - // Move on to make sure container status is updated. - } - } - err = cntr.Status.UpdateSync(func(status containerstore.Status) (containerstore.Status, error) { - // If FinishedAt has been set (e.g. with start failure), keep as - // it is. - if status.FinishedAt != 0 { - return status, nil - } - status.Pid = 0 - status.FinishedAt = e.ExitedAt.UnixNano() - status.ExitCode = int32(e.ExitStatus) - return status, nil - }) - if err != nil { - return errors.Wrap(err, "failed to update container state") - } - // Using channel to propagate the information of container stop - cntr.Stop() - return nil -} - -// handleSandboxExit handles TaskExit event for sandbox. -func handleSandboxExit(ctx context.Context, e *eventtypes.TaskExit, sb sandboxstore.Sandbox) error { - // No stream attached to sandbox container. - task, err := sb.Container.Task(ctx, nil) - if err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to load task for sandbox") - } - } else { - // TODO(random-liu): [P1] This may block the loop, we may want to spawn a worker - if _, err = task.Delete(ctx, containerd.WithProcessKill); err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to stop sandbox") - } - // Move on to make sure container status is updated. - } - } - err = sb.Status.Update(func(status sandboxstore.Status) (sandboxstore.Status, error) { - // NOTE(random-liu): We SHOULD NOT change INIT state here. - // If sandbox state is INIT when event monitor receives an TaskExit event, - // it means that sandbox start has failed. In that case, `RunPodSandbox` will - // cleanup everything immediately. - // Once sandbox state goes out of INIT, it becomes visable to the user, which - // is not what we want. - if status.State != sandboxstore.StateInit { - status.State = sandboxstore.StateNotReady - } - status.Pid = 0 - return status, nil - }) - if err != nil { - return errors.Wrap(err, "failed to update sandbox state") - } - // Using channel to propagate the information of sandbox stop - sb.Stop() - return nil -} - -func newBackOff() *backOff { - return &backOff{ - queuePool: map[string]*backOffQueue{}, - minDuration: backOffInitDuration, - maxDuration: backOffMaxDuration, - checkDuration: backOffExpireCheckDuration, - clock: clock.RealClock{}, - } -} - -func (b *backOff) getExpiredIDs() []string { - var ids []string - for id, q := range b.queuePool { - if q.isExpire() { - ids = append(ids, id) - } - } - return ids -} - -func (b *backOff) isInBackOff(key string) bool { - if _, ok := b.queuePool[key]; ok { - return true - } - return false -} - -// enBackOff start to backOff and put event to the tail of queue -func (b *backOff) enBackOff(key string, evt interface{}) { - if queue, ok := b.queuePool[key]; ok { - queue.events = append(queue.events, evt) - return - } - b.queuePool[key] = newBackOffQueue([]interface{}{evt}, b.minDuration, b.clock) -} - -// enBackOff get out the whole queue -func (b *backOff) deBackOff(key string) *backOffQueue { - queue := b.queuePool[key] - delete(b.queuePool, key) - return queue -} - -// enBackOff start to backOff again and put events to the queue -func (b *backOff) reBackOff(key string, events []interface{}, oldDuration time.Duration) { - duration := 2 * oldDuration - if duration > b.maxDuration { - duration = b.maxDuration - } - b.queuePool[key] = newBackOffQueue(events, duration, b.clock) -} - -func (b *backOff) start() <-chan time.Time { - b.tickerMu.Lock() - defer b.tickerMu.Unlock() - b.ticker = time.NewTicker(b.checkDuration) - return b.ticker.C -} - -func (b *backOff) stop() { - b.tickerMu.Lock() - defer b.tickerMu.Unlock() - if b.ticker != nil { - b.ticker.Stop() - } -} - -func newBackOffQueue(events []interface{}, init time.Duration, c clock.Clock) *backOffQueue { - return &backOffQueue{ - events: events, - duration: init, - expireTime: c.Now().Add(init), - clock: c, - } -} - -func (q *backOffQueue) isExpire() bool { - // return time.Now >= expireTime - return !q.clock.Now().Before(q.expireTime) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/helpers.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/helpers.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/helpers.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,605 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "fmt" - "os" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" - "time" - - "github.com/BurntSushi/toml" - "github.com/containerd/containerd" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/runtime/linux/runctypes" - runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" - "github.com/containerd/typeurl" - "github.com/docker/distribution/reference" - imagedigest "github.com/opencontainers/go-digest" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/opencontainers/selinux/go-selinux/label" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - criconfig "github.com/containerd/cri/pkg/config" - "github.com/containerd/cri/pkg/store" - containerstore "github.com/containerd/cri/pkg/store/container" - imagestore "github.com/containerd/cri/pkg/store/image" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" - "github.com/containerd/cri/pkg/util" -) - -const ( - // errorStartReason is the exit reason when fails to start container. - errorStartReason = "StartError" - // errorStartExitCode is the exit code when fails to start container. - // 128 is the same with Docker's behavior. - errorStartExitCode = 128 - // completeExitReason is the exit reason when container exits with code 0. - completeExitReason = "Completed" - // errorExitReason is the exit reason when container exits with code non-zero. - errorExitReason = "Error" - // oomExitReason is the exit reason when process in container is oom killed. - oomExitReason = "OOMKilled" -) - -const ( - // defaultSandboxOOMAdj is default omm adj for sandbox container. (kubernetes#47938). - defaultSandboxOOMAdj = -998 - // defaultSandboxCPUshares is default cpu shares for sandbox container. - defaultSandboxCPUshares = 2 - // defaultShmSize is the default size of the sandbox shm. - defaultShmSize = int64(1024 * 1024 * 64) - // relativeRootfsPath is the rootfs path relative to bundle path. - relativeRootfsPath = "rootfs" - // sandboxesDir contains all sandbox root. A sandbox root is the running - // directory of the sandbox, all files created for the sandbox will be - // placed under this directory. - sandboxesDir = "sandboxes" - // containersDir contains all container root. - containersDir = "containers" - // According to http://man7.org/linux/man-pages/man5/resolv.conf.5.html: - // "The search list is currently limited to six domains with a total of 256 characters." - maxDNSSearches = 6 - // Delimiter used to construct container/sandbox names. - nameDelimiter = "_" - // netNSFormat is the format of network namespace of a process. - netNSFormat = "/proc/%v/ns/net" - // ipcNSFormat is the format of ipc namespace of a process. - ipcNSFormat = "/proc/%v/ns/ipc" - // utsNSFormat is the format of uts namespace of a process. - utsNSFormat = "/proc/%v/ns/uts" - // pidNSFormat is the format of pid namespace of a process. - pidNSFormat = "/proc/%v/ns/pid" - // devShm is the default path of /dev/shm. - devShm = "/dev/shm" - // etcHosts is the default path of /etc/hosts file. - etcHosts = "/etc/hosts" - // etcHostname is the default path of /etc/hostname file. - etcHostname = "/etc/hostname" - // resolvConfPath is the abs path of resolv.conf on host or container. - resolvConfPath = "/etc/resolv.conf" - // hostnameEnv is the key for HOSTNAME env. - hostnameEnv = "HOSTNAME" -) - -const ( - // criContainerdPrefix is common prefix for cri-containerd - criContainerdPrefix = "io.cri-containerd" - // containerKindLabel is a label key indicating container is sandbox container or application container - containerKindLabel = criContainerdPrefix + ".kind" - // containerKindSandbox is a label value indicating container is sandbox container - containerKindSandbox = "sandbox" - // containerKindContainer is a label value indicating container is application container - containerKindContainer = "container" - // imageLabelKey is the label key indicating the image is managed by cri plugin. - imageLabelKey = criContainerdPrefix + ".image" - // imageLabelValue is the label value indicating the image is managed by cri plugin. - imageLabelValue = "managed" - // sandboxMetadataExtension is an extension name that identify metadata of sandbox in CreateContainerRequest - sandboxMetadataExtension = criContainerdPrefix + ".sandbox.metadata" - // containerMetadataExtension is an extension name that identify metadata of container in CreateContainerRequest - containerMetadataExtension = criContainerdPrefix + ".container.metadata" -) - -const ( - // defaultIfName is the default network interface for the pods - defaultIfName = "eth0" - // networkAttachCount is the minimum number of networks the PodSandbox - // attaches to - networkAttachCount = 2 -) - -// Runtime type strings for various runtimes. -const ( - // linuxRuntime is the legacy linux runtime for shim v1. - linuxRuntime = "io.containerd.runtime.v1.linux" - // runcRuntime is the runc runtime for shim v2. - runcRuntime = "io.containerd.runc.v1" -) - -// makeSandboxName generates sandbox name from sandbox metadata. The name -// generated is unique as long as sandbox metadata is unique. -func makeSandboxName(s *runtime.PodSandboxMetadata) string { - return strings.Join([]string{ - s.Name, // 0 - s.Namespace, // 1 - s.Uid, // 2 - fmt.Sprintf("%d", s.Attempt), // 3 - }, nameDelimiter) -} - -// makeContainerName generates container name from sandbox and container metadata. -// The name generated is unique as long as the sandbox container combination is -// unique. -func makeContainerName(c *runtime.ContainerMetadata, s *runtime.PodSandboxMetadata) string { - return strings.Join([]string{ - c.Name, // 0 - s.Name, // 1: pod name - s.Namespace, // 2: pod namespace - s.Uid, // 3: pod uid - fmt.Sprintf("%d", c.Attempt), // 4 - }, nameDelimiter) -} - -// getCgroupsPath generates container cgroups path. -func getCgroupsPath(cgroupsParent, id string, systemdCgroup bool) string { - if systemdCgroup { - // Convert a.slice/b.slice/c.slice to c.slice. - p := path.Base(cgroupsParent) - // runc systemd cgroup path format is "slice:prefix:name". - return strings.Join([]string{p, "cri-containerd", id}, ":") - } - return filepath.Join(cgroupsParent, id) -} - -// getSandboxRootDir returns the root directory for managing sandbox files, -// e.g. hosts files. -func (c *criService) getSandboxRootDir(id string) string { - return filepath.Join(c.config.RootDir, sandboxesDir, id) -} - -// getVolatileSandboxRootDir returns the root directory for managing volatile sandbox files, -// e.g. named pipes. -func (c *criService) getVolatileSandboxRootDir(id string) string { - return filepath.Join(c.config.StateDir, sandboxesDir, id) -} - -// getContainerRootDir returns the root directory for managing container files, -// e.g. state checkpoint. -func (c *criService) getContainerRootDir(id string) string { - return filepath.Join(c.config.RootDir, containersDir, id) -} - -// getVolatileContainerRootDir returns the root directory for managing volatile container files, -// e.g. named pipes. -func (c *criService) getVolatileContainerRootDir(id string) string { - return filepath.Join(c.config.StateDir, containersDir, id) -} - -// getSandboxHostname returns the hostname file path inside the sandbox root directory. -func (c *criService) getSandboxHostname(id string) string { - return filepath.Join(c.getSandboxRootDir(id), "hostname") -} - -// getSandboxHosts returns the hosts file path inside the sandbox root directory. -func (c *criService) getSandboxHosts(id string) string { - return filepath.Join(c.getSandboxRootDir(id), "hosts") -} - -// getResolvPath returns resolv.conf filepath for specified sandbox. -func (c *criService) getResolvPath(id string) string { - return filepath.Join(c.getSandboxRootDir(id), "resolv.conf") -} - -// getSandboxDevShm returns the shm file path inside the sandbox root directory. -func (c *criService) getSandboxDevShm(id string) string { - return filepath.Join(c.getVolatileSandboxRootDir(id), "shm") -} - -// getNetworkNamespace returns the network namespace of a process. -func getNetworkNamespace(pid uint32) string { - return fmt.Sprintf(netNSFormat, pid) -} - -// getIPCNamespace returns the ipc namespace of a process. -func getIPCNamespace(pid uint32) string { - return fmt.Sprintf(ipcNSFormat, pid) -} - -// getUTSNamespace returns the uts namespace of a process. -func getUTSNamespace(pid uint32) string { - return fmt.Sprintf(utsNSFormat, pid) -} - -// getPIDNamespace returns the pid namespace of a process. -func getPIDNamespace(pid uint32) string { - return fmt.Sprintf(pidNSFormat, pid) -} - -// criContainerStateToString formats CRI container state to string. -func criContainerStateToString(state runtime.ContainerState) string { - return runtime.ContainerState_name[int32(state)] -} - -// getRepoDigestAngTag returns image repoDigest and repoTag of the named image reference. -func getRepoDigestAndTag(namedRef reference.Named, digest imagedigest.Digest, schema1 bool) (string, string) { - var repoTag, repoDigest string - if _, ok := namedRef.(reference.NamedTagged); ok { - repoTag = namedRef.String() - } - if _, ok := namedRef.(reference.Canonical); ok { - repoDigest = namedRef.String() - } else if !schema1 { - // digest is not actual repo digest for schema1 image. - repoDigest = namedRef.Name() + "@" + digest.String() - } - return repoDigest, repoTag -} - -// localResolve resolves image reference locally and returns corresponding image metadata. It -// returns store.ErrNotExist if the reference doesn't exist. -func (c *criService) localResolve(refOrID string) (imagestore.Image, error) { - getImageID := func(refOrId string) string { - if _, err := imagedigest.Parse(refOrID); err == nil { - return refOrID - } - return func(ref string) string { - // ref is not image id, try to resolve it locally. - // TODO(random-liu): Handle this error better for debugging. - normalized, err := util.NormalizeImageRef(ref) - if err != nil { - return "" - } - id, err := c.imageStore.Resolve(normalized.String()) - if err != nil { - return "" - } - return id - }(refOrID) - } - - imageID := getImageID(refOrID) - if imageID == "" { - // Try to treat ref as imageID - imageID = refOrID - } - return c.imageStore.Get(imageID) -} - -// getUserFromImage gets uid or user name of the image user. -// If user is numeric, it will be treated as uid; or else, it is treated as user name. -func getUserFromImage(user string) (*int64, string) { - // return both empty if user is not specified in the image. - if user == "" { - return nil, "" - } - // split instances where the id may contain user:group - user = strings.Split(user, ":")[0] - // user could be either uid or user name. Try to interpret as numeric uid. - uid, err := strconv.ParseInt(user, 10, 64) - if err != nil { - // If user is non numeric, assume it's user name. - return nil, user - } - // If user is a numeric uid. - return &uid, "" -} - -// ensureImageExists returns corresponding metadata of the image reference, if image is not -// pulled yet, the function will pull the image. -func (c *criService) ensureImageExists(ctx context.Context, ref string) (*imagestore.Image, error) { - image, err := c.localResolve(ref) - if err != nil && err != store.ErrNotExist { - return nil, errors.Wrapf(err, "failed to get image %q", ref) - } - if err == nil { - return &image, nil - } - // Pull image to ensure the image exists - resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}}) - if err != nil { - return nil, errors.Wrapf(err, "failed to pull image %q", ref) - } - imageID := resp.GetImageRef() - newImage, err := c.imageStore.Get(imageID) - if err != nil { - // It's still possible that someone removed the image right after it is pulled. - return nil, errors.Wrapf(err, "failed to get image %q after pulling", imageID) - } - return &newImage, nil -} - -func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error) { - if selinuxOpt == nil { - return "", "", nil - } - - // Should ignored selinuxOpts if they are incomplete. - if selinuxOpt.GetUser() == "" || - selinuxOpt.GetRole() == "" || - selinuxOpt.GetType() == "" { - return "", "", nil - } - - // make sure the format of "level" is correct. - ok, err := checkSelinuxLevel(selinuxOpt.GetLevel()) - if err != nil || !ok { - return "", "", err - } - - labelOpts := fmt.Sprintf("%s:%s:%s:%s", - selinuxOpt.GetUser(), - selinuxOpt.GetRole(), - selinuxOpt.GetType(), - selinuxOpt.GetLevel()) - - options, err := label.DupSecOpt(labelOpts) - if err != nil { - return "", "", err - } - return label.InitLabels(options) -} - -func checkSelinuxLevel(level string) (bool, error) { - if len(level) == 0 { - return true, nil - } - - matched, err := regexp.MatchString(`^s\d(-s\d)??(:c\d{1,4}((.c\d{1,4})?,c\d{1,4})*(.c\d{1,4})?(,c\d{1,4}(.c\d{1,4})?)*)?$`, level) - if err != nil || !matched { - return false, errors.Wrapf(err, "the format of 'level' %q is not correct", level) - } - return true, nil -} - -// isInCRIMounts checks whether a destination is in CRI mount list. -func isInCRIMounts(dst string, mounts []*runtime.Mount) bool { - for _, m := range mounts { - if filepath.Clean(m.ContainerPath) == filepath.Clean(dst) { - return true - } - } - return false -} - -// filterLabel returns a label filter. Use `%q` here because containerd -// filter needs extra quote to work properly. -func filterLabel(k, v string) string { - return fmt.Sprintf("labels.%q==%q", k, v) -} - -// buildLabel builds the labels from config to be passed to containerd -func buildLabels(configLabels map[string]string, containerType string) map[string]string { - labels := make(map[string]string) - for k, v := range configLabels { - labels[k] = v - } - labels[containerKindLabel] = containerType - return labels -} - -// newSpecGenerator creates a new spec generator for the runtime spec. -func newSpecGenerator(spec *runtimespec.Spec) generator { - g := generate.NewFromSpec(spec) - g.HostSpecific = true - return newCustomGenerator(g) -} - -// generator is a custom generator with some functions overridden -// used by the cri plugin. -// TODO(random-liu): Upstream this fix. -type generator struct { - generate.Generator - envCache map[string]int -} - -func newCustomGenerator(g generate.Generator) generator { - cg := generator{ - Generator: g, - envCache: make(map[string]int), - } - if g.Config != nil && g.Config.Process != nil { - for i, env := range g.Config.Process.Env { - kv := strings.SplitN(env, "=", 2) - cg.envCache[kv[0]] = i - } - } - return cg -} - -// AddProcessEnv overrides the original AddProcessEnv. It uses -// a map to cache and override envs. -func (g *generator) AddProcessEnv(key, value string) { - if len(g.envCache) == 0 { - // Call AddProccessEnv once to initialize the spec. - g.Generator.AddProcessEnv(key, value) - g.envCache[key] = 0 - return - } - spec := g.Config - env := fmt.Sprintf("%s=%s", key, value) - if idx, ok := g.envCache[key]; !ok { - spec.Process.Env = append(spec.Process.Env, env) - g.envCache[key] = len(spec.Process.Env) - 1 - } else { - spec.Process.Env[idx] = env - } -} - -func getPodCNILabels(id string, config *runtime.PodSandboxConfig) map[string]string { - return map[string]string{ - "K8S_POD_NAMESPACE": config.GetMetadata().GetNamespace(), - "K8S_POD_NAME": config.GetMetadata().GetName(), - "K8S_POD_INFRA_CONTAINER_ID": id, - "IgnoreUnknown": "1", - } -} - -// toRuntimeAuthConfig converts cri plugin auth config to runtime auth config. -func toRuntimeAuthConfig(a criconfig.AuthConfig) *runtime.AuthConfig { - return &runtime.AuthConfig{ - Username: a.Username, - Password: a.Password, - Auth: a.Auth, - IdentityToken: a.IdentityToken, - } -} - -// mounts defines how to sort runtime.Mount. -// This is the same with the Docker implementation: -// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26 -type orderedMounts []*runtime.Mount - -// Len returns the number of mounts. Used in sorting. -func (m orderedMounts) Len() int { - return len(m) -} - -// Less returns true if the number of parts (a/b/c would be 3 parts) in the -// mount indexed by parameter 1 is less than that of the mount indexed by -// parameter 2. Used in sorting. -func (m orderedMounts) Less(i, j int) bool { - return m.parts(i) < m.parts(j) -} - -// Swap swaps two items in an array of mounts. Used in sorting -func (m orderedMounts) Swap(i, j int) { - m[i], m[j] = m[j], m[i] -} - -// parts returns the number of parts in the destination of a mount. Used in sorting. -func (m orderedMounts) parts(i int) int { - return strings.Count(filepath.Clean(m[i].ContainerPath), string(os.PathSeparator)) -} - -// parseImageReferences parses a list of arbitrary image references and returns -// the repotags and repodigests -func parseImageReferences(refs []string) ([]string, []string) { - var tags, digests []string - for _, ref := range refs { - parsed, err := reference.ParseAnyReference(ref) - if err != nil { - continue - } - if _, ok := parsed.(reference.Canonical); ok { - digests = append(digests, parsed.String()) - } else if _, ok := parsed.(reference.Tagged); ok { - tags = append(tags, parsed.String()) - } - } - return tags, digests -} - -// generateRuntimeOptions generates runtime options from cri plugin config. -func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { - if r.Options == nil { - if r.Type != linuxRuntime { - return nil, nil - } - // This is a legacy config, generate runctypes.RuncOptions. - return &runctypes.RuncOptions{ - Runtime: r.Engine, - RuntimeRoot: r.Root, - SystemdCgroup: c.SystemdCgroup, - }, nil - } - options := getRuntimeOptionsType(r.Type) - if err := toml.PrimitiveDecode(*r.Options, options); err != nil { - return nil, err - } - return options, nil -} - -// getRuntimeOptionsType gets empty runtime options by the runtime type name. -func getRuntimeOptionsType(t string) interface{} { - switch t { - case runcRuntime: - return &runcoptions.Options{} - default: - return &runctypes.RuncOptions{} - } -} - -// getRuntimeOptions get runtime options from container metadata. -func getRuntimeOptions(c containers.Container) (interface{}, error) { - if c.Runtime.Options == nil { - return nil, nil - } - opts, err := typeurl.UnmarshalAny(c.Runtime.Options) - if err != nil { - return nil, err - } - return opts, nil -} - -const ( - // unknownExitCode is the exit code when exit reason is unknown. - unknownExitCode = 255 - // unknownExitReason is the exit reason when exit reason is unknown. - unknownExitReason = "Unknown" -) - -// unknownContainerStatus returns the default container status when its status is unknown. -func unknownContainerStatus() containerstore.Status { - return containerstore.Status{ - CreatedAt: 0, - StartedAt: 0, - FinishedAt: 0, - ExitCode: unknownExitCode, - Reason: unknownExitReason, - } -} - -// unknownSandboxStatus returns the default sandbox status when its status is unknown. -func unknownSandboxStatus() sandboxstore.Status { - return sandboxstore.Status{ - State: sandboxstore.StateUnknown, - } -} - -// unknownExitStatus generates containerd.Status for container exited with unknown exit code. -func unknownExitStatus() containerd.Status { - return containerd.Status{ - Status: containerd.Stopped, - ExitStatus: unknownExitCode, - ExitTime: time.Now(), - } -} - -// getTaskStatus returns status for a given task. It returns unknown exit status if -// the task is nil or not found. -func getTaskStatus(ctx context.Context, task containerd.Task) (containerd.Status, error) { - if task == nil { - return unknownExitStatus(), nil - } - status, err := task.Status(ctx) - if err != nil { - if !errdefs.IsNotFound(err) { - return containerd.Status{}, err - } - return unknownExitStatus(), nil - } - return status, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/imagefs_info.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/imagefs_info.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/imagefs_info.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/imagefs_info.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "time" - - "golang.org/x/net/context" - - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// ImageFsInfo returns information of the filesystem that is used to store images. -func (c *criService) ImageFsInfo(ctx context.Context, r *runtime.ImageFsInfoRequest) (*runtime.ImageFsInfoResponse, error) { - snapshots := c.snapshotStore.List() - timestamp := time.Now().UnixNano() - var usedBytes, inodesUsed uint64 - for _, sn := range snapshots { - // Use the oldest timestamp as the timestamp of imagefs info. - if sn.Timestamp < timestamp { - timestamp = sn.Timestamp - } - usedBytes += sn.Size - inodesUsed += sn.Inodes - } - // TODO(random-liu): Handle content store - return &runtime.ImageFsInfoResponse{ - ImageFilesystems: []*runtime.FilesystemUsage{ - { - Timestamp: timestamp, - FsId: &runtime.FilesystemIdentifier{Mountpoint: c.imageFSPath}, - UsedBytes: &runtime.UInt64Value{Value: usedBytes}, - InodesUsed: &runtime.UInt64Value{Value: inodesUsed}, - }, - }, - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_list.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_list.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_list.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_list.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// ListImages lists existing images. -// TODO(random-liu): Add image list filters after CRI defines this more clear, and kubelet -// actually needs it. -func (c *criService) ListImages(ctx context.Context, r *runtime.ListImagesRequest) (*runtime.ListImagesResponse, error) { - imagesInStore := c.imageStore.List() - - var images []*runtime.Image - for _, image := range imagesInStore { - // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot - // doesn't exist? - images = append(images, toCRIImage(image)) - } - - return &runtime.ListImagesResponse{Images: images}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_load.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_load.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_load.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_load.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "os" - "path/filepath" - - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - - api "github.com/containerd/cri/pkg/api/v1" - "github.com/containerd/cri/pkg/containerd/importer" -) - -// LoadImage loads a image into containerd. -func (c *criService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (*api.LoadImageResponse, error) { - path := r.GetFilePath() - if !filepath.IsAbs(path) { - return nil, errors.Errorf("path %q is not an absolute path", path) - } - f, err := os.Open(path) - if err != nil { - return nil, errors.Wrap(err, "failed to open file") - } - repoTags, err := importer.Import(ctx, c.client, f, importer.WithUnpack(c.config.ContainerdConfig.Snapshotter)) - if err != nil { - return nil, errors.Wrap(err, "failed to import image") - } - for _, repoTag := range repoTags { - // Update image store to reflect the newest state in containerd. - // Image imported by importer.Import is not treated as managed - // by the cri plugin, call `updateImage` to make it managed. - // TODO(random-liu): Replace this with the containerd library (issue #909). - if err := c.updateImage(ctx, repoTag); err != nil { - return nil, errors.Wrapf(err, "update image store %q", repoTag) - } - logrus.Debugf("Imported image %q", repoTag) - } - return &api.LoadImageResponse{Images: repoTags}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_pull.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_pull.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_pull.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_pull.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "encoding/base64" - "net/http" - "net/url" - "strings" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/errdefs" - containerdimages "github.com/containerd/containerd/images" - "github.com/containerd/containerd/reference" - "github.com/containerd/containerd/remotes" - "github.com/containerd/containerd/remotes/docker" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/util" -) - -// For image management: -// 1) We have an in-memory metadata index to: -// a. Maintain ImageID -> RepoTags, ImageID -> RepoDigset relationships; ImageID -// is the digest of image config, which conforms to oci image spec. -// b. Cache constant and useful information such as image chainID, config etc. -// c. An image will be added into the in-memory metadata only when it's successfully -// pulled and unpacked. -// -// 2) We use containerd image metadata store and content store: -// a. To resolve image reference (digest/tag) locally. During pulling image, we -// normalize the image reference provided by user, and put it into image metadata -// store with resolved descriptor. For the other operations, if image id is provided, -// we'll access the in-memory metadata index directly; if image reference is -// provided, we'll normalize it, resolve it in containerd image metadata store -// to get the image id. -// b. As the backup of in-memory metadata in 1). During startup, the in-memory -// metadata could be re-constructed from image metadata store + content store. -// -// Several problems with current approach: -// 1) An entry in containerd image metadata store doesn't mean a "READY" (successfully -// pulled and unpacked) image. E.g. during pulling, the client gets killed. In that case, -// if we saw an image without snapshots or with in-complete contents during startup, -// should we re-pull the image? Or should we remove the entry? -// -// yanxuean: We cann't delete image directly, because we don't know if the image -// is pulled by us. There are resource leakage. -// -// 2) Containerd suggests user to add entry before pulling the image. However if -// an error occurrs during the pulling, should we remove the entry from metadata -// store? Or should we leave it there until next startup (resource leakage)? -// -// 3) The cri plugin only exposes "READY" (successfully pulled and unpacked) images -// to the user, which are maintained in the in-memory metadata index. However, it's -// still possible that someone else removes the content or snapshot by-pass the cri plugin, -// how do we detect that and update the in-memory metadata correspondingly? Always -// check whether corresponding snapshot is ready when reporting image status? -// -// 4) Is the content important if we cached necessary information in-memory -// after we pull the image? How to manage the disk usage of contents? If some -// contents are missing but snapshots are ready, is the image still "READY"? - -// PullImage pulls an image with authentication config. -func (c *criService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (*runtime.PullImageResponse, error) { - imageRef := r.GetImage().GetImage() - namedRef, err := util.NormalizeImageRef(imageRef) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse image reference %q", imageRef) - } - ref := namedRef.String() - if ref != imageRef { - logrus.Debugf("PullImage using normalized image ref: %q", ref) - } - resolver, desc, err := c.getResolver(ctx, ref, c.credentials(r.GetAuth())) - if err != nil { - return nil, errors.Wrapf(err, "failed to resolve image %q", ref) - } - // We have to check schema1 here, because after `Pull`, schema1 - // image has already been converted. - isSchema1 := desc.MediaType == containerdimages.MediaTypeDockerSchema1Manifest - - image, err := c.client.Pull(ctx, ref, - containerd.WithSchema1Conversion, - containerd.WithResolver(resolver), - containerd.WithPullSnapshotter(c.config.ContainerdConfig.Snapshotter), - containerd.WithPullUnpack, - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to pull and unpack image %q", ref) - } - - configDesc, err := image.Config(ctx) - if err != nil { - return nil, errors.Wrap(err, "get image config descriptor") - } - imageID := configDesc.Digest.String() - - repoDigest, repoTag := getRepoDigestAndTag(namedRef, image.Target().Digest, isSchema1) - for _, r := range []string{imageID, repoTag, repoDigest} { - if r == "" { - continue - } - if err := c.createImageReference(ctx, r, image.Target()); err != nil { - return nil, errors.Wrapf(err, "failed to create image reference %q", r) - } - // Update image store to reflect the newest state in containerd. - // No need to use `updateImage`, because the image reference must - // have been managed by the cri plugin. - if err := c.imageStore.Update(ctx, r); err != nil { - return nil, errors.Wrapf(err, "failed to update image store %q", r) - } - } - - logrus.Debugf("Pulled image %q with image id %q, repo tag %q, repo digest %q", imageRef, imageID, - repoTag, repoDigest) - // NOTE(random-liu): the actual state in containerd is the source of truth, even we maintain - // in-memory image store, it's only for in-memory indexing. The image could be removed - // by someone else anytime, before/during/after we create the metadata. We should always - // check the actual state in containerd before using the image or returning status of the - // image. - return &runtime.PullImageResponse{ImageRef: imageID}, nil -} - -// ParseAuth parses AuthConfig and returns username and password/secret required by containerd. -func ParseAuth(auth *runtime.AuthConfig) (string, string, error) { - if auth == nil { - return "", "", nil - } - if auth.Username != "" { - return auth.Username, auth.Password, nil - } - if auth.IdentityToken != "" { - return "", auth.IdentityToken, nil - } - if auth.Auth != "" { - decLen := base64.StdEncoding.DecodedLen(len(auth.Auth)) - decoded := make([]byte, decLen) - _, err := base64.StdEncoding.Decode(decoded, []byte(auth.Auth)) - if err != nil { - return "", "", err - } - fields := strings.SplitN(string(decoded), ":", 2) - if len(fields) != 2 { - return "", "", errors.Errorf("invalid decoded auth: %q", decoded) - } - user, passwd := fields[0], fields[1] - return user, strings.Trim(passwd, "\x00"), nil - } - // TODO(random-liu): Support RegistryToken. - return "", "", errors.New("invalid auth config") -} - -// createImageReference creates image reference inside containerd image store. -// Note that because create and update are not finished in one transaction, there could be race. E.g. -// the image reference is deleted by someone else after create returns already exists, but before update -// happens. -func (c *criService) createImageReference(ctx context.Context, name string, desc imagespec.Descriptor) error { - img := containerdimages.Image{ - Name: name, - Target: desc, - // Add a label to indicate that the image is managed by the cri plugin. - Labels: map[string]string{imageLabelKey: imageLabelValue}, - } - // TODO(random-liu): Figure out which is the more performant sequence create then update or - // update then create. - oldImg, err := c.client.ImageService().Create(ctx, img) - if err == nil || !errdefs.IsAlreadyExists(err) { - return err - } - if oldImg.Target.Digest == img.Target.Digest && oldImg.Labels[imageLabelKey] == imageLabelValue { - return nil - } - _, err = c.client.ImageService().Update(ctx, img, "target", "labels") - return err -} - -// updateImage updates image store to reflect the newest state of an image reference -// in containerd. If the reference is not managed by the cri plugin, the function also -// generates necessary metadata for the image and make it managed. -func (c *criService) updateImage(ctx context.Context, r string) error { - img, err := c.client.GetImage(ctx, r) - if err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "get image by reference") - } - if err == nil && img.Labels()[imageLabelKey] != imageLabelValue { - // Make sure the image has the image id as its unique - // identifier that references the image in its lifetime. - configDesc, err := img.Config(ctx) - if err != nil { - return errors.Wrap(err, "get image id") - } - id := configDesc.Digest.String() - if err := c.createImageReference(ctx, id, img.Target()); err != nil { - return errors.Wrapf(err, "create image id reference %q", id) - } - if err := c.imageStore.Update(ctx, id); err != nil { - return errors.Wrapf(err, "update image store for %q", id) - } - // The image id is ready, add the label to mark the image as managed. - if err := c.createImageReference(ctx, r, img.Target()); err != nil { - return errors.Wrap(err, "create managed label") - } - } - // If the image is not found, we should continue updating the cache, - // so that the image can be removed from the cache. - if err := c.imageStore.Update(ctx, r); err != nil { - return errors.Wrapf(err, "update image store for %q", r) - } - return nil -} - -// credentials returns a credential function for docker resolver to use. -func (c *criService) credentials(auth *runtime.AuthConfig) func(string) (string, string, error) { - return func(host string) (string, string, error) { - if auth == nil { - // Get default auth from config. - for h, ac := range c.config.Registry.Auths { - u, err := url.Parse(h) - if err != nil { - return "", "", errors.Wrapf(err, "parse auth host %q", h) - } - if u.Host == host { - auth = toRuntimeAuthConfig(ac) - break - } - } - } - return ParseAuth(auth) - } -} - -// getResolver tries registry mirrors and the default registry, and returns the resolver and descriptor -// from the first working registry. -func (c *criService) getResolver(ctx context.Context, ref string, cred func(string) (string, string, error)) (remotes.Resolver, imagespec.Descriptor, error) { - refspec, err := reference.Parse(ref) - if err != nil { - return nil, imagespec.Descriptor{}, errors.Wrap(err, "parse image reference") - } - // Try mirrors in order first, and then try default host name. - for _, e := range c.config.Registry.Mirrors[refspec.Hostname()].Endpoints { - u, err := url.Parse(e) - if err != nil { - return nil, imagespec.Descriptor{}, errors.Wrapf(err, "parse registry endpoint %q", e) - } - resolver := docker.NewResolver(docker.ResolverOptions{ - Authorizer: docker.NewAuthorizer(http.DefaultClient, cred), - Client: http.DefaultClient, - Host: func(string) (string, error) { return u.Host, nil }, - // By default use "https". - PlainHTTP: u.Scheme == "http", - }) - _, desc, err := resolver.Resolve(ctx, ref) - if err == nil { - return resolver, desc, nil - } - // Continue to try next endpoint - } - resolver := docker.NewResolver(docker.ResolverOptions{ - Credentials: cred, - Client: http.DefaultClient, - }) - _, desc, err := resolver.Resolve(ctx, ref) - if err != nil { - return nil, imagespec.Descriptor{}, errors.Wrap(err, "no available registry endpoint") - } - return resolver, desc, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_remove.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_remove.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_remove.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_remove.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/store" -) - -// RemoveImage removes the image. -// TODO(random-liu): Update CRI to pass image reference instead of ImageSpec. (See -// kubernetes/kubernetes#46255) -// TODO(random-liu): We should change CRI to distinguish image id and image spec. -// Remove the whole image no matter the it's image id or reference. This is the -// semantic defined in CRI now. -func (c *criService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequest) (*runtime.RemoveImageResponse, error) { - image, err := c.localResolve(r.GetImage().GetImage()) - if err != nil { - if err == store.ErrNotExist { - // return empty without error when image not found. - return &runtime.RemoveImageResponse{}, nil - } - return nil, errors.Wrapf(err, "can not resolve %q locally", r.GetImage().GetImage()) - } - - // Remove all image references. - for i, ref := range image.References { - var opts []images.DeleteOpt - if i == len(image.References)-1 { - // Delete the last image reference synchronously to trigger garbage collection. - // This is best effort. It is possible that the image reference is deleted by - // someone else before this point. - opts = []images.DeleteOpt{images.SynchronousDelete()} - } - err = c.client.ImageService().Delete(ctx, ref, opts...) - if err == nil || errdefs.IsNotFound(err) { - // Update image store to reflect the newest state in containerd. - if err := c.imageStore.Update(ctx, ref); err != nil { - return nil, errors.Wrapf(err, "failed to update image reference %q for %q", ref, image.ID) - } - continue - } - return nil, errors.Wrapf(err, "failed to delete image reference %q for %q", ref, image.ID) - } - return &runtime.RemoveImageResponse{}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/image_status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/image_status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "encoding/json" - - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/store" - imagestore "github.com/containerd/cri/pkg/store/image" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" -) - -// ImageStatus returns the status of the image, returns nil if the image isn't present. -// TODO(random-liu): We should change CRI to distinguish image id and image spec. (See -// kubernetes/kubernetes#46255) -func (c *criService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequest) (*runtime.ImageStatusResponse, error) { - image, err := c.localResolve(r.GetImage().GetImage()) - if err != nil { - if err == store.ErrNotExist { - // return empty without error when image not found. - return &runtime.ImageStatusResponse{}, nil - } - return nil, errors.Wrapf(err, "can not resolve %q locally", r.GetImage().GetImage()) - } - // TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot - // doesn't exist? - - runtimeImage := toCRIImage(image) - info, err := c.toCRIImageInfo(ctx, &image, r.GetVerbose()) - if err != nil { - return nil, errors.Wrap(err, "failed to generate image info") - } - - return &runtime.ImageStatusResponse{ - Image: runtimeImage, - Info: info, - }, nil -} - -// toCRIImage converts internal image object to CRI runtime.Image. -func toCRIImage(image imagestore.Image) *runtime.Image { - repoTags, repoDigests := parseImageReferences(image.References) - runtimeImage := &runtime.Image{ - Id: image.ID, - RepoTags: repoTags, - RepoDigests: repoDigests, - Size_: uint64(image.Size), - } - uid, username := getUserFromImage(image.ImageSpec.Config.User) - if uid != nil { - runtimeImage.Uid = &runtime.Int64Value{Value: *uid} - } - runtimeImage.Username = username - - return runtimeImage -} - -// TODO (mikebrow): discuss moving this struct and / or constants for info map for some or all of these fields to CRI -type verboseImageInfo struct { - ChainID string `json:"chainID"` - ImageSpec imagespec.Image `json:"imageSpec"` -} - -// toCRIImageInfo converts internal image object information to CRI image status response info map. -func (c *criService) toCRIImageInfo(ctx context.Context, image *imagestore.Image, verbose bool) (map[string]string, error) { - if !verbose { - return nil, nil - } - - info := make(map[string]string) - - imi := &verboseImageInfo{ - ChainID: image.ChainID, - ImageSpec: image.ImageSpec, - } - - m, err := json.Marshal(imi) - if err == nil { - info["info"] = string(m) - } else { - logrus.WithError(err).Errorf("failed to marshal info %v", imi) - info["info"] = err.Error() - } - - return info, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/instrumented_service.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/instrumented_service.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/instrumented_service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/instrumented_service.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,479 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "errors" - - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - api "github.com/containerd/cri/pkg/api/v1" - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - "github.com/containerd/cri/pkg/log" -) - -// instrumentedService wraps service with containerd namespace and logs. -type instrumentedService struct { - c *criService -} - -func newInstrumentedService(c *criService) grpcServices { - return &instrumentedService{c: c} -} - -// checkInitialized returns error if the server is not fully initialized. -// GRPC service request handlers should return error before server is fully -// initialized. -// NOTE(random-liu): All following functions MUST check initialized at the beginning. -func (in *instrumentedService) checkInitialized() error { - if in.c.initialized.IsSet() { - return nil - } - return errors.New("server is not initialized yet") -} - -func (in *instrumentedService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (res *runtime.RunPodSandboxResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("RunPodsandbox for %+v", r.GetConfig().GetMetadata()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("RunPodSandbox for %+v failed, error", r.GetConfig().GetMetadata()) - } else { - logrus.Infof("RunPodSandbox for %+v returns sandbox id %q", r.GetConfig().GetMetadata(), res.GetPodSandboxId()) - } - }() - return in.c.RunPodSandbox(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ListPodSandbox(ctx context.Context, r *runtime.ListPodSandboxRequest) (res *runtime.ListPodSandboxResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ListPodSandbox with filter %+v", r.GetFilter()) - defer func() { - if err != nil { - logrus.WithError(err).Error("ListPodSandbox failed") - } else { - log.Tracef("ListPodSandbox returns pod sandboxes %+v", res.GetItems()) - } - }() - return in.c.ListPodSandbox(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) PodSandboxStatus(ctx context.Context, r *runtime.PodSandboxStatusRequest) (res *runtime.PodSandboxStatusResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("PodSandboxStatus for %q", r.GetPodSandboxId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("PodSandboxStatus for %q failed", r.GetPodSandboxId()) - } else { - log.Tracef("PodSandboxStatus for %q returns status %+v", r.GetPodSandboxId(), res.GetStatus()) - } - }() - return in.c.PodSandboxStatus(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandboxRequest) (_ *runtime.StopPodSandboxResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("StopPodSandbox for %q", r.GetPodSandboxId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("StopPodSandbox for %q failed", r.GetPodSandboxId()) - } else { - logrus.Infof("StopPodSandbox for %q returns successfully", r.GetPodSandboxId()) - } - }() - return in.c.StopPodSandbox(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodSandboxRequest) (_ *runtime.RemovePodSandboxResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("RemovePodSandbox for %q", r.GetPodSandboxId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("RemovePodSandbox for %q failed", r.GetPodSandboxId()) - } else { - logrus.Infof("RemovePodSandbox %q returns successfully", r.GetPodSandboxId()) - } - }() - return in.c.RemovePodSandbox(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) PortForward(ctx context.Context, r *runtime.PortForwardRequest) (res *runtime.PortForwardResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("Portforward for %q port %v", r.GetPodSandboxId(), r.GetPort()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("Portforward for %q failed", r.GetPodSandboxId()) - } else { - logrus.Infof("Portforward for %q returns URL %q", r.GetPodSandboxId(), res.GetUrl()) - } - }() - return in.c.PortForward(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) CreateContainer(ctx context.Context, r *runtime.CreateContainerRequest) (res *runtime.CreateContainerResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("CreateContainer within sandbox %q for container %+v", - r.GetPodSandboxId(), r.GetConfig().GetMetadata()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("CreateContainer within sandbox %q for %+v failed", - r.GetPodSandboxId(), r.GetConfig().GetMetadata()) - } else { - logrus.Infof("CreateContainer within sandbox %q for %+v returns container id %q", - r.GetPodSandboxId(), r.GetConfig().GetMetadata(), res.GetContainerId()) - } - }() - return in.c.CreateContainer(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) StartContainer(ctx context.Context, r *runtime.StartContainerRequest) (_ *runtime.StartContainerResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("StartContainer for %q", r.GetContainerId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("StartContainer for %q failed", r.GetContainerId()) - } else { - logrus.Infof("StartContainer for %q returns successfully", r.GetContainerId()) - } - }() - return in.c.StartContainer(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ListContainers(ctx context.Context, r *runtime.ListContainersRequest) (res *runtime.ListContainersResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ListContainers with filter %+v", r.GetFilter()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ListContainers with filter %+v failed", r.GetFilter()) - } else { - log.Tracef("ListContainers with filter %+v returns containers %+v", - r.GetFilter(), res.GetContainers()) - } - }() - return in.c.ListContainers(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ContainerStatus(ctx context.Context, r *runtime.ContainerStatusRequest) (res *runtime.ContainerStatusResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ContainerStatus for %q", r.GetContainerId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ContainerStatus for %q failed", r.GetContainerId()) - } else { - log.Tracef("ContainerStatus for %q returns status %+v", r.GetContainerId(), res.GetStatus()) - } - }() - return in.c.ContainerStatus(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) StopContainer(ctx context.Context, r *runtime.StopContainerRequest) (res *runtime.StopContainerResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("StopContainer for %q with timeout %d (s)", r.GetContainerId(), r.GetTimeout()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("StopContainer for %q failed", r.GetContainerId()) - } else { - logrus.Infof("StopContainer for %q returns successfully", r.GetContainerId()) - } - }() - return in.c.StopContainer(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) RemoveContainer(ctx context.Context, r *runtime.RemoveContainerRequest) (res *runtime.RemoveContainerResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("RemoveContainer for %q", r.GetContainerId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("RemoveContainer for %q failed", r.GetContainerId()) - } else { - logrus.Infof("RemoveContainer for %q returns successfully", r.GetContainerId()) - } - }() - return in.c.RemoveContainer(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ExecSync(ctx context.Context, r *runtime.ExecSyncRequest) (res *runtime.ExecSyncResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("ExecSync for %q with command %+v and timeout %d (s)", r.GetContainerId(), r.GetCmd(), r.GetTimeout()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ExecSync for %q failed", r.GetContainerId()) - } else { - logrus.Infof("ExecSync for %q returns with exit code %d", r.GetContainerId(), res.GetExitCode()) - logrus.Debugf("ExecSync for %q outputs - stdout: %q, stderr: %q", r.GetContainerId(), - res.GetStdout(), res.GetStderr()) - } - }() - return in.c.ExecSync(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) Exec(ctx context.Context, r *runtime.ExecRequest) (res *runtime.ExecResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("Exec for %q with command %+v, tty %v and stdin %v", - r.GetContainerId(), r.GetCmd(), r.GetTty(), r.GetStdin()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("Exec for %q failed", r.GetContainerId()) - } else { - logrus.Infof("Exec for %q returns URL %q", r.GetContainerId(), res.GetUrl()) - } - }() - return in.c.Exec(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) Attach(ctx context.Context, r *runtime.AttachRequest) (res *runtime.AttachResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("Attach for %q with tty %v and stdin %v", r.GetContainerId(), r.GetTty(), r.GetStdin()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("Attach for %q failed", r.GetContainerId()) - } else { - logrus.Infof("Attach for %q returns URL %q", r.GetContainerId(), res.Url) - } - }() - return in.c.Attach(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) UpdateContainerResources(ctx context.Context, r *runtime.UpdateContainerResourcesRequest) (res *runtime.UpdateContainerResourcesResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("UpdateContainerResources for %q with %+v", r.GetContainerId(), r.GetLinux()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("UpdateContainerResources for %q failed", r.GetContainerId()) - } else { - logrus.Infof("UpdateContainerResources for %q returns successfully", r.GetContainerId()) - } - }() - return in.c.UpdateContainerResources(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) PullImage(ctx context.Context, r *runtime.PullImageRequest) (res *runtime.PullImageResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("PullImage %q", r.GetImage().GetImage()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("PullImage %q failed", r.GetImage().GetImage()) - } else { - logrus.Infof("PullImage %q returns image reference %q", - r.GetImage().GetImage(), res.GetImageRef()) - } - }() - return in.c.PullImage(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ListImages(ctx context.Context, r *runtime.ListImagesRequest) (res *runtime.ListImagesResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ListImages with filter %+v", r.GetFilter()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ListImages with filter %+v failed", r.GetFilter()) - } else { - log.Tracef("ListImages with filter %+v returns image list %+v", - r.GetFilter(), res.GetImages()) - } - }() - return in.c.ListImages(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ImageStatus(ctx context.Context, r *runtime.ImageStatusRequest) (res *runtime.ImageStatusResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ImageStatus for %q", r.GetImage().GetImage()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ImageStatus for %q failed", r.GetImage().GetImage()) - } else { - log.Tracef("ImageStatus for %q returns image status %+v", - r.GetImage().GetImage(), res.GetImage()) - } - }() - return in.c.ImageStatus(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) RemoveImage(ctx context.Context, r *runtime.RemoveImageRequest) (_ *runtime.RemoveImageResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Infof("RemoveImage %q", r.GetImage().GetImage()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("RemoveImage %q failed", r.GetImage().GetImage()) - } else { - logrus.Infof("RemoveImage %q returns successfully", r.GetImage().GetImage()) - } - }() - return in.c.RemoveImage(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ImageFsInfo(ctx context.Context, r *runtime.ImageFsInfoRequest) (res *runtime.ImageFsInfoResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Debugf("ImageFsInfo") - defer func() { - if err != nil { - logrus.WithError(err).Error("ImageFsInfo failed") - } else { - logrus.Debugf("ImageFsInfo returns filesystem info %+v", res.ImageFilesystems) - } - }() - return in.c.ImageFsInfo(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ContainerStats(ctx context.Context, r *runtime.ContainerStatsRequest) (res *runtime.ContainerStatsResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Debugf("ContainerStats for %q", r.GetContainerId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ContainerStats for %q failed", r.GetContainerId()) - } else { - logrus.Debugf("ContainerStats for %q returns stats %+v", r.GetContainerId(), res.GetStats()) - } - }() - return in.c.ContainerStats(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ListContainerStats(ctx context.Context, r *runtime.ListContainerStatsRequest) (res *runtime.ListContainerStatsResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("ListContainerStats with filter %+v", r.GetFilter()) - defer func() { - if err != nil { - logrus.WithError(err).Error("ListContainerStats failed") - } else { - log.Tracef("ListContainerStats returns stats %+v", res.GetStats()) - } - }() - return in.c.ListContainerStats(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) Status(ctx context.Context, r *runtime.StatusRequest) (res *runtime.StatusResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("Status") - defer func() { - if err != nil { - logrus.WithError(err).Error("Status failed") - } else { - log.Tracef("Status returns status %+v", res.GetStatus()) - } - }() - return in.c.Status(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) Version(ctx context.Context, r *runtime.VersionRequest) (res *runtime.VersionResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - log.Tracef("Version with client side version %q", r.GetVersion()) - defer func() { - if err != nil { - logrus.WithError(err).Error("Version failed") - } else { - log.Tracef("Version returns %+v", res) - } - }() - return in.c.Version(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateRuntimeConfigRequest) (res *runtime.UpdateRuntimeConfigResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Debugf("UpdateRuntimeConfig with config %+v", r.GetRuntimeConfig()) - defer func() { - if err != nil { - logrus.WithError(err).Error("UpdateRuntimeConfig failed") - } else { - logrus.Debug("UpdateRuntimeConfig returns returns successfully") - } - }() - return in.c.UpdateRuntimeConfig(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) LoadImage(ctx context.Context, r *api.LoadImageRequest) (res *api.LoadImageResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Debugf("LoadImage from file %q", r.GetFilePath()) - defer func() { - if err != nil { - logrus.WithError(err).Error("LoadImage failed") - } else { - logrus.Debugf("LoadImage returns images %+v", res.GetImages()) - } - }() - return in.c.LoadImage(ctrdutil.WithNamespace(ctx), r) -} - -func (in *instrumentedService) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (res *runtime.ReopenContainerLogResponse, err error) { - if err := in.checkInitialized(); err != nil { - return nil, err - } - logrus.Debugf("ReopenContainerLog for %q", r.GetContainerId()) - defer func() { - if err != nil { - logrus.WithError(err).Errorf("ReopenContainerLog for %q failed", r.GetContainerId()) - } else { - logrus.Debugf("ReopenContainerLog for %q returns successfully", r.GetContainerId()) - } - }() - return in.c.ReopenContainerLog(ctrdutil.WithNamespace(ctx), r) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/container_io.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/container_io.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/container_io.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/container_io.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io - -import ( - "errors" - "io" - "strings" - "sync" - - "github.com/containerd/containerd/cio" - "github.com/sirupsen/logrus" - - cioutil "github.com/containerd/cri/pkg/ioutil" - "github.com/containerd/cri/pkg/util" -) - -// streamKey generates a key for the stream. -func streamKey(id, name string, stream StreamType) string { - return strings.Join([]string{id, name, string(stream)}, "-") -} - -// ContainerIO holds the container io. -type ContainerIO struct { - id string - - fifos *cio.FIFOSet - *stdioPipes - - stdoutGroup *cioutil.WriterGroup - stderrGroup *cioutil.WriterGroup - - closer *wgCloser -} - -var _ cio.IO = &ContainerIO{} - -// ContainerIOOpts sets specific information to newly created ContainerIO. -type ContainerIOOpts func(*ContainerIO) error - -// WithFIFOs specifies existing fifos for the container io. -func WithFIFOs(fifos *cio.FIFOSet) ContainerIOOpts { - return func(c *ContainerIO) error { - c.fifos = fifos - return nil - } -} - -// WithNewFIFOs creates new fifos for the container io. -func WithNewFIFOs(root string, tty, stdin bool) ContainerIOOpts { - return func(c *ContainerIO) error { - fifos, err := newFifos(root, c.id, tty, stdin) - if err != nil { - return err - } - return WithFIFOs(fifos)(c) - } -} - -// NewContainerIO creates container io. -func NewContainerIO(id string, opts ...ContainerIOOpts) (_ *ContainerIO, err error) { - c := &ContainerIO{ - id: id, - stdoutGroup: cioutil.NewWriterGroup(), - stderrGroup: cioutil.NewWriterGroup(), - } - for _, opt := range opts { - if err := opt(c); err != nil { - return nil, err - } - } - if c.fifos == nil { - return nil, errors.New("fifos are not set") - } - // Create actual fifos. - stdio, closer, err := newStdioPipes(c.fifos) - if err != nil { - return nil, err - } - c.stdioPipes = stdio - c.closer = closer - return c, nil -} - -// Config returns io config. -func (c *ContainerIO) Config() cio.Config { - return c.fifos.Config -} - -// Pipe creates container fifos and pipe container output -// to output stream. -func (c *ContainerIO) Pipe() { - wg := c.closer.wg - wg.Add(1) - go func() { - if _, err := io.Copy(c.stdoutGroup, c.stdout); err != nil { - logrus.WithError(err).Errorf("Failed to pipe stdout of container %q", c.id) - } - c.stdout.Close() - c.stdoutGroup.Close() - wg.Done() - logrus.Infof("Finish piping stdout of container %q", c.id) - }() - - if !c.fifos.Terminal { - wg.Add(1) - go func() { - if _, err := io.Copy(c.stderrGroup, c.stderr); err != nil { - logrus.WithError(err).Errorf("Failed to pipe stderr of container %q", c.id) - } - c.stderr.Close() - c.stderrGroup.Close() - wg.Done() - logrus.Infof("Finish piping stderr of container %q", c.id) - }() - } -} - -// Attach attaches container stdio. -// TODO(random-liu): Use pools.Copy in docker to reduce memory usage? -func (c *ContainerIO) Attach(opts AttachOptions) { - var wg sync.WaitGroup - key := util.GenerateID() - stdinKey := streamKey(c.id, "attach-"+key, Stdin) - stdoutKey := streamKey(c.id, "attach-"+key, Stdout) - stderrKey := streamKey(c.id, "attach-"+key, Stderr) - - var stdinStreamRC io.ReadCloser - if c.stdin != nil && opts.Stdin != nil { - // Create a wrapper of stdin which could be closed. Note that the - // wrapper doesn't close the actual stdin, it only stops io.Copy. - // The actual stdin will be closed by stream server. - stdinStreamRC = cioutil.NewWrapReadCloser(opts.Stdin) - wg.Add(1) - go func() { - if _, err := io.Copy(c.stdin, stdinStreamRC); err != nil { - logrus.WithError(err).Errorf("Failed to pipe stdin for container attach %q", c.id) - } - logrus.Infof("Attach stream %q closed", stdinKey) - if opts.StdinOnce && !opts.Tty { - // Due to kubectl requirements and current docker behavior, when (opts.StdinOnce && - // opts.Tty) we have to close container stdin and keep stdout and stderr open until - // container stops. - c.stdin.Close() - // Also closes the containerd side. - if err := opts.CloseStdin(); err != nil { - logrus.WithError(err).Errorf("Failed to close stdin for container %q", c.id) - } - } else { - if opts.Stdout != nil { - c.stdoutGroup.Remove(stdoutKey) - } - if opts.Stderr != nil { - c.stderrGroup.Remove(stderrKey) - } - } - wg.Done() - }() - } - - attachStream := func(key string, close <-chan struct{}) { - <-close - logrus.Infof("Attach stream %q closed", key) - // Make sure stdin gets closed. - if stdinStreamRC != nil { - stdinStreamRC.Close() - } - wg.Done() - } - - if opts.Stdout != nil { - wg.Add(1) - wc, close := cioutil.NewWriteCloseInformer(opts.Stdout) - c.stdoutGroup.Add(stdoutKey, wc) - go attachStream(stdoutKey, close) - } - if !opts.Tty && opts.Stderr != nil { - wg.Add(1) - wc, close := cioutil.NewWriteCloseInformer(opts.Stderr) - c.stderrGroup.Add(stderrKey, wc) - go attachStream(stderrKey, close) - } - wg.Wait() -} - -// AddOutput adds new write closers to the container stream, and returns existing -// write closers if there are any. -func (c *ContainerIO) AddOutput(name string, stdout, stderr io.WriteCloser) (io.WriteCloser, io.WriteCloser) { - var oldStdout, oldStderr io.WriteCloser - if stdout != nil { - key := streamKey(c.id, name, Stdout) - oldStdout = c.stdoutGroup.Get(key) - c.stdoutGroup.Add(key, stdout) - } - if stderr != nil { - key := streamKey(c.id, name, Stderr) - oldStderr = c.stderrGroup.Get(key) - c.stderrGroup.Add(key, stderr) - } - return oldStdout, oldStderr -} - -// Cancel cancels container io. -func (c *ContainerIO) Cancel() { - c.closer.Cancel() -} - -// Wait waits container io to finish. -func (c *ContainerIO) Wait() { - c.closer.Wait() -} - -// Close closes all FIFOs. -func (c *ContainerIO) Close() error { - c.closer.Close() - if c.fifos != nil { - return c.fifos.Close() - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/exec_io.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/exec_io.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/exec_io.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/exec_io.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io - -import ( - "io" - "sync" - - "github.com/containerd/containerd/cio" - "github.com/sirupsen/logrus" - - cioutil "github.com/containerd/cri/pkg/ioutil" -) - -// ExecIO holds the exec io. -type ExecIO struct { - id string - fifos *cio.FIFOSet - *stdioPipes - closer *wgCloser -} - -var _ cio.IO = &ExecIO{} - -// NewExecIO creates exec io. -func NewExecIO(id, root string, tty, stdin bool) (*ExecIO, error) { - fifos, err := newFifos(root, id, tty, stdin) - if err != nil { - return nil, err - } - stdio, closer, err := newStdioPipes(fifos) - if err != nil { - return nil, err - } - return &ExecIO{ - id: id, - fifos: fifos, - stdioPipes: stdio, - closer: closer, - }, nil -} - -// Config returns io config. -func (e *ExecIO) Config() cio.Config { - return e.fifos.Config -} - -// Attach attaches exec stdio. The logic is similar with container io attach. -func (e *ExecIO) Attach(opts AttachOptions) <-chan struct{} { - var wg sync.WaitGroup - var stdinStreamRC io.ReadCloser - if e.stdin != nil && opts.Stdin != nil { - stdinStreamRC = cioutil.NewWrapReadCloser(opts.Stdin) - wg.Add(1) - go func() { - if _, err := io.Copy(e.stdin, stdinStreamRC); err != nil { - logrus.WithError(err).Errorf("Failed to redirect stdin for container exec %q", e.id) - } - logrus.Infof("Container exec %q stdin closed", e.id) - if opts.StdinOnce && !opts.Tty { - e.stdin.Close() - if err := opts.CloseStdin(); err != nil { - logrus.WithError(err).Errorf("Failed to close stdin for container exec %q", e.id) - } - } else { - if e.stdout != nil { - e.stdout.Close() - } - if e.stderr != nil { - e.stderr.Close() - } - } - wg.Done() - }() - } - - attachOutput := func(t StreamType, stream io.WriteCloser, out io.ReadCloser) { - if _, err := io.Copy(stream, out); err != nil { - logrus.WithError(err).Errorf("Failed to pipe %q for container exec %q", t, e.id) - } - out.Close() - stream.Close() - if stdinStreamRC != nil { - stdinStreamRC.Close() - } - e.closer.wg.Done() - wg.Done() - logrus.Infof("Finish piping %q of container exec %q", t, e.id) - } - - if opts.Stdout != nil { - wg.Add(1) - // Closer should wait for this routine to be over. - e.closer.wg.Add(1) - go attachOutput(Stdout, opts.Stdout, e.stdout) - } - - if !opts.Tty && opts.Stderr != nil { - wg.Add(1) - // Closer should wait for this routine to be over. - e.closer.wg.Add(1) - go attachOutput(Stderr, opts.Stderr, e.stderr) - } - - done := make(chan struct{}) - go func() { - wg.Wait() - close(done) - }() - return done -} - -// Cancel cancels exec io. -func (e *ExecIO) Cancel() { - e.closer.Cancel() -} - -// Wait waits exec io to finish. -func (e *ExecIO) Wait() { - e.closer.Wait() -} - -// Close closes all FIFOs. -func (e *ExecIO) Close() error { - if e.closer != nil { - e.closer.Close() - } - if e.fifos != nil { - return e.fifos.Close() - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/helpers.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/helpers.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/helpers.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io - -import ( - "io" - "os" - "path/filepath" - "sync" - "syscall" - - "github.com/containerd/containerd/cio" - "github.com/containerd/fifo" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// AttachOptions specifies how to attach to a container. -type AttachOptions struct { - Stdin io.Reader - Stdout io.WriteCloser - Stderr io.WriteCloser - Tty bool - StdinOnce bool - // CloseStdin is the function to close container stdin. - CloseStdin func() error -} - -// StreamType is the type of the stream, stdout/stderr. -type StreamType string - -const ( - // Stdin stream type. - Stdin StreamType = "stdin" - // Stdout stream type. - Stdout StreamType = StreamType(runtime.Stdout) - // Stderr stream type. - Stderr StreamType = StreamType(runtime.Stderr) -) - -type wgCloser struct { - ctx context.Context - wg *sync.WaitGroup - set []io.Closer - cancel context.CancelFunc -} - -func (g *wgCloser) Wait() { - g.wg.Wait() -} - -func (g *wgCloser) Close() { - for _, f := range g.set { - f.Close() - } -} - -func (g *wgCloser) Cancel() { - g.cancel() -} - -// newFifos creates fifos directory for a container. -func newFifos(root, id string, tty, stdin bool) (*cio.FIFOSet, error) { - root = filepath.Join(root, "io") - if err := os.MkdirAll(root, 0700); err != nil { - return nil, err - } - fifos, err := cio.NewFIFOSetInDir(root, id, tty) - if err != nil { - return nil, err - } - if !stdin { - fifos.Stdin = "" - } - return fifos, nil -} - -type stdioPipes struct { - stdin io.WriteCloser - stdout io.ReadCloser - stderr io.ReadCloser -} - -// newStdioPipes creates actual fifos for stdio. -func newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, _ *wgCloser, err error) { - var ( - f io.ReadWriteCloser - set []io.Closer - ctx, cancel = context.WithCancel(context.Background()) - p = &stdioPipes{} - ) - defer func() { - if err != nil { - for _, f := range set { - f.Close() - } - cancel() - } - }() - - if fifos.Stdin != "" { - if f, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return nil, nil, err - } - p.stdin = f - set = append(set, f) - } - - if f, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return nil, nil, err - } - p.stdout = f - set = append(set, f) - - if f, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); err != nil { - return nil, nil, err - } - p.stderr = f - set = append(set, f) - - return p, &wgCloser{ - wg: &sync.WaitGroup{}, - set: set, - ctx: ctx, - cancel: cancel, - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/logger.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/logger.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/io/logger.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/io/logger.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package io - -import ( - "bufio" - "bytes" - "fmt" - "io" - "io/ioutil" - "time" - - "github.com/sirupsen/logrus" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - cioutil "github.com/containerd/cri/pkg/ioutil" -) - -const ( - // delimiter used in CRI logging format. - delimiter = ' ' - // eof is end-of-line. - eol = '\n' - // timestampFormat is the timestamp format used in CRI logging format. - timestampFormat = time.RFC3339Nano - // defaultBufSize is the default size of the read buffer in bytes. - defaultBufSize = 4096 -) - -// NewDiscardLogger creates logger which discards all the input. -func NewDiscardLogger() io.WriteCloser { - return cioutil.NewNopWriteCloser(ioutil.Discard) -} - -// NewCRILogger returns a write closer which redirect container log into -// log file, and decorate the log line into CRI defined format. It also -// returns a channel which indicates whether the logger is stopped. -// maxLen is the max length limit of a line. A line longer than the -// limit will be cut into multiple lines. -func NewCRILogger(path string, w io.Writer, stream StreamType, maxLen int) (io.WriteCloser, <-chan struct{}) { - logrus.Debugf("Start writing stream %q to log file %q", stream, path) - prc, pwc := io.Pipe() - stop := make(chan struct{}) - go func() { - redirectLogs(path, prc, w, stream, maxLen) - close(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) { - defer rc.Close() - var ( - stream = []byte(s) - delimiter = []byte{delimiter} - partial = []byte(runtime.LogTagPartial) - full = []byte(runtime.LogTagFull) - buf [][]byte - length int - bufSize = defaultBufSize - ) - // Make sure bufSize <= maxLen - if maxLen > 0 && maxLen < bufSize { - bufSize = maxLen - } - r := bufio.NewReaderSize(rc, bufSize) - writeLine := func(tag, line []byte) { - timestamp := time.Now().AppendFormat(nil, timestampFormat) - data := bytes.Join([][]byte{timestamp, stream, tag, line}, delimiter) - data = append(data, eol) - if _, err := w.Write(data); err != nil { - logrus.WithError(err).Errorf("Fail to write %q log to log file %q", s, path) - // Continue on write error to drain the container output. - } - } - for { - var stop bool - 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 == io.EOF { - logrus.Debugf("Getting EOF from stream %q while redirecting to log file %q", s, path) - } else { - logrus.WithError(err).Errorf("An error occurred when redirecting stream %q to log file %q", s, path) - } - if length == 0 { - // No content left to write, break. - break - } - // Stop after writing the content left in buffer. - stop = true - } - if maxLen > 0 && length > maxLen { - exceedLen := length - maxLen - last := buf[len(buf)-1] - if exceedLen > len(last) { - // exceedLen must <= len(last), or else the buffer - // should have be written in the previous iteration. - panic("exceed length should <= last buffer size") - } - buf[len(buf)-1] = last[:len(last)-exceedLen] - writeLine(partial, bytes.Join(buf, nil)) - buf = [][]byte{last[len(last)-exceedLen:]} - length = exceedLen - } - if isPrefix { - 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)) - } - buf = nil - length = 0 - if stop { - break - } - } - logrus.Debugf("Finish redirecting stream %q to log file %q", s, path) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/restart.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/restart.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/restart.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/restart.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,452 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "io/ioutil" - "os" - "path/filepath" - "time" - - "github.com/containerd/containerd" - containerdio "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - containerdimages "github.com/containerd/containerd/images" - "github.com/containerd/containerd/platforms" - "github.com/containerd/typeurl" - "github.com/docker/docker/pkg/system" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/netns" - cio "github.com/containerd/cri/pkg/server/io" - containerstore "github.com/containerd/cri/pkg/store/container" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// NOTE: The recovery logic has following assumption: when the cri plugin is down: -// 1) Files (e.g. root directory, netns) and checkpoint maintained by the plugin MUST NOT be -// touched. Or else, recovery logic for those containers/sandboxes may return error. -// 2) Containerd containers may be deleted, but SHOULD NOT be added. Or else, recovery logic -// for the newly added container/sandbox will return error, because there is no corresponding root -// directory created. -// 3) Containerd container tasks may exit or be stoppped, deleted. Even though current logic could -// tolerant tasks being created or started, we prefer that not to happen. - -// recover recovers system state from containerd and status checkpoint. -func (c *criService) recover(ctx context.Context) error { - // Recover all sandboxes. - sandboxes, err := c.client.Containers(ctx, filterLabel(containerKindLabel, containerKindSandbox)) - if err != nil { - return errors.Wrap(err, "failed to list sandbox containers") - } - for _, sandbox := range sandboxes { - sb, err := loadSandbox(ctx, sandbox) - if err != nil { - logrus.WithError(err).Errorf("Failed to load sandbox %q", sandbox.ID()) - continue - } - logrus.Debugf("Loaded sandbox %+v", sb) - if err := c.sandboxStore.Add(sb); err != nil { - return errors.Wrapf(err, "failed to add sandbox %q to store", sandbox.ID()) - } - if err := c.sandboxNameIndex.Reserve(sb.Name, sb.ID); err != nil { - return errors.Wrapf(err, "failed to reserve sandbox name %q", sb.Name) - } - } - - // Recover all containers. - containers, err := c.client.Containers(ctx, filterLabel(containerKindLabel, containerKindContainer)) - if err != nil { - return errors.Wrap(err, "failed to list containers") - } - for _, container := range containers { - cntr, err := c.loadContainer(ctx, container) - if err != nil { - logrus.WithError(err).Errorf("Failed to load container %q", container.ID()) - continue - } - logrus.Debugf("Loaded container %+v", cntr) - if err := c.containerStore.Add(cntr); err != nil { - return errors.Wrapf(err, "failed to add container %q to store", container.ID()) - } - if err := c.containerNameIndex.Reserve(cntr.Name, cntr.ID); err != nil { - return errors.Wrapf(err, "failed to reserve container name %q", cntr.Name) - } - } - - // Recover all images. - cImages, err := c.client.ListImages(ctx) - if err != nil { - return errors.Wrap(err, "failed to list images") - } - c.loadImages(ctx, cImages) - - // It's possible that containerd containers are deleted unexpectedly. In that case, - // we can't even get metadata, we should cleanup orphaned sandbox/container directories - // with best effort. - - // Cleanup orphaned sandbox and container directories without corresponding containerd container. - for _, cleanup := range []struct { - cntrs []containerd.Container - base string - errMsg string - }{ - { - cntrs: sandboxes, - base: filepath.Join(c.config.RootDir, sandboxesDir), - errMsg: "failed to cleanup orphaned sandbox directories", - }, - { - cntrs: sandboxes, - base: filepath.Join(c.config.StateDir, sandboxesDir), - errMsg: "failed to cleanup orphaned volatile sandbox directories", - }, - { - cntrs: containers, - base: filepath.Join(c.config.RootDir, containersDir), - errMsg: "failed to cleanup orphaned container directories", - }, - { - cntrs: containers, - base: filepath.Join(c.config.StateDir, containersDir), - errMsg: "failed to cleanup orphaned volatile container directories", - }, - } { - if err := cleanupOrphanedIDDirs(cleanup.cntrs, cleanup.base); err != nil { - return errors.Wrap(err, cleanup.errMsg) - } - } - return nil -} - -// loadContainerTimeout is the default timeout for loading a container/sandbox. -// One container/sandbox hangs (e.g. containerd#2438) should not affect other -// containers/sandboxes. -// Most CRI container/sandbox related operations are per container, the ones -// which handle multiple containers at a time are: -// * ListPodSandboxes: Don't talk with containerd services. -// * ListContainers: Don't talk with containerd services. -// * ListContainerStats: Not in critical code path, a default timeout will -// be applied at CRI level. -// * Recovery logic: We should set a time for each container/sandbox recovery. -// * Event montior: We should set a timeout for each container/sandbox event handling. -const loadContainerTimeout = 10 * time.Second - -// loadContainer loads container from containerd and status checkpoint. -func (c *criService) loadContainer(ctx context.Context, cntr containerd.Container) (containerstore.Container, error) { - ctx, cancel := context.WithTimeout(ctx, loadContainerTimeout) - defer cancel() - id := cntr.ID() - containerDir := c.getContainerRootDir(id) - volatileContainerDir := c.getVolatileContainerRootDir(id) - var container containerstore.Container - // Load container metadata. - exts, err := cntr.Extensions(ctx) - if err != nil { - return container, errors.Wrap(err, "failed to get container extensions") - } - ext, ok := exts[containerMetadataExtension] - if !ok { - return container, errors.Errorf("metadata extension %q not found", containerMetadataExtension) - } - data, err := typeurl.UnmarshalAny(&ext) - if err != nil { - return container, errors.Wrapf(err, "failed to unmarshal metadata extension %q", ext) - } - meta := data.(*containerstore.Metadata) - - // Load status from checkpoint. - status, err := containerstore.LoadStatus(containerDir, id) - if err != nil { - logrus.WithError(err).Warnf("Failed to load container status for %q", id) - status = unknownContainerStatus() - } - - var containerIO *cio.ContainerIO - err = func() error { - // Load up-to-date status from containerd. - t, err := cntr.Task(ctx, func(fifos *containerdio.FIFOSet) (_ containerdio.IO, err error) { - stdoutWC, stderrWC, err := c.createContainerLoggers(meta.LogPath, meta.Config.GetTty()) - if err != nil { - return nil, err - } - defer func() { - if err != nil { - if stdoutWC != nil { - stdoutWC.Close() - } - if stderrWC != nil { - stderrWC.Close() - } - } - }() - containerIO, err = cio.NewContainerIO(id, - cio.WithFIFOs(fifos), - ) - if err != nil { - return nil, err - } - containerIO.AddOutput("log", stdoutWC, stderrWC) - containerIO.Pipe() - return containerIO, nil - }) - if err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to load task") - } - var s containerd.Status - var notFound bool - if errdefs.IsNotFound(err) { - // Task is not found. - notFound = true - } else { - // Task is found. Get task status. - s, err = t.Status(ctx) - if err != nil { - // It's still possible that task is deleted during this window. - if !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to get task status") - } - notFound = true - } - } - if notFound { - // Task is not created or has been deleted, use the checkpointed status - // to generate container status. - switch status.State() { - case runtime.ContainerState_CONTAINER_CREATED: - // NOTE: Another possibility is that we've tried to start the container, but - // containerd got restarted during that. In that case, we still - // treat the container as `CREATED`. - containerIO, err = cio.NewContainerIO(id, - cio.WithNewFIFOs(volatileContainerDir, meta.Config.GetTty(), meta.Config.GetStdin()), - ) - if err != nil { - return errors.Wrap(err, "failed to create container io") - } - case runtime.ContainerState_CONTAINER_RUNNING: - // Container was in running state, but its task has been deleted, - // set unknown exited state. Container io is not needed in this case. - status.FinishedAt = time.Now().UnixNano() - status.ExitCode = unknownExitCode - status.Reason = unknownExitReason - default: - // Container is in exited/unknown state, return the status as it is. - } - } else { - // Task status is found. Update container status based on the up-to-date task status. - switch s.Status { - case containerd.Created: - // Task has been created, but not started yet. This could only happen if containerd - // gets restarted during container start. - // Container must be in `CREATED` state. - if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to delete task") - } - if status.State() != runtime.ContainerState_CONTAINER_CREATED { - return errors.Errorf("unexpected container state for created task: %q", status.State()) - } - case containerd.Running: - // Task is running. Container must be in `RUNNING` state, based on our assuption that - // "task should not be started when containerd is down". - switch status.State() { - case runtime.ContainerState_CONTAINER_EXITED: - return errors.Errorf("unexpected container state for running task: %q", status.State()) - case runtime.ContainerState_CONTAINER_RUNNING: - default: - // This may happen if containerd gets restarted after task is started, but - // before status is checkpointed. - status.StartedAt = time.Now().UnixNano() - status.Pid = t.Pid() - } - case containerd.Stopped: - // Task is stopped. Updata status and delete the task. - if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to delete task") - } - status.FinishedAt = s.ExitTime.UnixNano() - status.ExitCode = int32(s.ExitStatus) - default: - return errors.Errorf("unexpected task status %q", s.Status) - } - } - return nil - }() - if err != nil { - logrus.WithError(err).Errorf("Failed to load container status for %q", id) - status = unknownContainerStatus() - } - opts := []containerstore.Opts{ - containerstore.WithStatus(status, containerDir), - containerstore.WithContainer(cntr), - } - // containerIO could be nil for container in unknown state. - if containerIO != nil { - opts = append(opts, containerstore.WithContainerIO(containerIO)) - } - return containerstore.NewContainer(*meta, opts...) -} - -// loadSandbox loads sandbox from containerd. -func loadSandbox(ctx context.Context, cntr containerd.Container) (sandboxstore.Sandbox, error) { - ctx, cancel := context.WithTimeout(ctx, loadContainerTimeout) - defer cancel() - var sandbox sandboxstore.Sandbox - // Load sandbox metadata. - exts, err := cntr.Extensions(ctx) - if err != nil { - return sandbox, errors.Wrap(err, "failed to get sandbox container extensions") - } - ext, ok := exts[sandboxMetadataExtension] - if !ok { - return sandbox, errors.Errorf("metadata extension %q not found", sandboxMetadataExtension) - } - data, err := typeurl.UnmarshalAny(&ext) - if err != nil { - return sandbox, errors.Wrapf(err, "failed to unmarshal metadata extension %q", ext) - } - meta := data.(*sandboxstore.Metadata) - - s, err := func() (sandboxstore.Status, error) { - status := unknownSandboxStatus() - // Load sandbox created timestamp. - info, err := cntr.Info(ctx) - if err != nil { - return status, errors.Wrap(err, "failed to get sandbox container info") - } - status.CreatedAt = info.CreatedAt - - // Load sandbox state. - t, err := cntr.Task(ctx, nil) - if err != nil && !errdefs.IsNotFound(err) { - return status, errors.Wrap(err, "failed to load task") - } - var taskStatus containerd.Status - var notFound bool - if errdefs.IsNotFound(err) { - // Task is not found. - notFound = true - } else { - // Task is found. Get task status. - taskStatus, err = t.Status(ctx) - if err != nil { - // It's still possible that task is deleted during this window. - if !errdefs.IsNotFound(err) { - return status, errors.Wrap(err, "failed to get task status") - } - notFound = true - } - } - if notFound { - // Task does not exist, set sandbox state as NOTREADY. - status.State = sandboxstore.StateNotReady - } else { - if taskStatus.Status == containerd.Running { - // Task is running, set sandbox state as READY. - status.State = sandboxstore.StateReady - status.Pid = t.Pid() - } else { - // Task is not running. Delete the task and set sandbox state as NOTREADY. - if _, err := t.Delete(ctx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { - return status, errors.Wrap(err, "failed to delete task") - } - status.State = sandboxstore.StateNotReady - } - } - return status, nil - }() - if err != nil { - logrus.WithError(err).Errorf("Failed to load sandbox status for %q", cntr.ID()) - } - - sandbox = sandboxstore.NewSandbox(*meta, s) - sandbox.Container = cntr - - // Load network namespace. - if meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE { - // Don't need to load netns for host network sandbox. - return sandbox, nil - } - sandbox.NetNS = netns.LoadNetNS(meta.NetNSPath) - - // It doesn't matter whether task is running or not. If it is running, sandbox - // status will be `READY`; if it is not running, sandbox status will be `NOT_READY`, - // kubelet will stop the sandbox which will properly cleanup everything. - return sandbox, nil -} - -// loadImages loads images from containerd. -func (c *criService) loadImages(ctx context.Context, cImages []containerd.Image) { - snapshotter := c.config.ContainerdConfig.Snapshotter - for _, i := range cImages { - ok, _, _, _, err := containerdimages.Check(ctx, i.ContentStore(), i.Target(), platforms.Default()) - if err != nil { - logrus.WithError(err).Errorf("Failed to check image content readiness for %q", i.Name()) - continue - } - if !ok { - logrus.Warnf("The image content readiness for %q is not ok", i.Name()) - continue - } - // Checking existence of top-level snapshot for each image being recovered. - unpacked, err := i.IsUnpacked(ctx, snapshotter) - if err != nil { - logrus.WithError(err).Warnf("Failed to check whether image is unpacked for image %s", i.Name()) - continue - } - if !unpacked { - logrus.Warnf("The image %s is not unpacked.", i.Name()) - // TODO(random-liu): Consider whether we should try unpack here. - } - if err := c.updateImage(ctx, i.Name()); err != nil { - logrus.WithError(err).Warnf("Failed to update reference for image %q", i.Name()) - continue - } - logrus.Debugf("Loaded image %q", i.Name()) - } -} - -func cleanupOrphanedIDDirs(cntrs []containerd.Container, base string) error { - // Cleanup orphaned id directories. - dirs, err := ioutil.ReadDir(base) - if err != nil && !os.IsNotExist(err) { - return errors.Wrap(err, "failed to read base directory") - } - idsMap := make(map[string]containerd.Container) - for _, cntr := range cntrs { - idsMap[cntr.ID()] = cntr - } - for _, d := range dirs { - if !d.IsDir() { - logrus.Warnf("Invalid file %q found in base directory %q", d.Name(), base) - continue - } - if _, ok := idsMap[d.Name()]; ok { - // Do not remove id directory if corresponding container is found. - continue - } - dir := filepath.Join(base, d.Name()) - if err := system.EnsureRemoveAll(dir); err != nil { - logrus.WithError(err).Warnf("Failed to remove id directory %q", dir) - } else { - logrus.Debugf("Cleanup orphaned id directory %q", dir) - } - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_list.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_list.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_list.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_list.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// ListPodSandbox returns a list of Sandbox. -func (c *criService) ListPodSandbox(ctx context.Context, r *runtime.ListPodSandboxRequest) (*runtime.ListPodSandboxResponse, error) { - // List all sandboxes from store. - sandboxesInStore := c.sandboxStore.List() - var sandboxes []*runtime.PodSandbox - for _, sandboxInStore := range sandboxesInStore { - sandboxes = append(sandboxes, toCRISandbox( - sandboxInStore.Metadata, - sandboxInStore.Status.Get(), - )) - } - - sandboxes = c.filterCRISandboxes(sandboxes, r.GetFilter()) - return &runtime.ListPodSandboxResponse{Items: sandboxes}, nil -} - -// toCRISandbox converts sandbox metadata into CRI pod sandbox. -func toCRISandbox(meta sandboxstore.Metadata, status sandboxstore.Status) *runtime.PodSandbox { - // Set sandbox state to NOTREADY by default. - state := runtime.PodSandboxState_SANDBOX_NOTREADY - if status.State == sandboxstore.StateReady { - state = runtime.PodSandboxState_SANDBOX_READY - } - return &runtime.PodSandbox{ - Id: meta.ID, - Metadata: meta.Config.GetMetadata(), - State: state, - CreatedAt: status.CreatedAt.UnixNano(), - Labels: meta.Config.GetLabels(), - Annotations: meta.Config.GetAnnotations(), - } -} - -func (c *criService) normalizePodSandboxFilter(filter *runtime.PodSandboxFilter) { - if sb, err := c.sandboxStore.Get(filter.GetId()); err == nil { - filter.Id = sb.ID - } -} - -// filterCRISandboxes filters CRISandboxes. -func (c *criService) filterCRISandboxes(sandboxes []*runtime.PodSandbox, filter *runtime.PodSandboxFilter) []*runtime.PodSandbox { - if filter == nil { - return sandboxes - } - - c.normalizePodSandboxFilter(filter) - filtered := []*runtime.PodSandbox{} - for _, s := range sandboxes { - // Filter by id - if filter.GetId() != "" && filter.GetId() != s.Id { - continue - } - // Filter by state - if filter.GetState() != nil && filter.GetState().GetState() != s.State { - continue - } - // Filter by label - if filter.GetLabelSelector() != nil { - match := true - for k, v := range filter.GetLabelSelector() { - got, ok := s.Labels[k] - if !ok || got != v { - match = false - break - } - } - if !match { - continue - } - } - filtered = append(filtered, s) - } - - return filtered -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_portforward.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_portforward.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_portforward.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_portforward.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "bytes" - "fmt" - "io" - "os/exec" - "strings" - - "github.com/containernetworking/plugins/pkg/ns" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address. -func (c *criService) PortForward(ctx context.Context, r *runtime.PortForwardRequest) (retRes *runtime.PortForwardResponse, retErr error) { - sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) - if err != nil { - return nil, errors.Wrapf(err, "failed to find sandbox %q", r.GetPodSandboxId()) - } - if sandbox.Status.Get().State != sandboxstore.StateReady { - return nil, errors.New("sandbox container is not running") - } - // TODO(random-liu): Verify that ports are exposed. - return c.streamServer.GetPortForward(r) -} - -// portForward requires `socat` on the node. It uses netns to enter the sandbox namespace, -// and run `socat` insidethe namespace to forward stream for a specific port. The `socat` -// command keeps running until it exits or client disconnect. -func (c *criService) portForward(id string, port int32, stream io.ReadWriteCloser) error { - s, err := c.sandboxStore.Get(id) - if err != nil { - return errors.Wrapf(err, "failed to find sandbox %q in store", id) - } - var netNSDo func(func(ns.NetNS) error) error - // netNSPath is the network namespace path for logging. - var netNSPath string - securityContext := s.Config.GetLinux().GetSecurityContext() - hostNet := securityContext.GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE - if !hostNet { - if closed, err := s.NetNS.Closed(); err != nil { - return errors.Wrapf(err, "failed to check netwok namespace closed for sandbox %q", id) - } else if closed { - return errors.Errorf("network namespace for sandbox %q is closed", id) - } - netNSDo = s.NetNS.Do - netNSPath = s.NetNS.GetPath() - } else { - // Run the function directly for host network. - netNSDo = func(do func(_ ns.NetNS) error) error { - return do(nil) - } - netNSPath = "host" - } - - socat, err := exec.LookPath("socat") - if err != nil { - return errors.Wrap(err, "failed to find socat") - } - - // Check https://linux.die.net/man/1/socat for meaning of the options. - args := []string{socat, "-", fmt.Sprintf("TCP4:localhost:%d", port)} - - logrus.Infof("Executing port forwarding command %q in network namespace %q", strings.Join(args, " "), netNSPath) - err = netNSDo(func(_ ns.NetNS) error { - cmd := exec.Command(args[0], args[1:]...) - cmd.Stdout = stream - - stderr := new(bytes.Buffer) - cmd.Stderr = stderr - - // If we use Stdin, command.Run() won't return until the goroutine that's copying - // from stream finishes. Unfortunately, if you have a client like telnet connected - // via port forwarding, as long as the user's telnet client is connected to the user's - // local listener that port forwarding sets up, the telnet session never exits. This - // means that even if socat has finished running, command.Run() won't ever return - // (because the client still has the connection and stream open). - // - // The work around is to use StdinPipe(), as Wait() (called by Run()) closes the pipe - // when the command (socat) exits. - in, err := cmd.StdinPipe() - if err != nil { - return errors.Wrap(err, "failed to create stdin pipe") - } - go func() { - if _, err := io.Copy(in, stream); err != nil { - logrus.WithError(err).Errorf("Failed to copy port forward input for %q port %d", id, port) - } - in.Close() - logrus.Debugf("Finish copying port forward input for %q port %d", id, port) - }() - - if err := cmd.Run(); err != nil { - return errors.Errorf("socat command returns error: %v, stderr: %q", err, stderr.String()) - } - return nil - }) - if err != nil { - return errors.Wrapf(err, "failed to execute portforward in network namespace %q", netNSPath) - } - logrus.Infof("Finish port forwarding for %q port %d", id, port) - - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_remove.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_remove.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_remove.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_remove.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/containerd/containerd" - "github.com/containerd/containerd/errdefs" - "github.com/docker/docker/pkg/system" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/log" - "github.com/containerd/cri/pkg/store" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// RemovePodSandbox removes the sandbox. If there are running containers in the -// sandbox, they should be forcibly removed. -func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodSandboxRequest) (*runtime.RemovePodSandboxResponse, error) { - sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) - if err != nil { - if err != store.ErrNotExist { - return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q", - r.GetPodSandboxId()) - } - // Do not return error if the id doesn't exist. - log.Tracef("RemovePodSandbox called for sandbox %q that does not exist", - r.GetPodSandboxId()) - return &runtime.RemovePodSandboxResponse{}, nil - } - // Use the full sandbox id. - id := sandbox.ID - - // Return error if sandbox container is still running or unknown. - state := sandbox.Status.Get().State - if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown { - return nil, errors.Errorf("sandbox container %q is not fully stopped", id) - } - - // Return error if sandbox network namespace is not closed yet. - if sandbox.NetNS != nil { - nsPath := sandbox.NetNS.GetPath() - if closed, err := sandbox.NetNS.Closed(); err != nil { - return nil, errors.Wrapf(err, "failed to check sandbox network namespace %q closed", nsPath) - } else if !closed { - return nil, errors.Errorf("sandbox network namespace %q is not fully closed", nsPath) - } - } - - // Remove all containers inside the sandbox. - // NOTE(random-liu): container could still be created after this point, Kubelet should - // not rely on this behavior. - // TODO(random-liu): Introduce an intermediate state to avoid container creation after - // this point. - cntrs := c.containerStore.List() - for _, cntr := range cntrs { - if cntr.SandboxID != id { - continue - } - _, err = c.RemoveContainer(ctx, &runtime.RemoveContainerRequest{ContainerId: cntr.ID}) - if err != nil { - return nil, errors.Wrapf(err, "failed to remove container %q", cntr.ID) - } - } - - // Cleanup the sandbox root directories. - sandboxRootDir := c.getSandboxRootDir(id) - if err := system.EnsureRemoveAll(sandboxRootDir); err != nil { - return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q", - sandboxRootDir) - } - volatileSandboxRootDir := c.getVolatileSandboxRootDir(id) - if err := system.EnsureRemoveAll(volatileSandboxRootDir); err != nil { - return nil, errors.Wrapf(err, "failed to remove volatile sandbox root directory %q", - volatileSandboxRootDir) - } - - // Delete sandbox container. - if err := sandbox.Container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil { - if !errdefs.IsNotFound(err) { - return nil, errors.Wrapf(err, "failed to delete sandbox container %q", id) - } - log.Tracef("Remove called for sandbox container %q that does not exist", id) - } - - // Remove sandbox from sandbox store. Note that once the sandbox is successfully - // deleted: - // 1) ListPodSandbox will not include this sandbox. - // 2) PodSandboxStatus and StopPodSandbox will return error. - // 3) On-going operations which have held the reference will not be affected. - c.sandboxStore.Delete(id) - - // Release the sandbox name reserved for the sandbox. - c.sandboxNameIndex.ReleaseByKey(id) - - return &runtime.RemovePodSandboxResponse{}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,658 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "fmt" - "os" - "strings" - - "github.com/containerd/containerd" - containerdio "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/oci" - cni "github.com/containerd/go-cni" - "github.com/containerd/typeurl" - "github.com/davecgh/go-spew/spew" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "golang.org/x/sys/unix" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/annotations" - criconfig "github.com/containerd/cri/pkg/config" - customopts "github.com/containerd/cri/pkg/containerd/opts" - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - "github.com/containerd/cri/pkg/log" - "github.com/containerd/cri/pkg/netns" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" - "github.com/containerd/cri/pkg/util" -) - -func init() { - typeurl.Register(&sandboxstore.Metadata{}, - "github.com/containerd/cri/pkg/store/sandbox", "Metadata") -} - -// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure -// the sandbox is in ready state. -func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandboxRequest) (_ *runtime.RunPodSandboxResponse, retErr error) { - config := r.GetConfig() - logrus.Debugf("Sandbox config %+v", config) - - // Generate unique id and name for the sandbox and reserve the name. - id := util.GenerateID() - name := makeSandboxName(config.GetMetadata()) - logrus.Debugf("Generated id %q for sandbox %q", id, name) - // Reserve the sandbox name to avoid concurrent `RunPodSandbox` request starting the - // same sandbox. - if err := c.sandboxNameIndex.Reserve(name, id); err != nil { - return nil, errors.Wrapf(err, "failed to reserve sandbox name %q", name) - } - defer func() { - // Release the name if the function returns with an error. - if retErr != nil { - c.sandboxNameIndex.ReleaseByName(name) - } - }() - - // Create initial internal sandbox object. - sandbox := sandboxstore.NewSandbox( - sandboxstore.Metadata{ - ID: id, - Name: name, - Config: config, - RuntimeHandler: r.GetRuntimeHandler(), - }, - sandboxstore.Status{ - State: sandboxstore.StateInit, - }, - ) - - // Ensure sandbox container image snapshot. - image, err := c.ensureImageExists(ctx, c.config.SandboxImage) - if err != nil { - return nil, errors.Wrapf(err, "failed to get sandbox image %q", c.config.SandboxImage) - } - securityContext := config.GetLinux().GetSecurityContext() - //Create Network Namespace if it is not in host network - hostNet := securityContext.GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE - if !hostNet { - // If it is not in host network namespace then create a namespace and set the sandbox - // handle. NetNSPath in sandbox metadata and NetNS is non empty only for non host network - // namespaces. If the pod is in host network namespace then both are empty and should not - // be used. - sandbox.NetNS, err = netns.NewNetNS() - if err != nil { - return nil, errors.Wrapf(err, "failed to create network namespace for sandbox %q", id) - } - sandbox.NetNSPath = sandbox.NetNS.GetPath() - defer func() { - if retErr != nil { - if err := sandbox.NetNS.Remove(); err != nil { - logrus.WithError(err).Errorf("Failed to remove network namespace %s for sandbox %q", sandbox.NetNSPath, id) - } - sandbox.NetNSPath = "" - } - }() - // Setup network for sandbox. - // Certain VM based solutions like clear containers (Issue containerd/cri-containerd#524) - // rely on the assumption that CRI shim will not be querying the network namespace to check the - // network states such as IP. - // In future runtime implementation should avoid relying on CRI shim implementation details. - // In this case however caching the IP will add a subtle performance enhancement by avoiding - // calls to network namespace of the pod to query the IP of the veth interface on every - // SandboxStatus request. - sandbox.IP, err = c.setupPod(id, sandbox.NetNSPath, config) - if err != nil { - return nil, errors.Wrapf(err, "failed to setup network for sandbox %q", id) - } - defer func() { - if retErr != nil { - // Teardown network if an error is returned. - if err := c.teardownPod(id, sandbox.NetNSPath, config); err != nil { - logrus.WithError(err).Errorf("Failed to destroy network for sandbox %q", id) - } - } - }() - } - - ociRuntime, err := c.getSandboxRuntime(config, r.GetRuntimeHandler()) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox runtime") - } - logrus.Debugf("Use OCI %+v for sandbox %q", ociRuntime, id) - - // Create sandbox container. - spec, err := c.generateSandboxContainerSpec(id, config, &image.ImageSpec.Config, sandbox.NetNSPath) - if err != nil { - return nil, errors.Wrap(err, "failed to generate sandbox container spec") - } - logrus.Debugf("Sandbox container %q spec: %#+v", id, spew.NewFormatter(spec)) - - var specOpts []oci.SpecOpts - userstr, err := generateUserString( - "", - securityContext.GetRunAsUser(), - securityContext.GetRunAsGroup(), - ) - if err != nil { - return nil, errors.Wrap(err, "failed to generate user string") - } - if userstr != "" { - specOpts = append(specOpts, oci.WithUser(userstr)) - } - - seccompSpecOpts, err := generateSeccompSpecOpts( - securityContext.GetSeccompProfilePath(), - securityContext.GetPrivileged(), - c.seccompEnabled) - if err != nil { - return nil, errors.Wrap(err, "failed to generate seccomp spec opts") - } - if seccompSpecOpts != nil { - specOpts = append(specOpts, seccompSpecOpts) - } - - sandboxLabels := buildLabels(config.Labels, containerKindSandbox) - - runtimeOpts, err := generateRuntimeOptions(ociRuntime, c.config) - if err != nil { - return nil, errors.Wrap(err, "failed to generate runtime options") - } - opts := []containerd.NewContainerOpts{ - containerd.WithSnapshotter(c.config.ContainerdConfig.Snapshotter), - customopts.WithNewSnapshot(id, image.Image), - containerd.WithSpec(spec, specOpts...), - containerd.WithContainerLabels(sandboxLabels), - containerd.WithContainerExtension(sandboxMetadataExtension, &sandbox.Metadata), - containerd.WithRuntime(ociRuntime.Type, runtimeOpts)} - - container, err := c.client.NewContainer(ctx, id, opts...) - if err != nil { - return nil, errors.Wrap(err, "failed to create containerd container") - } - defer func() { - if retErr != nil { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - if err := container.Delete(deferCtx, containerd.WithSnapshotCleanup); err != nil { - logrus.WithError(err).Errorf("Failed to delete containerd container %q", id) - } - } - }() - - // Create sandbox container root directories. - sandboxRootDir := c.getSandboxRootDir(id) - if err := c.os.MkdirAll(sandboxRootDir, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create sandbox root directory %q", - sandboxRootDir) - } - defer func() { - if retErr != nil { - // Cleanup the sandbox root directory. - if err := c.os.RemoveAll(sandboxRootDir); err != nil { - logrus.WithError(err).Errorf("Failed to remove sandbox root directory %q", - sandboxRootDir) - } - } - }() - volatileSandboxRootDir := c.getVolatileSandboxRootDir(id) - if err := c.os.MkdirAll(volatileSandboxRootDir, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create volatile sandbox root directory %q", - volatileSandboxRootDir) - } - defer func() { - if retErr != nil { - // Cleanup the volatile sandbox root directory. - if err := c.os.RemoveAll(volatileSandboxRootDir); err != nil { - logrus.WithError(err).Errorf("Failed to remove volatile sandbox root directory %q", - volatileSandboxRootDir) - } - } - }() - - // Setup sandbox /dev/shm, /etc/hosts, /etc/resolv.conf and /etc/hostname. - if err = c.setupSandboxFiles(id, config); err != nil { - return nil, errors.Wrapf(err, "failed to setup sandbox files") - } - defer func() { - if retErr != nil { - if err = c.unmountSandboxFiles(id, config); err != nil { - logrus.WithError(err).Errorf("Failed to unmount sandbox files in %q", - sandboxRootDir) - } - } - }() - - // Update sandbox created timestamp. - info, err := container.Info(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox container info") - } - if err := sandbox.Status.Update(func(status sandboxstore.Status) (sandboxstore.Status, error) { - status.CreatedAt = info.CreatedAt - return status, nil - }); err != nil { - return nil, errors.Wrap(err, "failed to update sandbox created timestamp") - } - - // Add sandbox into sandbox store in INIT state. - sandbox.Container = container - if err := c.sandboxStore.Add(sandbox); err != nil { - return nil, errors.Wrapf(err, "failed to add sandbox %+v into store", sandbox) - } - defer func() { - // Delete sandbox from sandbox store if there is an error. - if retErr != nil { - c.sandboxStore.Delete(id) - } - }() - // NOTE(random-liu): Sandbox state only stay in INIT state after this point - // and before the end of this function. - // * If `Update` succeeds, sandbox state will become READY in one transaction. - // * If `Update` fails, sandbox will be removed from the store in the defer above. - // * If containerd stops at any point before `Update` finishes, because sandbox - // state is not checkpointed, it will be recovered from corresponding containerd task - // status during restart: - // * If the task is running, sandbox state will be READY, - // * Or else, sandbox state will be NOTREADY. - // - // In any case, sandbox will leave INIT state, so it's safe to ignore sandbox - // in INIT state in other functions. - - // Start sandbox container in one transaction to avoid race condition with - // event monitor. - if err := sandbox.Status.Update(func(status sandboxstore.Status) (_ sandboxstore.Status, retErr error) { - // NOTE(random-liu): We should not change the sandbox state to NOTREADY - // if `Update` fails. - // - // If `Update` fails, the sandbox will be cleaned up by all the defers - // above. We should not let user see this sandbox, or else they will - // see the sandbox disappear after the defer clean up, which may confuse - // them. - // - // Given so, we should keep the sandbox in INIT state if `Update` fails, - // and ignore sandbox in INIT state in all the inspection functions. - - // Create sandbox task in containerd. - log.Tracef("Create sandbox container (id=%q, name=%q).", - id, name) - - var taskOpts []containerd.NewTaskOpts - // TODO(random-liu): Remove this after shim v1 is deprecated. - if c.config.NoPivot && ociRuntime.Type == linuxRuntime { - taskOpts = append(taskOpts, containerd.WithNoPivotRoot) - } - // We don't need stdio for sandbox container. - task, err := container.NewTask(ctx, containerdio.NullIO, taskOpts...) - if err != nil { - return status, errors.Wrap(err, "failed to create containerd task") - } - defer func() { - if retErr != nil { - deferCtx, deferCancel := ctrdutil.DeferContext() - defer deferCancel() - // Cleanup the sandbox container if an error is returned. - // It's possible that task is deleted by event monitor. - if _, err := task.Delete(deferCtx, containerd.WithProcessKill); err != nil && !errdefs.IsNotFound(err) { - logrus.WithError(err).Errorf("Failed to delete sandbox container %q", id) - } - } - }() - - if err := task.Start(ctx); err != nil { - return status, errors.Wrapf(err, "failed to start sandbox container task %q", id) - } - - // Set the pod sandbox as ready after successfully start sandbox container. - status.Pid = task.Pid() - status.State = sandboxstore.StateReady - return status, nil - }); err != nil { - return nil, errors.Wrap(err, "failed to start sandbox container") - } - - return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil -} - -func (c *criService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig, - imageConfig *imagespec.ImageConfig, nsPath string) (*runtimespec.Spec, error) { - // Creates a spec Generator with the default spec. - // TODO(random-liu): [P1] Compare the default settings with docker and containerd default. - spec, err := defaultRuntimeSpec(id) - if err != nil { - return nil, err - } - g := newSpecGenerator(spec) - - // Apply default config from image config. - if err := addImageEnvs(&g, imageConfig.Env); err != nil { - return nil, err - } - - if imageConfig.WorkingDir != "" { - g.SetProcessCwd(imageConfig.WorkingDir) - } - - if len(imageConfig.Entrypoint) == 0 && len(imageConfig.Cmd) == 0 { - // Pause image must have entrypoint or cmd. - return nil, errors.Errorf("invalid empty entrypoint and cmd in image config %+v", imageConfig) - } - // Set process commands. - g.SetProcessArgs(append(imageConfig.Entrypoint, imageConfig.Cmd...)) - - // Set relative root path. - g.SetRootPath(relativeRootfsPath) - - // Make root of sandbox container read-only. - g.SetRootReadonly(true) - - // Set hostname. - g.SetHostname(config.GetHostname()) - - // TODO(random-liu): [P2] Consider whether to add labels and annotations to the container. - - // Set cgroups parent. - if config.GetLinux().GetCgroupParent() != "" { - cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id, - c.config.SystemdCgroup) - g.SetLinuxCgroupsPath(cgroupsPath) - } - // When cgroup parent is not set, containerd-shim will create container in a child cgroup - // of the cgroup itself is in. - // TODO(random-liu): [P2] Set default cgroup path if cgroup parent is not specified. - - // Set namespace options. - securityContext := config.GetLinux().GetSecurityContext() - nsOptions := securityContext.GetNamespaceOptions() - if nsOptions.GetNetwork() == runtime.NamespaceMode_NODE { - g.RemoveLinuxNamespace(string(runtimespec.NetworkNamespace)) // nolint: errcheck - g.RemoveLinuxNamespace(string(runtimespec.UTSNamespace)) // nolint: errcheck - } else { - //TODO(Abhi): May be move this to containerd spec opts (WithLinuxSpaceOption) - g.AddOrReplaceLinuxNamespace(string(runtimespec.NetworkNamespace), nsPath) // nolint: errcheck - } - if nsOptions.GetPid() == runtime.NamespaceMode_NODE { - g.RemoveLinuxNamespace(string(runtimespec.PIDNamespace)) // nolint: errcheck - } - if nsOptions.GetIpc() == runtime.NamespaceMode_NODE { - g.RemoveLinuxNamespace(string(runtimespec.IPCNamespace)) // nolint: errcheck - } - - // It's fine to generate the spec before the sandbox /dev/shm - // is actually created. - sandboxDevShm := c.getSandboxDevShm(id) - if nsOptions.GetIpc() == runtime.NamespaceMode_NODE { - sandboxDevShm = devShm - } - g.AddMount(runtimespec.Mount{ - Source: sandboxDevShm, - Destination: devShm, - Type: "bind", - Options: []string{"rbind", "ro"}, - }) - - selinuxOpt := securityContext.GetSelinuxOptions() - processLabel, mountLabel, err := initSelinuxOpts(selinuxOpt) - if err != nil { - return nil, errors.Wrapf(err, "failed to init selinux options %+v", securityContext.GetSelinuxOptions()) - } - g.SetProcessSelinuxLabel(processLabel) - g.SetLinuxMountLabel(mountLabel) - - supplementalGroups := securityContext.GetSupplementalGroups() - for _, group := range supplementalGroups { - g.AddProcessAdditionalGid(uint32(group)) - } - - // Add sysctls - sysctls := config.GetLinux().GetSysctls() - for key, value := range sysctls { - g.AddLinuxSysctl(key, value) - } - - // Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile - - g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares)) - g.SetProcessOOMScoreAdj(int(defaultSandboxOOMAdj)) - - g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox) - g.AddAnnotation(annotations.SandboxID, id) - g.AddAnnotation(annotations.SandboxLogDir, config.GetLogDirectory()) - - return g.Config, nil -} - -// setupSandboxFiles sets up necessary sandbox files including /dev/shm, /etc/hosts, -// /etc/resolv.conf and /etc/hostname. -func (c *criService) setupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { - sandboxEtcHostname := c.getSandboxHostname(id) - hostname := config.GetHostname() - if hostname == "" { - var err error - hostname, err = c.os.Hostname() - if err != nil { - return errors.Wrap(err, "failed to get hostname") - } - } - if err := c.os.WriteFile(sandboxEtcHostname, []byte(hostname+"\n"), 0644); err != nil { - return errors.Wrapf(err, "failed to write hostname to %q", sandboxEtcHostname) - } - - // TODO(random-liu): Consider whether we should maintain /etc/hosts and /etc/resolv.conf in kubelet. - sandboxEtcHosts := c.getSandboxHosts(id) - if err := c.os.CopyFile(etcHosts, sandboxEtcHosts, 0644); err != nil { - return errors.Wrapf(err, "failed to generate sandbox hosts file %q", sandboxEtcHosts) - } - - // Set DNS options. Maintain a resolv.conf for the sandbox. - var err error - resolvContent := "" - if dnsConfig := config.GetDnsConfig(); dnsConfig != nil { - resolvContent, err = parseDNSOptions(dnsConfig.Servers, dnsConfig.Searches, dnsConfig.Options) - if err != nil { - return errors.Wrapf(err, "failed to parse sandbox DNSConfig %+v", dnsConfig) - } - } - resolvPath := c.getResolvPath(id) - if resolvContent == "" { - // copy host's resolv.conf to resolvPath - err = c.os.CopyFile(resolvConfPath, resolvPath, 0644) - if err != nil { - return errors.Wrapf(err, "failed to copy host's resolv.conf to %q", resolvPath) - } - } else { - err = c.os.WriteFile(resolvPath, []byte(resolvContent), 0644) - if err != nil { - return errors.Wrapf(err, "failed to write resolv content to %q", resolvPath) - } - } - - // Setup sandbox /dev/shm. - if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() == runtime.NamespaceMode_NODE { - if _, err := c.os.Stat(devShm); err != nil { - return errors.Wrapf(err, "host %q is not available for host ipc", devShm) - } - } else { - sandboxDevShm := c.getSandboxDevShm(id) - if err := c.os.MkdirAll(sandboxDevShm, 0700); err != nil { - return errors.Wrap(err, "failed to create sandbox shm") - } - shmproperty := fmt.Sprintf("mode=1777,size=%d", defaultShmSize) - if err := c.os.Mount("shm", sandboxDevShm, "tmpfs", uintptr(unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV), shmproperty); err != nil { - return errors.Wrap(err, "failed to mount sandbox shm") - } - } - - return nil -} - -// parseDNSOptions parse DNS options into resolv.conf format content, -// if none option is specified, will return empty with no error. -func parseDNSOptions(servers, searches, options []string) (string, error) { - resolvContent := "" - - if len(searches) > maxDNSSearches { - return "", errors.New("DNSOption.Searches has more than 6 domains") - } - - if len(searches) > 0 { - resolvContent += fmt.Sprintf("search %s\n", strings.Join(searches, " ")) - } - - if len(servers) > 0 { - resolvContent += fmt.Sprintf("nameserver %s\n", strings.Join(servers, "\nnameserver ")) - } - - if len(options) > 0 { - resolvContent += fmt.Sprintf("options %s\n", strings.Join(options, " ")) - } - - return resolvContent, nil -} - -// unmountSandboxFiles unmount some sandbox files, we rely on the removal of sandbox root directory to -// remove these files. Unmount should *NOT* return error if the mount point is already unmounted. -func (c *criService) unmountSandboxFiles(id string, config *runtime.PodSandboxConfig) error { - if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE { - path, err := c.os.FollowSymlinkInScope(c.getSandboxDevShm(id), "/") - if err != nil { - return errors.Wrap(err, "failed to follow symlink") - } - if err := c.os.Unmount(path); err != nil && !os.IsNotExist(err) { - return errors.Wrapf(err, "failed to unmount %q", path) - } - } - return nil -} - -// setupPod setups up the network for a pod -func (c *criService) setupPod(id string, path string, config *runtime.PodSandboxConfig) (string, error) { - if c.netPlugin == nil { - return "", errors.New("cni config not intialized") - } - - labels := getPodCNILabels(id, config) - result, err := c.netPlugin.Setup(id, - path, - cni.WithLabels(labels), - cni.WithCapabilityPortMap(toCNIPortMappings(config.GetPortMappings()))) - if err != nil { - return "", err - } - // Check if the default interface has IP config - if configs, ok := result.Interfaces[defaultIfName]; ok && len(configs.IPConfigs) > 0 { - return selectPodIP(configs.IPConfigs), nil - } - // If it comes here then the result was invalid so destroy the pod network and return error - if err := c.teardownPod(id, path, config); err != nil { - logrus.WithError(err).Errorf("Failed to destroy network for sandbox %q", id) - } - return "", errors.Errorf("failed to find network info for sandbox %q", id) -} - -// toCNIPortMappings converts CRI port mappings to CNI. -func toCNIPortMappings(criPortMappings []*runtime.PortMapping) []cni.PortMapping { - var portMappings []cni.PortMapping - for _, mapping := range criPortMappings { - if mapping.HostPort <= 0 { - continue - } - if mapping.Protocol != runtime.Protocol_TCP && mapping.Protocol != runtime.Protocol_UDP { - continue - } - portMappings = append(portMappings, cni.PortMapping{ - HostPort: mapping.HostPort, - ContainerPort: mapping.ContainerPort, - Protocol: strings.ToLower(mapping.Protocol.String()), - HostIP: mapping.HostIp, - }) - } - return portMappings -} - -// selectPodIP select an ip from the ip list. It prefers ipv4 more than ipv6. -func selectPodIP(ipConfigs []*cni.IPConfig) string { - for _, c := range ipConfigs { - if c.IP.To4() != nil { - return c.IP.String() - } - } - return ipConfigs[0].IP.String() -} - -// untrustedWorkload returns true if the sandbox contains untrusted workload. -func untrustedWorkload(config *runtime.PodSandboxConfig) bool { - return config.GetAnnotations()[annotations.UntrustedWorkload] == "true" -} - -// hostAccessingSandbox returns true if the sandbox configuration -// requires additional host access for the sandbox. -func hostAccessingSandbox(config *runtime.PodSandboxConfig) bool { - securityContext := config.GetLinux().GetSecurityContext() - - namespaceOptions := securityContext.GetNamespaceOptions() - if namespaceOptions.GetNetwork() == runtime.NamespaceMode_NODE || - namespaceOptions.GetPid() == runtime.NamespaceMode_NODE || - namespaceOptions.GetIpc() == runtime.NamespaceMode_NODE { - return true - } - - return false -} - -// getSandboxRuntime returns the runtime configuration for sandbox. -// If the sandbox contains untrusted workload, runtime for untrusted workload will be returned, -// or else default runtime will be returned. -func (c *criService) getSandboxRuntime(config *runtime.PodSandboxConfig, runtimeHandler string) (criconfig.Runtime, error) { - if untrustedWorkload(config) { - // If the untrusted annotation is provided, runtimeHandler MUST be empty. - if runtimeHandler != "" && runtimeHandler != criconfig.RuntimeUntrusted { - return criconfig.Runtime{}, errors.New("untrusted workload with explicit runtime handler is not allowed") - } - - // If the untrusted workload is requesting access to the host/node, this request will fail. - // - // Note: If the workload is marked untrusted but requests privileged, this can be granted, as the - // runtime may support this. For example, in a virtual-machine isolated runtime, privileged - // is a supported option, granting the workload to access the entire guest VM instead of host. - if hostAccessingSandbox(config) { - return criconfig.Runtime{}, errors.New("untrusted workload with host access is not allowed") - } - - // Handle the deprecated UntrustedWorkloadRuntime. - if c.config.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { - return c.config.ContainerdConfig.UntrustedWorkloadRuntime, nil - } - - runtimeHandler = criconfig.RuntimeUntrusted - } - - if runtimeHandler == "" { - return c.config.ContainerdConfig.DefaultRuntime, nil - } - - handler, ok := c.config.ContainerdConfig.Runtimes[runtimeHandler] - if !ok { - return criconfig.Runtime{}, errors.Errorf("no runtime for %q is configured", runtimeHandler) - } - return handler, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,201 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "encoding/json" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/errdefs" - runtimespec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// PodSandboxStatus returns the status of the PodSandbox. -func (c *criService) PodSandboxStatus(ctx context.Context, r *runtime.PodSandboxStatusRequest) (*runtime.PodSandboxStatusResponse, error) { - sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) - if err != nil { - return nil, errors.Wrap(err, "an error occurred when try to find sandbox") - } - - ip, err := c.getIP(sandbox) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox ip") - } - status := toCRISandboxStatus(sandbox.Metadata, sandbox.Status.Get(), ip) - if status.GetCreatedAt() == 0 { - // CRI doesn't allow CreatedAt == 0. - info, err := sandbox.Container.Info(ctx) - if err != nil { - return nil, errors.Wrapf(err, "failed to get CreatedAt for sandbox container in %q state", status.State) - } - status.CreatedAt = info.CreatedAt.UnixNano() - } - if !r.GetVerbose() { - return &runtime.PodSandboxStatusResponse{Status: status}, nil - } - - // Generate verbose information. - info, err := toCRISandboxInfo(ctx, sandbox) - if err != nil { - return nil, errors.Wrap(err, "failed to get verbose sandbox container info") - } - - return &runtime.PodSandboxStatusResponse{ - Status: status, - Info: info, - }, nil -} - -func (c *criService) getIP(sandbox sandboxstore.Sandbox) (string, error) { - config := sandbox.Config - - if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE { - // For sandboxes using the node network we are not - // responsible for reporting the IP. - return "", nil - } - - if closed, err := sandbox.NetNS.Closed(); err != nil { - return "", errors.Wrap(err, "check network namespace closed") - } else if closed { - return "", nil - } - - return sandbox.IP, nil -} - -// toCRISandboxStatus converts sandbox metadata into CRI pod sandbox status. -func toCRISandboxStatus(meta sandboxstore.Metadata, status sandboxstore.Status, ip string) *runtime.PodSandboxStatus { - // Set sandbox state to NOTREADY by default. - state := runtime.PodSandboxState_SANDBOX_NOTREADY - if status.State == sandboxstore.StateReady { - state = runtime.PodSandboxState_SANDBOX_READY - } - nsOpts := meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions() - return &runtime.PodSandboxStatus{ - Id: meta.ID, - Metadata: meta.Config.GetMetadata(), - State: state, - CreatedAt: status.CreatedAt.UnixNano(), - Network: &runtime.PodSandboxNetworkStatus{Ip: ip}, - Linux: &runtime.LinuxPodSandboxStatus{ - Namespaces: &runtime.Namespace{ - Options: &runtime.NamespaceOption{ - Network: nsOpts.GetNetwork(), - Pid: nsOpts.GetPid(), - Ipc: nsOpts.GetIpc(), - }, - }, - }, - Labels: meta.Config.GetLabels(), - Annotations: meta.Config.GetAnnotations(), - } -} - -// SandboxInfo is extra information for sandbox. -// TODO (mikebrow): discuss predefining constants structures for some or all of these field names in CRI -type SandboxInfo struct { - Pid uint32 `json:"pid"` - Status string `json:"processStatus"` - NetNSClosed bool `json:"netNamespaceClosed"` - Image string `json:"image"` - SnapshotKey string `json:"snapshotKey"` - Snapshotter string `json:"snapshotter"` - RuntimeHandler string `json:"runtimeHandler"` - RuntimeType string `json:"runtimeType"` - RuntimeOptions interface{} `json:"runtimeOptions"` - Config *runtime.PodSandboxConfig `json:"config"` - RuntimeSpec *runtimespec.Spec `json:"runtimeSpec"` -} - -// toCRISandboxInfo converts internal container object information to CRI sandbox status response info map. -func toCRISandboxInfo(ctx context.Context, sandbox sandboxstore.Sandbox) (map[string]string, error) { - container := sandbox.Container - task, err := container.Task(ctx, nil) - if err != nil && !errdefs.IsNotFound(err) { - return nil, errors.Wrap(err, "failed to get sandbox container task") - } - - var processStatus containerd.ProcessStatus - if task != nil { - taskStatus, err := task.Status(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get task status") - } - - processStatus = taskStatus.Status - } - - si := &SandboxInfo{ - Pid: sandbox.Status.Get().Pid, - RuntimeHandler: sandbox.RuntimeHandler, - Status: string(processStatus), - Config: sandbox.Config, - } - - if si.Status == "" { - // If processStatus is empty, it means that the task is deleted. Apply "deleted" - // status which does not exist in containerd. - si.Status = "deleted" - } - - if sandbox.NetNS != nil { - // Add network closed information if sandbox is not using host network. - closed, err := sandbox.NetNS.Closed() - if err != nil { - return nil, errors.Wrap(err, "failed to check network namespace closed") - } - si.NetNSClosed = closed - } - - spec, err := container.Spec(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox container runtime spec") - } - si.RuntimeSpec = spec - - ctrInfo, err := container.Info(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to get sandbox container info") - } - // Do not use config.SandboxImage because the configuration might - // be changed during restart. It may not reflect the actual image - // used by the sandbox container. - si.Image = ctrInfo.Image - si.SnapshotKey = ctrInfo.SnapshotKey - si.Snapshotter = ctrInfo.Snapshotter - - runtimeOptions, err := getRuntimeOptions(ctrInfo) - if err != nil { - return nil, errors.Wrap(err, "failed to get runtime options") - } - si.RuntimeType = ctrInfo.Runtime.Name - si.RuntimeOptions = runtimeOptions - - infoBytes, err := json.Marshal(si) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal info %v", si) - } - return map[string]string{ - "info": string(infoBytes), - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/sandbox_stop.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "time" - - "github.com/containerd/containerd" - eventtypes "github.com/containerd/containerd/api/events" - "github.com/containerd/containerd/errdefs" - cni "github.com/containerd/go-cni" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - "golang.org/x/sys/unix" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" -) - -// StopPodSandbox stops the sandbox. If there are any running containers in the -// sandbox, they should be forcibly terminated. -func (c *criService) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandboxRequest) (*runtime.StopPodSandboxResponse, error) { - sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId()) - if err != nil { - return nil, errors.Wrapf(err, "an error occurred when try to find sandbox %q", - r.GetPodSandboxId()) - } - // Use the full sandbox id. - id := sandbox.ID - - // Stop all containers inside the sandbox. This terminates the container forcibly, - // and container may still be so production should not rely on this behavior. - // TODO(random-liu): Delete the sandbox container before this after permanent network namespace - // is introduced, so that no container will be started after that. - containers := c.containerStore.List() - for _, container := range containers { - if container.SandboxID != id { - continue - } - // Forcibly stop the container. Do not use `StopContainer`, because it introduces a race - // if a container is removed after list. - if err = c.stopContainer(ctx, container, 0); err != nil { - return nil, errors.Wrapf(err, "failed to stop container %q", container.ID) - } - } - - // Teardown network for sandbox. - if sandbox.NetNS != nil { - netNSPath := sandbox.NetNSPath - // Use empty netns path if netns is not available. This is defined in: - // https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md - if closed, err := sandbox.NetNS.Closed(); err != nil { - return nil, errors.Wrap(err, "failed to check network namespace closed") - } else if closed { - netNSPath = "" - } - if err := c.teardownPod(id, netNSPath, sandbox.Config); err != nil { - return nil, errors.Wrapf(err, "failed to destroy network for sandbox %q", id) - } - if err = sandbox.NetNS.Remove(); err != nil { - return nil, errors.Wrapf(err, "failed to remove network namespace for sandbox %q", id) - } - } - - logrus.Infof("TearDown network for sandbox %q successfully", id) - - if err := c.unmountSandboxFiles(id, sandbox.Config); err != nil { - return nil, errors.Wrap(err, "failed to unmount sandbox files") - } - - // Only stop sandbox container when it's running or unknown. - state := sandbox.Status.Get().State - if state == sandboxstore.StateReady || state == sandboxstore.StateUnknown { - if err := c.stopSandboxContainer(ctx, sandbox); err != nil { - return nil, errors.Wrapf(err, "failed to stop sandbox container %q in %q state", id, state) - } - } - return &runtime.StopPodSandboxResponse{}, nil -} - -// stopSandboxContainer kills the sandbox container. -// `task.Delete` is not called here because it will be called when -// the event monitor handles the `TaskExit` event. -func (c *criService) stopSandboxContainer(ctx context.Context, sandbox sandboxstore.Sandbox) error { - container := sandbox.Container - state := sandbox.Status.Get().State - task, err := container.Task(ctx, nil) - if err != nil { - if !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to get sandbox container") - } - // Don't return for unknown state, some cleanup needs to be done. - if state != sandboxstore.StateUnknown { - return nil - } - // Task is an interface, explicitly set it to nil just in case. - task = nil - } - - // Handle unknown state. - // The cleanup logic is the same with container unknown state. - if state == sandboxstore.StateUnknown { - status, err := getTaskStatus(ctx, task) - if err != nil { - return errors.Wrapf(err, "failed to get task status for %q", sandbox.ID) - } - switch status.Status { - case containerd.Running, containerd.Created: - // The task is still running, continue stopping the task. - case containerd.Stopped: - // The task has exited, explicitly cleanup. - return cleanupUnknownSandbox(ctx, sandbox.ID, status, sandbox) - default: - return errors.Wrapf(err, "unsupported task status %q", status.Status) - } - } - - // Kill the sandbox container. - if err = task.Kill(ctx, unix.SIGKILL); err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "failed to kill sandbox container") - } - - return c.waitSandboxStop(ctx, sandbox, killContainerTimeout) -} - -// waitSandboxStop waits for sandbox to be stopped until timeout exceeds or context is cancelled. -func (c *criService) waitSandboxStop(ctx context.Context, sandbox sandboxstore.Sandbox, timeout time.Duration) error { - timeoutTimer := time.NewTimer(timeout) - defer timeoutTimer.Stop() - select { - case <-ctx.Done(): - return errors.Wrapf(ctx.Err(), "wait sandbox container %q is cancelled", sandbox.ID) - case <-timeoutTimer.C: - return errors.Errorf("wait sandbox container %q stop timeout", sandbox.ID) - case <-sandbox.Stopped(): - return nil - } -} - -// teardownPod removes the network from the pod -func (c *criService) teardownPod(id string, path string, config *runtime.PodSandboxConfig) error { - if c.netPlugin == nil { - return errors.New("cni config not intialized") - } - - labels := getPodCNILabels(id, config) - return c.netPlugin.Remove(id, - path, - cni.WithLabels(labels), - cni.WithCapabilityPortMap(toCNIPortMappings(config.GetPortMappings()))) -} - -// cleanupUnknownSandbox cleanup stopped sandbox in unknown state. -func cleanupUnknownSandbox(ctx context.Context, id string, status containerd.Status, - sandbox sandboxstore.Sandbox) error { - // Reuse handleSandboxExit to do the cleanup. - return handleSandboxExit(ctx, &eventtypes.TaskExit{ - ContainerID: id, - ID: id, - Pid: 0, - ExitStatus: status.ExitStatus, - ExitedAt: status.ExitTime, - }, sandbox) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/service.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/service.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/service.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,269 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "fmt" - "io" - "net/http" - "path/filepath" - "time" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/plugin" - cni "github.com/containerd/go-cni" - runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor" - runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp" - "github.com/opencontainers/selinux/go-selinux" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "google.golang.org/grpc" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - "k8s.io/kubernetes/pkg/kubelet/server/streaming" - - api "github.com/containerd/cri/pkg/api/v1" - "github.com/containerd/cri/pkg/atomic" - criconfig "github.com/containerd/cri/pkg/config" - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - osinterface "github.com/containerd/cri/pkg/os" - "github.com/containerd/cri/pkg/registrar" - containerstore "github.com/containerd/cri/pkg/store/container" - imagestore "github.com/containerd/cri/pkg/store/image" - sandboxstore "github.com/containerd/cri/pkg/store/sandbox" - snapshotstore "github.com/containerd/cri/pkg/store/snapshot" -) - -// grpcServices are all the grpc services provided by cri containerd. -type grpcServices interface { - runtime.RuntimeServiceServer - runtime.ImageServiceServer - api.CRIPluginServiceServer -} - -// CRIService is the interface implement CRI remote service server. -type CRIService interface { - Run() error - // io.Closer is used by containerd to gracefully stop cri service. - io.Closer - plugin.Service - grpcServices -} - -// criService implements CRIService. -type criService struct { - // config contains all configurations. - config criconfig.Config - // imageFSPath is the path to image filesystem. - imageFSPath string - // apparmorEnabled indicates whether apparmor is enabled. - apparmorEnabled bool - // seccompEnabled indicates whether seccomp is enabled. - seccompEnabled bool - // os is an interface for all required os operations. - os osinterface.OS - // sandboxStore stores all resources associated with sandboxes. - sandboxStore *sandboxstore.Store - // sandboxNameIndex stores all sandbox names and make sure each name - // is unique. - sandboxNameIndex *registrar.Registrar - // containerStore stores all resources associated with containers. - containerStore *containerstore.Store - // containerNameIndex stores all container names and make sure each - // name is unique. - containerNameIndex *registrar.Registrar - // imageStore stores all resources associated with images. - imageStore *imagestore.Store - // snapshotStore stores information of all snapshots. - snapshotStore *snapshotstore.Store - // netPlugin is used to setup and teardown network when run/stop pod sandbox. - netPlugin cni.CNI - // client is an instance of the containerd client - client *containerd.Client - // streamServer is the streaming server serves container streaming request. - streamServer streaming.Server - // eventMonitor is the monitor monitors containerd events. - eventMonitor *eventMonitor - // initialized indicates whether the server is initialized. All GRPC services - // should return error before the server is initialized. - initialized atomic.Bool -} - -// NewCRIService returns a new instance of CRIService -func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIService, error) { - var err error - c := &criService{ - config: config, - client: client, - apparmorEnabled: runcapparmor.IsEnabled(), - seccompEnabled: runcseccomp.IsEnabled(), - os: osinterface.RealOS{}, - sandboxStore: sandboxstore.NewStore(), - containerStore: containerstore.NewStore(), - imageStore: imagestore.NewStore(client), - snapshotStore: snapshotstore.NewStore(), - sandboxNameIndex: registrar.NewRegistrar(), - containerNameIndex: registrar.NewRegistrar(), - initialized: atomic.NewBool(false), - } - - if c.config.EnableSelinux { - if !selinux.GetEnabled() { - logrus.Warn("Selinux is not supported") - } - } else { - selinux.SetDisabled() - } - - if client.SnapshotService(c.config.ContainerdConfig.Snapshotter) == nil { - return nil, errors.Errorf("failed to find snapshotter %q", c.config.ContainerdConfig.Snapshotter) - } - - c.imageFSPath = imageFSPath(config.ContainerdRootDir, config.ContainerdConfig.Snapshotter) - logrus.Infof("Get image filesystem path %q", c.imageFSPath) - - // Pod needs to attach to atleast loopback network and a non host network, - // hence networkAttachCount is 2. If there are more network configs the - // pod will be attached to all the networks but we will only use the ip - // of the default network interface as the pod IP. - c.netPlugin, err = cni.New(cni.WithMinNetworkCount(networkAttachCount), - cni.WithPluginConfDir(config.NetworkPluginConfDir), - cni.WithPluginDir([]string{config.NetworkPluginBinDir})) - if err != nil { - return nil, errors.Wrap(err, "failed to initialize cni") - } - - // Try to load the config if it exists. Just log the error if load fails - // This is not disruptive for containerd to panic - if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil { - logrus.WithError(err).Error("Failed to load cni during init, please check CRI plugin status before setting up network for pods") - } - // prepare streaming server - c.streamServer, err = newStreamServer(c, config.StreamServerAddress, config.StreamServerPort) - if err != nil { - return nil, errors.Wrap(err, "failed to create stream server") - } - - c.eventMonitor = newEventMonitor(c) - - return c, nil -} - -// Register registers all required services onto a specific grpc server. -// This is used by containerd cri plugin. -func (c *criService) Register(s *grpc.Server) error { - instrumented := newInstrumentedService(c) - runtime.RegisterRuntimeServiceServer(s, instrumented) - runtime.RegisterImageServiceServer(s, instrumented) - api.RegisterCRIPluginServiceServer(s, instrumented) - return nil -} - -// Run starts the CRI service. -func (c *criService) Run() error { - logrus.Info("Start subscribing containerd event") - c.eventMonitor.subscribe(c.client) - - logrus.Infof("Start recovering state") - if err := c.recover(ctrdutil.NamespacedContext()); err != nil { - return errors.Wrap(err, "failed to recover state") - } - - // Start event handler. - logrus.Info("Start event monitor") - eventMonitorErrCh := c.eventMonitor.start() - - // Start snapshot stats syncer, it doesn't need to be stopped. - logrus.Info("Start snapshots syncer") - snapshotsSyncer := newSnapshotsSyncer( - c.snapshotStore, - c.client.SnapshotService(c.config.ContainerdConfig.Snapshotter), - time.Duration(c.config.StatsCollectPeriod)*time.Second, - ) - snapshotsSyncer.start() - - // Start streaming server. - logrus.Info("Start streaming server") - streamServerErrCh := make(chan error) - go func() { - defer close(streamServerErrCh) - if err := c.streamServer.Start(true); err != nil && err != http.ErrServerClosed { - logrus.WithError(err).Error("Failed to start streaming server") - streamServerErrCh <- err - } - }() - - // Set the server as initialized. GRPC services could start serving traffic. - c.initialized.Set() - - var eventMonitorErr, streamServerErr error - // Stop the whole CRI service if any of the critical service exits. - select { - case eventMonitorErr = <-eventMonitorErrCh: - case streamServerErr = <-streamServerErrCh: - } - if err := c.Close(); err != nil { - return errors.Wrap(err, "failed to stop cri service") - } - // If the error is set above, err from channel must be nil here, because - // the channel is supposed to be closed. Or else, we wait and set it. - if err := <-eventMonitorErrCh; err != nil { - eventMonitorErr = err - } - logrus.Info("Event monitor stopped") - // There is a race condition with http.Server.Serve. - // When `Close` is called at the same time with `Serve`, `Close` - // may finish first, and `Serve` may still block. - // See https://github.com/golang/go/issues/20239. - // Here we set a 2 second timeout for the stream server wait, - // if it timeout, an error log is generated. - // TODO(random-liu): Get rid of this after https://github.com/golang/go/issues/20239 - // is fixed. - const streamServerStopTimeout = 2 * time.Second - select { - case err := <-streamServerErrCh: - if err != nil { - streamServerErr = err - } - logrus.Info("Stream server stopped") - case <-time.After(streamServerStopTimeout): - logrus.Errorf("Stream server is not stopped in %q", streamServerStopTimeout) - } - if eventMonitorErr != nil { - return errors.Wrap(eventMonitorErr, "event monitor error") - } - if streamServerErr != nil { - return errors.Wrap(streamServerErr, "stream server error") - } - return nil -} - -// Close stops the CRI service. -// TODO(random-liu): Make close synchronous. -func (c *criService) Close() error { - logrus.Info("Stop CRI service") - c.eventMonitor.stop() - if err := c.streamServer.Stop(); err != nil { - return errors.Wrap(err, "failed to stop stream server") - } - return nil -} - -// imageFSPath returns containerd image filesystem path. -// Note that if containerd changes directory layout, we also needs to change this. -func imageFSPath(rootDir, snapshotter string) string { - return filepath.Join(rootDir, fmt.Sprintf("%s.%s", plugin.SnapshotPlugin, snapshotter)) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/snapshots.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/snapshots.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/snapshots.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/snapshots.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "context" - "time" - - "github.com/containerd/containerd/errdefs" - snapshot "github.com/containerd/containerd/snapshots" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" - snapshotstore "github.com/containerd/cri/pkg/store/snapshot" -) - -// snapshotsSyncer syncs snapshot stats periodically. imagefs info and container stats -// should both use cached result here. -// TODO(random-liu): Benchmark with high workload. We may need a statsSyncer instead if -// benchmark result shows that container cpu/memory stats also need to be cached. -type snapshotsSyncer struct { - store *snapshotstore.Store - snapshotter snapshot.Snapshotter - syncPeriod time.Duration -} - -// newSnapshotsSyncer creates a snapshot syncer. -func newSnapshotsSyncer(store *snapshotstore.Store, snapshotter snapshot.Snapshotter, - period time.Duration) *snapshotsSyncer { - return &snapshotsSyncer{ - store: store, - snapshotter: snapshotter, - syncPeriod: period, - } -} - -// start starts the snapshots syncer. No stop function is needed because -// the syncer doesn't update any persistent states, it's fine to let it -// exit with the process. -func (s *snapshotsSyncer) start() { - tick := time.NewTicker(s.syncPeriod) - go func() { - defer tick.Stop() - // TODO(random-liu): This is expensive. We should do benchmark to - // check the resource usage and optimize this. - for { - if err := s.sync(); err != nil { - logrus.WithError(err).Error("Failed to sync snapshot stats") - } - <-tick.C - } - }() -} - -// sync updates all snapshots stats. -func (s *snapshotsSyncer) sync() error { - ctx := ctrdutil.NamespacedContext() - start := time.Now().UnixNano() - var snapshots []snapshot.Info - // Do not call `Usage` directly in collect function, because - // `Usage` takes time, we don't want `Walk` to hold read lock - // of snapshot metadata store for too long time. - // TODO(random-liu): Set timeout for the following 2 contexts. - if err := s.snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error { - snapshots = append(snapshots, info) - return nil - }); err != nil { - return errors.Wrap(err, "walk all snapshots failed") - } - for _, info := range snapshots { - sn, err := s.store.Get(info.Name) - if err == nil { - // Only update timestamp for non-active snapshot. - if sn.Kind == info.Kind && sn.Kind != snapshot.KindActive { - sn.Timestamp = time.Now().UnixNano() - s.store.Add(sn) - continue - } - } - // Get newest stats if the snapshot is new or active. - sn = snapshotstore.Snapshot{ - Key: info.Name, - Kind: info.Kind, - Timestamp: time.Now().UnixNano(), - } - usage, err := s.snapshotter.Usage(ctx, info.Name) - if err != nil { - if !errdefs.IsNotFound(err) { - logrus.WithError(err).Errorf("Failed to get usage for snapshot %q", info.Name) - } - continue - } - sn.Size = uint64(usage.Size) - sn.Inodes = uint64(usage.Inodes) - s.store.Add(sn) - } - for _, sn := range s.store.List() { - if sn.Timestamp >= start { - continue - } - // Delete the snapshot stats if it's not updated this time. - s.store.Delete(sn.Key) - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "encoding/json" - "fmt" - goruntime "runtime" - - cni "github.com/containerd/go-cni" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// networkNotReadyReason is the reason reported when network is not ready. -const networkNotReadyReason = "NetworkPluginNotReady" - -// Status returns the status of the runtime. -func (c *criService) Status(ctx context.Context, r *runtime.StatusRequest) (*runtime.StatusResponse, error) { - // As a containerd plugin, if CRI plugin is serving request, - // containerd must be ready. - runtimeCondition := &runtime.RuntimeCondition{ - Type: runtime.RuntimeReady, - Status: true, - } - networkCondition := &runtime.RuntimeCondition{ - Type: runtime.NetworkReady, - Status: true, - } - - // Load the latest cni configuration to be in sync with the latest network configuration - if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil { - logrus.WithError(err).Errorf("Failed to load cni configuration") - } - // Check the status of the cni initialization - if err := c.netPlugin.Status(); err != nil { - networkCondition.Status = false - networkCondition.Reason = networkNotReadyReason - networkCondition.Message = fmt.Sprintf("Network plugin returns error: %v", err) - } - - resp := &runtime.StatusResponse{ - Status: &runtime.RuntimeStatus{Conditions: []*runtime.RuntimeCondition{ - runtimeCondition, - networkCondition, - }}, - } - if r.Verbose { - configByt, err := json.Marshal(c.config) - if err != nil { - return nil, err - } - resp.Info = make(map[string]string) - resp.Info["config"] = string(configByt) - versionByt, err := json.Marshal(goruntime.Version()) - if err != nil { - return nil, err - } - resp.Info["golang"] = string(versionByt) - } - return resp, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/streaming.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/streaming.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/streaming.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/streaming.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "crypto/tls" - "io" - "math" - "net" - "os" - - "github.com/pkg/errors" - k8snet "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/tools/remotecommand" - k8scert "k8s.io/client-go/util/cert" - "k8s.io/kubernetes/pkg/kubelet/server/streaming" - "k8s.io/utils/exec" - - ctrdutil "github.com/containerd/cri/pkg/containerd/util" -) - -type streamListenerMode int - -const ( - x509KeyPairTLS streamListenerMode = iota - selfSignTLS - withoutTLS -) - -func getStreamListenerMode(c *criService) (streamListenerMode, error) { - if c.config.EnableTLSStreaming { - if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" { - return x509KeyPairTLS, nil - } - if c.config.X509KeyPairStreaming.TLSCertFile != "" && c.config.X509KeyPairStreaming.TLSKeyFile == "" { - return -1, errors.New("must set X509KeyPairStreaming.TLSKeyFile") - } - if c.config.X509KeyPairStreaming.TLSCertFile == "" && c.config.X509KeyPairStreaming.TLSKeyFile != "" { - return -1, errors.New("must set X509KeyPairStreaming.TLSCertFile") - } - return selfSignTLS, nil - } - if c.config.X509KeyPairStreaming.TLSCertFile != "" { - return -1, errors.New("X509KeyPairStreaming.TLSCertFile is set but EnableTLSStreaming is not set") - } - if c.config.X509KeyPairStreaming.TLSKeyFile != "" { - return -1, errors.New("X509KeyPairStreaming.TLSKeyFile is set but EnableTLSStreaming is not set") - } - return withoutTLS, nil -} - -func newStreamServer(c *criService, addr, port string) (streaming.Server, error) { - if addr == "" { - a, err := k8snet.ChooseBindAddress(nil) - if err != nil { - return nil, errors.Wrap(err, "failed to get stream server address") - } - addr = a.String() - } - config := streaming.DefaultConfig - config.Addr = net.JoinHostPort(addr, port) - run := newStreamRuntime(c) - tlsMode, err := getStreamListenerMode(c) - if err != nil { - return nil, errors.Wrapf(err, "invalid stream server configuration") - } - switch tlsMode { - case x509KeyPairTLS: - tlsCert, err := tls.LoadX509KeyPair(c.config.X509KeyPairStreaming.TLSCertFile, c.config.X509KeyPairStreaming.TLSKeyFile) - if err != nil { - return nil, errors.Wrap(err, "failed to load x509 key pair for stream server") - } - config.TLSConfig = &tls.Config{ - Certificates: []tls.Certificate{tlsCert}, - } - return streaming.NewServer(config, run) - case selfSignTLS: - tlsCert, err := newTLSCert() - if err != nil { - return nil, errors.Wrap(err, "failed to generate tls certificate for stream server") - } - config.TLSConfig = &tls.Config{ - Certificates: []tls.Certificate{tlsCert}, - InsecureSkipVerify: true, - } - return streaming.NewServer(config, run) - case withoutTLS: - return streaming.NewServer(config, run) - default: - return nil, errors.New("invalid configuration for the stream listener") - } -} - -type streamRuntime struct { - c *criService -} - -func newStreamRuntime(c *criService) streaming.Runtime { - return &streamRuntime{c: c} -} - -// Exec executes a command inside the container. exec.ExitError is returned if the command -// returns non-zero exit code. -func (s *streamRuntime) Exec(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, - tty bool, resize <-chan remotecommand.TerminalSize) error { - exitCode, err := s.c.execInContainer(ctrdutil.NamespacedContext(), containerID, execOptions{ - cmd: cmd, - stdin: stdin, - stdout: stdout, - stderr: stderr, - tty: tty, - resize: resize, - }) - if err != nil { - return errors.Wrap(err, "failed to exec in container") - } - if *exitCode == 0 { - return nil - } - return &exec.CodeExitError{ - Err: errors.Errorf("error executing command %v, exit code %d", cmd, *exitCode), - Code: int(*exitCode), - } -} - -func (s *streamRuntime) Attach(containerID string, in io.Reader, out, err io.WriteCloser, tty bool, - resize <-chan remotecommand.TerminalSize) error { - return s.c.attachContainer(ctrdutil.NamespacedContext(), containerID, in, out, err, tty, resize) -} - -func (s *streamRuntime) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error { - if port <= 0 || port > math.MaxUint16 { - return errors.Errorf("invalid port %d", port) - } - return s.c.portForward(podSandboxID, port, stream) -} - -// handleResizing spawns a goroutine that processes the resize channel, calling resizeFunc for each -// remotecommand.TerminalSize received from the channel. The resize channel must be closed elsewhere to stop the -// goroutine. -func handleResizing(resize <-chan remotecommand.TerminalSize, resizeFunc func(size remotecommand.TerminalSize)) { - if resize == nil { - return - } - - go func() { - defer runtime.HandleCrash() - - for { - size, ok := <-resize - if !ok { - return - } - if size.Height < 1 || size.Width < 1 { - continue - } - resizeFunc(size) - } - }() -} - -// newTLSCert returns a self CA signed tls.certificate. -// TODO (mikebrow): replace / rewrite this function to support using CA -// signing of the cetificate. Requires a security plan for kubernetes regarding -// CRI connections / streaming, etc. For example, kubernetes could configure or -// require a CA service and pass a configuration down through CRI. -func newTLSCert() (tls.Certificate, error) { - fail := func(err error) (tls.Certificate, error) { return tls.Certificate{}, err } - - hostName, err := os.Hostname() - if err != nil { - return fail(errors.Wrap(err, "failed to get hostname")) - } - - addrs, err := net.InterfaceAddrs() - if err != nil { - return fail(errors.Wrap(err, "failed to get host IP addresses")) - } - - var alternateIPs []net.IP - var alternateDNS []string - for _, addr := range addrs { - var ip net.IP - - switch v := addr.(type) { - case *net.IPNet: - ip = v.IP - case *net.IPAddr: - ip = v.IP - default: - continue - } - - alternateIPs = append(alternateIPs, ip) - alternateDNS = append(alternateDNS, ip.String()) - } - - // Generate a self signed certificate key (CA is self) - certPem, keyPem, err := k8scert.GenerateSelfSignedCertKey(hostName, alternateIPs, alternateDNS) - if err != nil { - return fail(errors.Wrap(err, "certificate key could not be created")) - } - - // Load the tls certificate - tlsCert, err := tls.X509KeyPair(certPem, keyPem) - if err != nil { - return fail(errors.Wrap(err, "certificate could not be loaded")) - } - - return tlsCert, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/update_runtime_config.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "os" - "path/filepath" - "text/template" - - cni "github.com/containerd/go-cni" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// cniConfigTemplate contains the values containerd will overwrite -// in the cni config template. -type cniConfigTemplate struct { - // PodCIDR is the cidr for pods on the node. - PodCIDR string -} - -// cniConfigFileName is the name of cni config file generated by containerd. -const cniConfigFileName = "10-containerd-net.conflist" - -// UpdateRuntimeConfig updates the runtime config. Currently only handles podCIDR updates. -func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateRuntimeConfigRequest) (*runtime.UpdateRuntimeConfigResponse, error) { - podCIDR := r.GetRuntimeConfig().GetNetworkConfig().GetPodCidr() - if podCIDR == "" { - return &runtime.UpdateRuntimeConfigResponse{}, nil - } - confTemplate := c.config.NetworkPluginConfTemplate - if confTemplate == "" { - logrus.Info("No cni config template is specified, wait for other system components to drop the config.") - return &runtime.UpdateRuntimeConfigResponse{}, nil - } - if err := c.netPlugin.Status(); err == nil { - logrus.Infof("Network plugin is ready, skip generating cni config from template %q", confTemplate) - return &runtime.UpdateRuntimeConfigResponse{}, nil - } else if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err == nil { - logrus.Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate) - return &runtime.UpdateRuntimeConfigResponse{}, nil - } - logrus.Infof("Generating cni config from template %q", confTemplate) - // generate cni config file from the template with updated pod cidr. - t, err := template.ParseFiles(confTemplate) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse cni config template %q", confTemplate) - } - if err := os.MkdirAll(c.config.NetworkPluginConfDir, 0755); err != nil { - return nil, errors.Wrapf(err, "failed to create cni config directory: %q", c.config.NetworkPluginConfDir) - } - confFile := filepath.Join(c.config.NetworkPluginConfDir, cniConfigFileName) - f, err := os.OpenFile(confFile, os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return nil, errors.Wrapf(err, "failed to open cni config file %q", confFile) - } - defer f.Close() - if err := t.Execute(f, cniConfigTemplate{PodCIDR: podCIDR}); err != nil { - return nil, errors.Wrapf(err, "failed to generate cni config file %q", confFile) - } - return &runtime.UpdateRuntimeConfigResponse{}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/version.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/version.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/server/version.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/server/version.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "github.com/containerd/containerd/version" - "golang.org/x/net/context" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - "github.com/containerd/cri/pkg/constants" -) - -const ( - containerName = "containerd" - // kubeAPIVersion is the api version of kubernetes. - // TODO(random-liu): Change this to actual CRI version. - kubeAPIVersion = "0.1.0" -) - -// Version returns the runtime name, runtime version and runtime API version. -func (c *criService) Version(ctx context.Context, r *runtime.VersionRequest) (*runtime.VersionResponse, error) { - return &runtime.VersionResponse{ - Version: kubeAPIVersion, - RuntimeName: containerName, - RuntimeVersion: version.Version, - RuntimeApiVersion: constants.CRIVersion, - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/container.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/container.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/container.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/container.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package container - -import ( - "sync" - - "github.com/containerd/containerd" - "github.com/docker/docker/pkg/truncindex" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" - - cio "github.com/containerd/cri/pkg/server/io" - "github.com/containerd/cri/pkg/store" -) - -// Container contains all resources associated with the container. All methods to -// mutate the internal state are thread-safe. -type Container struct { - // Metadata is the metadata of the container, it is **immutable** after created. - Metadata - // Status stores the status of the container. - Status StatusStorage - // Container is the containerd container client. - Container containerd.Container - // Container IO. - // IO could only be nil when the container is in unknown state. - IO *cio.ContainerIO - // StopCh is used to propagate the stop information of the container. - *store.StopCh -} - -// Opts sets specific information to newly created Container. -type Opts func(*Container) error - -// WithContainer adds the containerd Container to the internal data store. -func WithContainer(cntr containerd.Container) Opts { - return func(c *Container) error { - c.Container = cntr - return nil - } -} - -// WithContainerIO adds IO into the container. -func WithContainerIO(io *cio.ContainerIO) Opts { - return func(c *Container) error { - c.IO = io - return nil - } -} - -// WithStatus adds status to the container. -func WithStatus(status Status, root string) Opts { - return func(c *Container) error { - s, err := StoreStatus(root, c.ID, status) - if err != nil { - return err - } - c.Status = s - if s.Get().State() == runtime.ContainerState_CONTAINER_EXITED { - c.Stop() - } - return nil - } -} - -// NewContainer creates an internally used container type. -func NewContainer(metadata Metadata, opts ...Opts) (Container, error) { - c := Container{ - Metadata: metadata, - StopCh: store.NewStopCh(), - } - for _, o := range opts { - if err := o(&c); err != nil { - return Container{}, err - } - } - return c, nil -} - -// Delete deletes checkpoint for the container. -func (c *Container) Delete() error { - return c.Status.Delete() -} - -// Store stores all Containers. -type Store struct { - lock sync.RWMutex - containers map[string]Container - idIndex *truncindex.TruncIndex -} - -// NewStore creates a container store. -func NewStore() *Store { - return &Store{ - containers: make(map[string]Container), - idIndex: truncindex.NewTruncIndex([]string{}), - } -} - -// Add a container into the store. Returns store.ErrAlreadyExist if the -// container already exists. -func (s *Store) Add(c Container) error { - s.lock.Lock() - defer s.lock.Unlock() - if _, ok := s.containers[c.ID]; ok { - return store.ErrAlreadyExist - } - if err := s.idIndex.Add(c.ID); err != nil { - return err - } - s.containers[c.ID] = c - return nil -} - -// Get returns the container with specified id. Returns store.ErrNotExist -// if the container doesn't exist. -func (s *Store) Get(id string) (Container, error) { - s.lock.RLock() - defer s.lock.RUnlock() - id, err := s.idIndex.Get(id) - if err != nil { - if err == truncindex.ErrNotExist { - err = store.ErrNotExist - } - return Container{}, err - } - if c, ok := s.containers[id]; ok { - return c, nil - } - return Container{}, store.ErrNotExist -} - -// List lists all containers. -func (s *Store) List() []Container { - s.lock.RLock() - defer s.lock.RUnlock() - var containers []Container - for _, c := range s.containers { - containers = append(containers, c) - } - return containers -} - -// Delete deletes the container from store with specified id. -func (s *Store) Delete(id string) { - s.lock.Lock() - defer s.lock.Unlock() - id, err := s.idIndex.Get(id) - if err != nil { - // Note: The idIndex.Delete and delete doesn't handle truncated index. - // So we need to return if there are error. - return - } - s.idIndex.Delete(id) // nolint: errcheck - delete(s.containers, id) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/fake_status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/fake_status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/fake_status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/fake_status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package container - -import "sync" - -// WithFakeStatus adds fake status to the container. -func WithFakeStatus(status Status) Opts { - return func(c *Container) error { - c.Status = &fakeStatusStorage{status: status} - if status.FinishedAt != 0 { - // Fake the TaskExit event - c.Stop() - } - return nil - } -} - -// fakeStatusStorage is a fake status storage for testing. -type fakeStatusStorage struct { - sync.RWMutex - status Status -} - -func (f *fakeStatusStorage) Get() Status { - f.RLock() - defer f.RUnlock() - return f.status -} - -func (f *fakeStatusStorage) UpdateSync(u UpdateFunc) error { - return f.Update(u) -} - -func (f *fakeStatusStorage) Update(u UpdateFunc) error { - f.Lock() - defer f.Unlock() - newStatus, err := u(f.status) - if err != nil { - return err - } - f.status = newStatus - return nil -} - -func (f *fakeStatusStorage) Delete() error { - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/metadata.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/metadata.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/metadata.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/metadata.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package container - -import ( - "encoding/json" - - "github.com/pkg/errors" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// NOTE(random-liu): -// 1) Metadata is immutable after created. -// 2) Metadata is checkpointed as containerd container label. - -// metadataVersion is current version of container metadata. -const metadataVersion = "v1" // nolint - -// versionedMetadata is the internal versioned container metadata. -// nolint -type versionedMetadata struct { - // Version indicates the version of the versioned container metadata. - Version string - // Metadata's type is metadataInternal. If not there will be a recursive call in MarshalJSON. - Metadata metadataInternal -} - -// metadataInternal is for internal use. -type metadataInternal Metadata - -// Metadata is the unversioned container metadata. -type Metadata struct { - // ID is the container id. - ID string - // Name is the container name. - Name string - // SandboxID is the sandbox id the container belongs to. - SandboxID string - // Config is the CRI container config. - // NOTE(random-liu): Resource limits are updatable, the source - // of truth for resource limits are in containerd. - Config *runtime.ContainerConfig - // ImageRef is the reference of image used by the container. - ImageRef string - // LogPath is the container log path. - LogPath string - // StopSignal is the system call signal that will be sent to the container to exit. - // TODO(random-liu): Add integration test for stop signal. - StopSignal string -} - -// MarshalJSON encodes Metadata into bytes in json format. -func (c *Metadata) MarshalJSON() ([]byte, error) { - return json.Marshal(&versionedMetadata{ - Version: metadataVersion, - Metadata: metadataInternal(*c), - }) -} - -// UnmarshalJSON decodes Metadata from bytes. -func (c *Metadata) UnmarshalJSON(data []byte) error { - versioned := &versionedMetadata{} - if err := json.Unmarshal(data, versioned); err != nil { - return err - } - // Handle old version after upgrade. - switch versioned.Version { - case metadataVersion: - *c = Metadata(versioned.Metadata) - return nil - } - return errors.Errorf("unsupported version: %q", versioned.Version) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/container/status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/container/status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,238 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package container - -import ( - "encoding/json" - "io/ioutil" - "os" - "path/filepath" - "sync" - - "github.com/docker/docker/pkg/ioutils" - "github.com/pkg/errors" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// The container state machine in the CRI plugin: -// -// + + -// | | -// | Create | Load -// | | -// +----v----+ | -// | | | -// | CREATED <---------+-----------+ -// | | | | -// +----+----- | | -// | | | -// | Start | | -// | | | -// +----v----+ | | -// Exec +--------+ | | | -// Attach | | RUNNING <---------+ | -// LogReopen +--------> | | | -// +----+----+ | | -// | | | -// | Stop/Exit | | -// | | | -// +----v----+ | | -// | <---------+ +----v----+ -// | EXITED | | | -// | <----------------+ UNKNOWN | -// +----+----+ Stop | | -// | +---------+ -// | Remove -// v -// DELETED - -// statusVersion is current version of container status. -const statusVersion = "v1" // nolint - -// versionedStatus is the internal used versioned container status. -// nolint -type versionedStatus struct { - // Version indicates the version of the versioned container status. - Version string - Status -} - -// Status is the status of a container. -type Status struct { - // Pid is the init process id of the container. - Pid uint32 - // CreatedAt is the created timestamp. - CreatedAt int64 - // StartedAt is the started timestamp. - StartedAt int64 - // FinishedAt is the finished timestamp. - FinishedAt int64 - // ExitCode is the container exit code. - ExitCode int32 - // CamelCase string explaining why container is in its current state. - Reason string - // Human-readable message indicating details about why container is in its - // current state. - Message string - // Removing indicates that the container is in removing state. - // This field doesn't need to be checkpointed. - Removing bool `json:"-"` -} - -// State returns current state of the container based on the container status. -func (s Status) State() runtime.ContainerState { - if s.FinishedAt != 0 { - return runtime.ContainerState_CONTAINER_EXITED - } - if s.StartedAt != 0 { - return runtime.ContainerState_CONTAINER_RUNNING - } - if s.CreatedAt != 0 { - return runtime.ContainerState_CONTAINER_CREATED - } - return runtime.ContainerState_CONTAINER_UNKNOWN -} - -// encode encodes Status into bytes in json format. -func (s *Status) encode() ([]byte, error) { - return json.Marshal(&versionedStatus{ - Version: statusVersion, - Status: *s, - }) -} - -// decode decodes Status from bytes. -func (s *Status) decode(data []byte) error { - versioned := &versionedStatus{} - if err := json.Unmarshal(data, versioned); err != nil { - return err - } - // Handle old version after upgrade. - switch versioned.Version { - case statusVersion: - *s = versioned.Status - return nil - } - return errors.New("unsupported version") -} - -// UpdateFunc is function used to update the container status. If there -// is an error, the update will be rolled back. -type UpdateFunc func(Status) (Status, error) - -// StatusStorage manages the container status with a storage backend. -type StatusStorage interface { - // Get a container status. - Get() Status - // UpdateSync updates the container status and the on disk checkpoint. - // Note that the update MUST be applied in one transaction. - UpdateSync(UpdateFunc) error - // Update the container status. Note that the update MUST be applied - // in one transaction. - Update(UpdateFunc) error - // Delete the container status. - // Note: - // * Delete should be idempotent. - // * The status must be deleted in one trasaction. - Delete() error -} - -// StoreStatus creates the storage containing the passed in container status with the -// specified id. -// The status MUST be created in one transaction. -func StoreStatus(root, id string, status Status) (StatusStorage, error) { - data, err := status.encode() - if err != nil { - return nil, errors.Wrap(err, "failed to encode status") - } - path := filepath.Join(root, "status") - if err := ioutils.AtomicWriteFile(path, data, 0600); err != nil { - return nil, errors.Wrapf(err, "failed to checkpoint status to %q", path) - } - return &statusStorage{ - path: path, - status: status, - }, nil -} - -// LoadStatus loads container status from checkpoint. There shouldn't be threads -// writing to the file during loading. -func LoadStatus(root, id string) (Status, error) { - path := filepath.Join(root, "status") - data, err := ioutil.ReadFile(path) - if err != nil { - return Status{}, errors.Wrapf(err, "failed to read status from %q", path) - } - var status Status - if err := status.decode(data); err != nil { - return Status{}, errors.Wrapf(err, "failed to decode status %q", data) - } - return status, nil -} - -type statusStorage struct { - sync.RWMutex - path string - status Status -} - -// Get a copy of container status. -func (s *statusStorage) Get() Status { - s.RLock() - defer s.RUnlock() - return s.status -} - -// UpdateSync updates the container status and the on disk checkpoint. -func (s *statusStorage) UpdateSync(u UpdateFunc) error { - s.Lock() - defer s.Unlock() - newStatus, err := u(s.status) - if err != nil { - return err - } - data, err := newStatus.encode() - if err != nil { - return errors.Wrap(err, "failed to encode status") - } - if err := ioutils.AtomicWriteFile(s.path, data, 0600); err != nil { - return errors.Wrapf(err, "failed to checkpoint status to %q", s.path) - } - s.status = newStatus - return nil -} - -// Update the container status. -func (s *statusStorage) Update(u UpdateFunc) error { - s.Lock() - defer s.Unlock() - newStatus, err := u(s.status) - if err != nil { - return err - } - s.status = newStatus - return nil -} - -// Delete deletes the container status from disk atomically. -func (s *statusStorage) Delete() error { - temp := filepath.Dir(s.path) + ".del-" + filepath.Base(s.path) - if err := os.Rename(s.path, temp); err != nil && !os.IsNotExist(err) { - return err - } - return os.RemoveAll(temp) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/errors.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/errors.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/errors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/errors.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package store - -import "errors" - -var ( - // ErrAlreadyExist is the error returned when data added in the store - // already exists. - ErrAlreadyExist = errors.New("already exists") - // ErrNotExist is the error returned when data is not in the store. - ErrNotExist = errors.New("does not exist") -) diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/image/fake_image.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/image/fake_image.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/image/fake_image.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/image/fake_image.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package image - -import "github.com/pkg/errors" - -// NewFakeStore returns an image store with predefined images. -// Update is not allowed for this fake store. -func NewFakeStore(images []Image) (*Store, error) { - s := NewStore(nil) - for _, i := range images { - for _, ref := range i.References { - s.refCache[ref] = i.ID - } - if err := s.store.add(i); err != nil { - return nil, errors.Wrapf(err, "add image %+v", i) - } - } - return s, nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/image/image.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/image/image.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/image/image.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/image/image.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package image - -import ( - "context" - "encoding/json" - "sync" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" - "github.com/docker/distribution/digestset" - imagedigest "github.com/opencontainers/go-digest" - imageidentity "github.com/opencontainers/image-spec/identity" - imagespec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" - - storeutil "github.com/containerd/cri/pkg/store" - "github.com/containerd/cri/pkg/util" -) - -// Image contains all resources associated with the image. All fields -// MUST not be mutated directly after created. -type Image struct { - // Id of the image. Normally the digest of image config. - ID string - // References are references to the image, e.g. RepoTag and RepoDigest. - References []string - // ChainID is the chainID of the image. - ChainID string - // Size is the compressed size of the image. - Size int64 - // ImageSpec is the oci image structure which describes basic information about the image. - ImageSpec imagespec.Image - // Containerd image reference - Image containerd.Image -} - -// Store stores all images. -type Store struct { - lock sync.RWMutex - // refCache is a containerd image reference to image id cache. - refCache map[string]string - // client is the containerd client. - client *containerd.Client - // store is the internal image store indexed by image id. - store *store -} - -// NewStore creates an image store. -func NewStore(client *containerd.Client) *Store { - return &Store{ - refCache: make(map[string]string), - client: client, - store: &store{ - images: make(map[string]Image), - digestSet: digestset.NewSet(), - }, - } -} - -// Update updates cache for a reference. -func (s *Store) Update(ctx context.Context, ref string) error { - s.lock.Lock() - defer s.lock.Unlock() - i, err := s.client.GetImage(ctx, ref) - if err != nil && !errdefs.IsNotFound(err) { - return errors.Wrap(err, "get image from containerd") - } - var img *Image - if err == nil { - img, err = getImage(ctx, i) - if err != nil { - return errors.Wrap(err, "get image info from containerd") - } - } - return s.update(ref, img) -} - -// update updates the internal cache. img == nil means that -// the image does not exist in containerd. -func (s *Store) update(ref string, img *Image) error { - oldID, oldExist := s.refCache[ref] - if img == nil { - // The image reference doesn't exist in containerd. - if oldExist { - // Remove the reference from the store. - s.store.delete(oldID, ref) - delete(s.refCache, ref) - } - return nil - } - if oldExist { - if oldID == img.ID { - return nil - } - // Updated. Remove tag from old image. - s.store.delete(oldID, ref) - } - // New image. Add new image. - s.refCache[ref] = img.ID - return s.store.add(*img) -} - -// getImage gets image information from containerd. -func getImage(ctx context.Context, i containerd.Image) (*Image, error) { - // Get image information. - diffIDs, err := i.RootFS(ctx) - if err != nil { - return nil, errors.Wrap(err, "get image diffIDs") - } - chainID := imageidentity.ChainID(diffIDs) - - size, err := i.Size(ctx) - if err != nil { - return nil, errors.Wrap(err, "get image compressed resource size") - } - - desc, err := i.Config(ctx) - if err != nil { - return nil, errors.Wrap(err, "get image config descriptor") - } - id := desc.Digest.String() - - rb, err := content.ReadBlob(ctx, i.ContentStore(), desc) - if err != nil { - return nil, errors.Wrap(err, "read image config from content store") - } - var ociimage imagespec.Image - if err := json.Unmarshal(rb, &ociimage); err != nil { - return nil, errors.Wrapf(err, "unmarshal image config %s", rb) - } - - return &Image{ - ID: id, - References: []string{i.Name()}, - ChainID: chainID.String(), - Size: size, - ImageSpec: ociimage, - Image: i, - }, nil -} - -// Resolve resolves a image reference to image id. -func (s *Store) Resolve(ref string) (string, error) { - s.lock.RLock() - defer s.lock.RUnlock() - id, ok := s.refCache[ref] - if !ok { - return "", storeutil.ErrNotExist - } - return id, nil -} - -// Get gets image metadata by image id. The id can be truncated. -// Returns various validation errors if the image id is invalid. -// Returns storeutil.ErrNotExist if the image doesn't exist. -func (s *Store) Get(id string) (Image, error) { - return s.store.get(id) -} - -// List lists all images. -func (s *Store) List() []Image { - return s.store.list() -} - -type store struct { - lock sync.RWMutex - images map[string]Image - digestSet *digestset.Set -} - -func (s *store) list() []Image { - s.lock.RLock() - defer s.lock.RUnlock() - var images []Image - for _, i := range s.images { - images = append(images, i) - } - return images -} - -func (s *store) add(img Image) error { - s.lock.Lock() - defer s.lock.Unlock() - if _, err := s.digestSet.Lookup(img.ID); err != nil { - if err != digestset.ErrDigestNotFound { - return err - } - if err := s.digestSet.Add(imagedigest.Digest(img.ID)); err != nil { - return err - } - } - - i, ok := s.images[img.ID] - if !ok { - // If the image doesn't exist, add it. - s.images[img.ID] = img - return nil - } - // Or else, merge the references. - i.References = util.MergeStringSlices(i.References, img.References) - s.images[img.ID] = i - return nil -} - -func (s *store) get(id string) (Image, error) { - s.lock.RLock() - defer s.lock.RUnlock() - digest, err := s.digestSet.Lookup(id) - if err != nil { - if err == digestset.ErrDigestNotFound { - err = storeutil.ErrNotExist - } - return Image{}, err - } - if i, ok := s.images[digest.String()]; ok { - return i, nil - } - return Image{}, storeutil.ErrNotExist -} - -func (s *store) delete(id, ref string) { - s.lock.Lock() - defer s.lock.Unlock() - digest, err := s.digestSet.Lookup(id) - if err != nil { - // Note: The idIndex.Delete and delete doesn't handle truncated index. - // So we need to return if there are error. - return - } - i, ok := s.images[digest.String()] - if !ok { - return - } - i.References = util.SubtractStringSlice(i.References, ref) - if len(i.References) != 0 { - s.images[digest.String()] = i - return - } - // Remove the image if it is not referenced any more. - s.digestSet.Remove(digest) // nolint: errcheck - delete(s.images, digest.String()) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/metadata.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/metadata.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/metadata.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/metadata.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sandbox - -import ( - "encoding/json" - - "github.com/pkg/errors" - runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" -) - -// NOTE(random-liu): -// 1) Metadata is immutable after created. -// 2) Metadata is checkpointed as containerd container label. - -// metadataVersion is current version of sandbox metadata. -const metadataVersion = "v1" // nolint - -// versionedMetadata is the internal versioned sandbox metadata. -// nolint -type versionedMetadata struct { - // Version indicates the version of the versioned sandbox metadata. - Version string - // Metadata's type is metadataInternal. If not there will be a recursive call in MarshalJSON. - Metadata metadataInternal -} - -// metadataInternal is for internal use. -type metadataInternal Metadata - -// Metadata is the unversioned sandbox metadata. -type Metadata struct { - // ID is the sandbox id. - ID string - // Name is the sandbox name. - Name string - // Config is the CRI sandbox config. - Config *runtime.PodSandboxConfig - // NetNSPath is the network namespace used by the sandbox. - NetNSPath string - // IP of Pod if it is attached to non host network - IP string - // RuntimeHandler is the runtime handler name of the pod. - RuntimeHandler string -} - -// MarshalJSON encodes Metadata into bytes in json format. -func (c *Metadata) MarshalJSON() ([]byte, error) { - return json.Marshal(&versionedMetadata{ - Version: metadataVersion, - Metadata: metadataInternal(*c), - }) -} - -// UnmarshalJSON decodes Metadata from bytes. -func (c *Metadata) UnmarshalJSON(data []byte) error { - versioned := &versionedMetadata{} - if err := json.Unmarshal(data, versioned); err != nil { - return err - } - // Handle old version after upgrade. - switch versioned.Version { - case metadataVersion: - *c = Metadata(versioned.Metadata) - return nil - } - return errors.Errorf("unsupported version: %q", versioned.Version) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/sandbox.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/sandbox.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/sandbox.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/sandbox.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sandbox - -import ( - "sync" - - "github.com/containerd/containerd" - "github.com/docker/docker/pkg/truncindex" - - "github.com/containerd/cri/pkg/netns" - "github.com/containerd/cri/pkg/store" -) - -// Sandbox contains all resources associated with the sandbox. All methods to -// mutate the internal state are thread safe. -type Sandbox struct { - // Metadata is the metadata of the sandbox, it is immutable after created. - Metadata - // Status stores the status of the sandbox. - Status StatusStorage - // Container is the containerd sandbox container client. - Container containerd.Container - // CNI network namespace client. - // For hostnetwork pod, this is always nil; - // For non hostnetwork pod, this should never be nil. - NetNS *netns.NetNS - // StopCh is used to propagate the stop information of the sandbox. - *store.StopCh -} - -// NewSandbox creates an internally used sandbox type. This functions reminds -// the caller that a sandbox must have a status. -func NewSandbox(metadata Metadata, status Status) Sandbox { - s := Sandbox{ - Metadata: metadata, - Status: StoreStatus(status), - StopCh: store.NewStopCh(), - } - if status.State == StateNotReady { - s.Stop() - } - return s -} - -// Store stores all sandboxes. -type Store struct { - lock sync.RWMutex - sandboxes map[string]Sandbox - idIndex *truncindex.TruncIndex -} - -// NewStore creates a sandbox store. -func NewStore() *Store { - return &Store{ - sandboxes: make(map[string]Sandbox), - idIndex: truncindex.NewTruncIndex([]string{}), - } -} - -// Add a sandbox into the store. -func (s *Store) Add(sb Sandbox) error { - s.lock.Lock() - defer s.lock.Unlock() - if _, ok := s.sandboxes[sb.ID]; ok { - return store.ErrAlreadyExist - } - if err := s.idIndex.Add(sb.ID); err != nil { - return err - } - s.sandboxes[sb.ID] = sb - return nil -} - -// Get returns the sandbox with specified id. Returns store.ErrNotExist -// if the sandbox doesn't exist. -func (s *Store) Get(id string) (Sandbox, error) { - sb, err := s.GetAll(id) - if err != nil { - return sb, err - } - if sb.Status.Get().State == StateInit { - return Sandbox{}, store.ErrNotExist - } - return sb, nil -} - -// GetAll returns the sandbox with specified id, including sandbox in unknown -// state. Returns store.ErrNotExist if the sandbox doesn't exist. -func (s *Store) GetAll(id string) (Sandbox, error) { - s.lock.RLock() - defer s.lock.RUnlock() - id, err := s.idIndex.Get(id) - if err != nil { - if err == truncindex.ErrNotExist { - err = store.ErrNotExist - } - return Sandbox{}, err - } - if sb, ok := s.sandboxes[id]; ok { - return sb, nil - } - return Sandbox{}, store.ErrNotExist -} - -// List lists all sandboxes. -func (s *Store) List() []Sandbox { - s.lock.RLock() - defer s.lock.RUnlock() - var sandboxes []Sandbox - for _, sb := range s.sandboxes { - if sb.Status.Get().State == StateInit { - continue - } - sandboxes = append(sandboxes, sb) - } - return sandboxes -} - -// Delete deletes the sandbox with specified id. -func (s *Store) Delete(id string) { - s.lock.Lock() - defer s.lock.Unlock() - id, err := s.idIndex.Get(id) - if err != nil { - // Note: The idIndex.Delete and delete doesn't handle truncated index. - // So we need to return if there are error. - return - } - s.idIndex.Delete(id) // nolint: errcheck - delete(s.sandboxes, id) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/status.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/status.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/sandbox/status.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/sandbox/status.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sandbox - -import ( - "sync" - "time" -) - -// The sandbox state machine in the CRI plugin: -// + + -// | | -// | Create(Run) | Load -// | | -// Start +----v----+ | -// (failed) | | | -// +-------------+ INIT | +-----------+ -// | | | | | -// | +----+----+ | | -// | | | | -// | | Start(Run) | | -// | | | | -// | PortForward +----v----+ | | -// | +------+ | | | -// | | | READY <---------+ | -// | +------> | | | -// | +----+----+ | | -// | | | | -// | | Stop/Exit | | -// | | | | -// | +----v----+ | | -// | | <---------+ +----v----+ -// | | NOTREADY| | | -// | | <----------------+ UNKNOWN | -// | +----+----+ Stop | | -// | | +---------+ -// | | Remove -// | v -// +-------------> DELETED - -// State is the sandbox state we use in containerd/cri. -// It includes init and unknown, which are internal states not defined in CRI. -// The state mapping from internal states to CRI states: -// * ready -> ready -// * not ready -> not ready -// * init -> not exist -// * unknown -> not ready -type State uint32 - -const ( - // StateInit is init state of sandbox. Sandbox - // is in init state before its corresponding sandbox container - // is created. Sandbox in init state should be ignored by most - // functions, unless the caller needs to update sandbox state. - StateInit State = iota - // StateReady is ready state, it means sandbox container - // is running. - StateReady - // StateNotReady is notready state, it ONLY means sandbox - // container is not running. - // StopPodSandbox should still be called for NOTREADY sandbox to - // cleanup resources other than sandbox container, e.g. network namespace. - // This is an assumption made in CRI. - StateNotReady - // StateUnknown is unknown state. Sandbox only goes - // into unknown state when its status fails to be loaded. - StateUnknown -) - -// Status is the status of a sandbox. -type Status struct { - // Pid is the init process id of the sandbox container. - Pid uint32 - // CreatedAt is the created timestamp. - CreatedAt time.Time - // State is the state of the sandbox. - State State -} - -// UpdateFunc is function used to update the sandbox status. If there -// is an error, the update will be rolled back. -type UpdateFunc func(Status) (Status, error) - -// StatusStorage manages the sandbox status. -// The status storage for sandbox is different from container status storage, -// because we don't checkpoint sandbox status. If we need checkpoint in the -// future, we should combine this with container status storage. -type StatusStorage interface { - // Get a sandbox status. - Get() Status - // Update the sandbox status. Note that the update MUST be applied - // in one transaction. - Update(UpdateFunc) error -} - -// StoreStatus creates the storage containing the passed in sandbox status with the -// specified id. -// The status MUST be created in one transaction. -func StoreStatus(status Status) StatusStorage { - return &statusStorage{status: status} -} - -type statusStorage struct { - sync.RWMutex - status Status -} - -// Get a copy of sandbox status. -func (s *statusStorage) Get() Status { - s.RLock() - defer s.RUnlock() - return s.status -} - -// Update the sandbox status. -func (s *statusStorage) Update(u UpdateFunc) error { - s.Lock() - defer s.Unlock() - newStatus, err := u(s.status) - if err != nil { - return err - } - s.status = newStatus - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/snapshot/snapshot.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/snapshot/snapshot.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/snapshot/snapshot.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/snapshot/snapshot.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package snapshot - -import ( - "sync" - - snapshot "github.com/containerd/containerd/snapshots" - - "github.com/containerd/cri/pkg/store" -) - -// Snapshot contains the information about the snapshot. -type Snapshot struct { - // Key is the key of the snapshot - Key string - // Kind is the kind of the snapshot (active, commited, view) - Kind snapshot.Kind - // Size is the size of the snapshot in bytes. - Size uint64 - // Inodes is the number of inodes used by the snapshot - Inodes uint64 - // Timestamp is latest update time (in nanoseconds) of the snapshot - // information. - Timestamp int64 -} - -// Store stores all snapshots. -type Store struct { - lock sync.RWMutex - snapshots map[string]Snapshot -} - -// NewStore creates a snapshot store. -func NewStore() *Store { - return &Store{snapshots: make(map[string]Snapshot)} -} - -// Add a snapshot into the store. -func (s *Store) Add(snapshot Snapshot) { - s.lock.Lock() - defer s.lock.Unlock() - s.snapshots[snapshot.Key] = snapshot -} - -// Get returns the snapshot with specified key. Returns store.ErrNotExist if the -// snapshot doesn't exist. -func (s *Store) Get(key string) (Snapshot, error) { - s.lock.RLock() - defer s.lock.RUnlock() - if sn, ok := s.snapshots[key]; ok { - return sn, nil - } - return Snapshot{}, store.ErrNotExist -} - -// List lists all snapshots. -func (s *Store) List() []Snapshot { - s.lock.RLock() - defer s.lock.RUnlock() - var snapshots []Snapshot - for _, sn := range s.snapshots { - snapshots = append(snapshots, sn) - } - return snapshots -} - -// Delete deletes the snapshot with specified key. -func (s *Store) Delete(key string) { - s.lock.Lock() - defer s.lock.Unlock() - delete(s.snapshots, key) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/util.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/util.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/store/util.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/store/util.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package store - -import "sync" - -// StopCh is used to propagate the stop information of a container. -type StopCh struct { - ch chan struct{} - once sync.Once -} - -// NewStopCh creates a stop channel. The channel is open by default. -func NewStopCh() *StopCh { - return &StopCh{ch: make(chan struct{})} -} - -// Stop close stopCh of the container. -func (s *StopCh) Stop() { - s.once.Do(func() { - close(s.ch) - }) -} - -// Stopped return the stopCh of the container as a readonly channel. -func (s *StopCh) Stopped() <-chan struct{} { - return s.ch -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/deep_copy.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/deep_copy.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/deep_copy.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/deep_copy.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "encoding/json" - - "github.com/pkg/errors" -) - -// DeepCopy makes a deep copy from src into dst. -func DeepCopy(dst interface{}, src interface{}) error { - if dst == nil { - return errors.New("dst cannot be nil") - } - if src == nil { - return errors.New("src cannot be nil") - } - bytes, err := json.Marshal(src) - if err != nil { - return errors.Wrap(err, "unable to marshal src") - } - err = json.Unmarshal(bytes, dst) - if err != nil { - return errors.Wrap(err, "unable to unmarshal into dst") - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/id.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/id.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/id.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/id.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "encoding/hex" - "math/rand" -) - -// GenerateID generates a random unique id. -func GenerateID() string { - b := make([]byte, 32) - rand.Read(b) - return hex.EncodeToString(b) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/image.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/image.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/image.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/image.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "github.com/docker/distribution/reference" -) - -// NormalizeImageRef normalizes the image reference following the docker convention. This is added -// mainly for backward compatibility. -// The reference returned can only be either tagged or digested. For reference contains both tag -// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ -// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as -// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. -func NormalizeImageRef(ref string) (reference.Named, error) { - named, err := reference.ParseNormalizedNamed(ref) - if err != nil { - return nil, err - } - if _, ok := named.(reference.NamedTagged); ok { - if canonical, ok := named.(reference.Canonical); ok { - // The reference is both tagged and digested, only - // return digested. - newNamed, err := reference.WithName(canonical.Name()) - if err != nil { - return nil, err - } - newCanonical, err := reference.WithDigest(newNamed, canonical.Digest()) - if err != nil { - return nil, err - } - return newCanonical, nil - } - } - return reference.TagNameOnly(named), nil -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/strings.go containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/strings.go --- containerd-1.2.6/vendor/github.com/containerd/cri/pkg/util/strings.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/pkg/util/strings.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import "strings" - -// InStringSlice checks whether a string is inside a string slice. -// Comparison is case insensitive. -func InStringSlice(ss []string, str string) bool { - for _, s := range ss { - if strings.EqualFold(s, str) { - return true - } - } - return false -} - -// SubtractStringSlice subtracts string from string slice. -// Comparison is case insensitive. -func SubtractStringSlice(ss []string, str string) []string { - var res []string - for _, s := range ss { - if strings.EqualFold(s, str) { - continue - } - res = append(res, s) - } - return res -} - -// MergeStringSlices merges 2 string slices into one and remove duplicated elements. -func MergeStringSlices(a []string, b []string) []string { - set := map[string]struct{}{} - for _, s := range a { - set[s] = struct{}{} - } - for _, s := range b { - set[s] = struct{}{} - } - var ss []string - for s := range set { - ss = append(ss, s) - } - return ss -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/README.md containerd-1.5.9/vendor/github.com/containerd/cri/README.md --- containerd-1.2.6/vendor/github.com/containerd/cri/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,176 +0,0 @@ -# cri -

- - -

- -*Note: The standalone `cri-containerd` binary is end-of-life. `cri-containerd` is -transitioning from a standalone binary that talks to containerd to a plugin within -containerd. This github branch is for the `cri` plugin. See -[standalone-cri-containerd branch](https://github.com/containerd/cri/tree/standalone-cri-containerd) -for information about the standalone version of `cri-containerd`.* - -*Note: You need to [drain your node](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/) before upgrading from standalone `cri-containerd` to containerd with `cri` plugin.* - -[![Build Status](https://api.travis-ci.org/containerd/cri.svg?style=flat-square)](https://travis-ci.org/containerd/cri) -[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cri)](https://goreportcard.com/report/github.com/containerd/cri) - -`cri` is a [containerd](https://containerd.io/) plugin implementation of Kubernetes [container runtime interface (CRI)](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/cri/runtime/v1alpha2/api.proto). - -With it, you could run Kubernetes using containerd as the container runtime. -![cri](./docs/cri.png) -## Current Status -`cri` is a native plugin of containerd 1.1 and above. It is built into containerd and enabled by default. - -`cri` is in GA: -* It is feature complete. -* It (the GA version) works with Kubernetes 1.10 and above. -* It has passed all [CRI validation tests](https://github.com/kubernetes/community/blob/master/contributors/devel/cri-validation.md). -* It has passed all [node e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-node-tests.md). -* It has passed all [e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md). - -See [test dashboard](https://k8s-testgrid.appspot.com/sig-node-containerd) -## Support Metrics -| CRI-Containerd Version | Containerd Version | Kubernetes Version | CRI Version | -|:----------------------:|:------------------:|:------------------:|:-----------:| -| v1.0.0-alpha.x | | 1.7, 1.8 | v1alpha1 | -| v1.0.0-beta.x | | 1.9 | v1alpha1 | -| End-Of-Life | v1.1 | 1.10+ | v1alpha2 | -| | HEAD | 1.10+ | v1alpha2 | - -## Production Quality Cluster on GCE -For a production quality cluster on GCE brought up with `kube-up.sh` refer [here](docs/kube-up.md). -## Installing with Ansible and Kubeadm -For a multi node cluster installer and bring up steps using ansible and kubeadm refer [here](contrib/ansible/README.md). -## Custom Installation -For non ansible users, you can download the `cri-containerd` release tarball and deploy -kubernetes cluster using kubeadm as described [here](docs/installation.md). -## Getting Started for Developers -### Binary Dependencies and Specifications -The current release of the `cri` plugin has the following dependencies: -* [containerd](https://github.com/containerd/containerd) -* [runc](https://github.com/opencontainers/runc) -* [CNI](https://github.com/containernetworking/cni) - -See [versions](./vendor.conf) of these dependencies `cri` is tested with. - -As containerd and runc move to their respective general availability releases, -we will do our best to rebase/retest `cri` with these releases on a -weekly/monthly basis. Similarly, given that `cri` uses the Open -Container Initiative (OCI) [image](https://github.com/opencontainers/image-spec) -and [runtime](https://github.com/opencontainers/runtime-spec) specifications, we -will also do our best to update `cri` to the latest releases of these -specifications as appropriate. -### Install Dependencies -1. Install development libraries: -* **libseccomp development library.** Required by `cri` and runc seccomp support. `libseccomp-dev` (Ubuntu, Debian) / `libseccomp-devel` -(Fedora, CentOS, RHEL). On releases of Ubuntu <=Trusty and Debian <=jessie a -backport version of `libseccomp-dev` is required. See [travis.yml](.travis.yml) for an example on trusty. -* **btrfs development library.** Required by containerd btrfs support. `btrfs-tools`(Ubuntu, Debian) / `btrfs-progs-devel`(Fedora, CentOS, RHEL) -2. Install **`socat`** (required by portforward). -2. Install and setup a go 1.10 development environment. -3. Make a local clone of this repository. -4. Install binary dependencies by running the following command from your cloned `cri/` project directory: -```bash -# Note: install.deps installs the above mentioned runc, containerd, and CNI -# binary dependencies. install.deps is only provided for general use and ease of -# testing. To customize `runc` and `containerd` build tags and/or to configure -# `cni`, please follow instructions in their documents. -make install.deps -``` -### Build and Install `cri` -To build and install a version of containerd with the `cri` plugin, enter the -following commands from your `cri` project directory: -```bash -make -sudo make install -``` -*NOTE: The version of containerd built and installed from the `Makefile` is only for -testing purposes. The version tag carries the suffix "-TEST".* -#### Build Tags -`cri` supports optional build tags for compiling support of various features. -To add build tags to the make option the `BUILD_TAGS` variable must be set. - -```bash -make BUILD_TAGS='seccomp apparmor' -``` - -| Build Tag | Feature | Dependency | -|-----------|------------------------------------|---------------------------------| -| seccomp | syscall filtering | libseccomp development library | -| selinux | selinux process and mount labeling | | -| apparmor | apparmor profile support | | -### Validate Your `cri` Setup -A Kubernetes incubator project called [cri-tools](https://github.com/kubernetes-sigs/cri-tools) -includes programs for exercising CRI implementations such as the `cri` plugin. -More importantly, cri-tools includes the program `critest` which is used for running -[CRI Validation Testing](https://github.com/kubernetes/community/blob/master/contributors/devel/cri-validation.md). - -Run the CRI Validation test to validate your installation of `containerd` with `cri` built in: -```bash -make test-cri -``` -### Running a Kubernetes local cluster -If you already have a working development environment for supported Kubernetes -version, you can try `cri` in a local cluster: - -1. Start the version of `containerd` with `cri` plugin that you built and installed -above as root in a first terminal: -```bash -sudo containerd -``` -2. From the Kubernetes project directory startup a local cluster using `containerd`: -```bash -CONTAINER_RUNTIME=remote CONTAINER_RUNTIME_ENDPOINT='unix:///run/containerd/containerd.sock' ./hack/local-up-cluster.sh -``` -### Test -See [here](./docs/testing.md) for information about test. -## Using crictl -See [here](./docs/crictl.md) for information about using `crictl` to debug -pods, containers, and images. -## Configurations -See [here](./docs/config.md) for information about how to configure cri plugins -and [here](https://github.com/containerd/containerd/blob/master/docs/man/containerd-config.1.md) -for information about how to configure containerd -## Documentation -See [here](./docs) for additional documentation. -## Contributing -Interested in contributing? Check out the [documentation](./CONTRIBUTING.md). - -## Communication -This project was originally established in April of 2017 in the Kubernetes -Incubator program. After reaching the Beta stage, In January of 2018, the -project was merged into [containerd](https://github.com/containerd/containerd). - -For async communication and long running discussions please use issues and pull -requests on this github repo. This will be the best place to discuss design and -implementation. - -For sync communication we have a community slack with a #containerd channel that -everyone is welcome to join and chat about development. - -**Slack:** https://dockr.ly/community - -## Other Communications -As this project is tightly coupled to CRI and CRI-Tools and they are Kubernetes -projects, some of our project communications take place in the Kubernetes' SIG: -`sig-node.` - -For more information about `sig-node`, `CRI`, and the `CRI-Tools` projects: -* [sig-node community site](https://github.com/kubernetes/community/tree/master/sig-node) -* Slack: `#sig-node` channel in Kubernetes (kubernetes.slack.com) -* Mailing List: https://groups.google.com/forum/#!forum/kubernetes-sig-node - -### Reporting Security Issues - -__If you are reporting a security issue, please reach out discreetly at security@containerd.io__. - -## Licenses -The containerd codebase is released under the [Apache 2.0 license](https://github.com/containerd/containerd/blob/master/LICENSE.code). -The README.md file, and files in the "docs" folder are licensed under the -Creative Commons Attribution 4.0 International License under the terms and -conditions set forth in the file "[LICENSE.docs](https://github.com/containerd/containerd/blob/master/LICENSE.docs)". You may obtain a duplicate -copy of the same license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/. - -## Code of Conduct -This project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). diff -Nru containerd-1.2.6/vendor/github.com/containerd/cri/vendor.conf containerd-1.5.9/vendor/github.com/containerd/cri/vendor.conf --- containerd-1.2.6/vendor/github.com/containerd/cri/vendor.conf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/cri/vendor.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 -github.com/blang/semver v3.1.0 -github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 -github.com/containerd/cgroups dbea6f2bd41658b84b00417ceefa416b979cbf10 -github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23 -github.com/containerd/containerd v1.2.5 -github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4 -github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c -github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90 -github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3 -github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a -github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40 -github.com/containernetworking/cni v0.6.0 -github.com/containernetworking/plugins v0.7.5 -github.com/coreos/go-systemd v14 -github.com/davecgh/go-spew v1.1.0 -github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580 -github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00 -github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 -github.com/docker/go-metrics 4ea375f7759c82740c893fc030bc37088d2ec098 -github.com/docker/go-units v0.3.1 -github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528 -github.com/emicklei/go-restful v2.2.1 -github.com/ghodss/yaml v1.0.0 -github.com/godbus/dbus v3 -github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef -github.com/gogo/protobuf v1.0.0 -github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed -github.com/golang/protobuf v1.1.0 -github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c -github.com/grpc-ecosystem/go-grpc-prometheus v1.1 -github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 -github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f -github.com/json-iterator/go 1.1.5 -github.com/matttproud/golang_protobuf_extensions v1.0.0 -github.com/Microsoft/go-winio v0.4.11 -github.com/Microsoft/hcsshim v0.8.1 -github.com/modern-go/concurrent 1.0.3 -github.com/modern-go/reflect2 1.0.1 -github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7 -github.com/opencontainers/image-spec v1.0.1 -github.com/opencontainers/runc 2b18fe1d885ee5083ef9f0838fee39b62d653e30 -github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 -github.com/opencontainers/runtime-tools v0.6.0 -github.com/opencontainers/selinux v1.2.1 -github.com/pkg/errors v0.8.0 -github.com/pmezard/go-difflib v1.0.0 -github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823 -github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c -github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563 -github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd -github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 -github.com/sirupsen/logrus v1.0.0 -github.com/stretchr/testify v1.1.4 -github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16 -github.com/tchap/go-patricia v2.2.6 -github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c -github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6 -github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b -github.com/xeipuuv/gojsonschema 1d523034197ff1f222f6429836dd36a2457a1874 -go.etcd.io/bbolt v1.3.1-etcd.8 -golang.org/x/crypto 49796115aa4b964c318aad4f3084fdb41e9aa067 -golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac -golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4 -golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c -golang.org/x/sys 41f3e6584952bb034a481797859f6ab34b6803bd https://github.com/golang/sys -golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 -golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631 -google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 -google.golang.org/grpc v1.12.0 -gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 -gopkg.in/yaml.v2 53feefa2559fb8dfa8d81baad31be332c97d6c77 -k8s.io/api kubernetes-1.12.0 -k8s.io/apimachinery kubernetes-1.12.0 -k8s.io/apiserver kubernetes-1.12.0 -k8s.io/client-go kubernetes-1.12.0 -k8s.io/kubernetes v1.12.0 -k8s.io/utils cd34563cd63c2bd7c6fe88a73c4dcf34ed8a67cb diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/errors.go containerd-1.5.9/vendor/github.com/containerd/fifo/errors.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/errors.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fifo + +import "errors" + +var ( + ErrClosed = errors.New("fifo closed") + ErrCtrlClosed = errors.New("control of closed fifo") + ErrRdFrmWRONLY = errors.New("reading from write-only fifo") + ErrReadClosed = errors.New("reading from a closed fifo") + ErrWrToRDONLY = errors.New("writing to read-only fifo") + ErrWriteClosed = errors.New("writing to a closed fifo") +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/fifo.go containerd-1.5.9/vendor/github.com/containerd/fifo/fifo.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/fifo.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/fifo.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,5 @@ +// +build !windows + /* Copyright The containerd Authors. @@ -17,6 +19,7 @@ package fifo import ( + "context" "io" "os" "runtime" @@ -24,7 +27,7 @@ "syscall" "github.com/pkg/errors" - "golang.org/x/net/context" + "golang.org/x/sys/unix" ) type fifo struct { @@ -41,6 +44,21 @@ var leakCheckWg *sync.WaitGroup +// OpenFifoDup2 is same as OpenFifo, but additionally creates a copy of the FIFO file descriptor with dup2 syscall. +func OpenFifoDup2(ctx context.Context, fn string, flag int, perm os.FileMode, fd int) (io.ReadWriteCloser, error) { + f, err := openFifo(ctx, fn, flag, perm) + if err != nil { + return nil, errors.Wrap(err, "fifo error") + } + + if err := unix.Dup2(int(f.file.Fd()), fd); err != nil { + _ = f.Close() + return nil, errors.Wrap(err, "dup2 error") + } + + return f, nil +} + // OpenFifo opens a fifo. Returns io.ReadWriteCloser. // Context can be used to cancel this function until open(2) has not returned. // Accepted flags: @@ -52,9 +70,13 @@ // fifo isn't open. read/write will be connected after the actual fifo is // open or after fifo is closed. func OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) { + return openFifo(ctx, fn, flag, perm) +} + +func openFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (*fifo, error) { if _, err := os.Stat(fn); err != nil { if os.IsNotExist(err) && flag&syscall.O_CREAT != 0 { - if err := mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) { + if err := syscall.Mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) { return nil, errors.Wrapf(err, "error creating fifo %v", fn) } } else { @@ -147,7 +169,7 @@ // Read from a fifo to a byte array. func (f *fifo) Read(b []byte) (int, error) { if f.flag&syscall.O_WRONLY > 0 { - return 0, errors.New("reading from write-only fifo") + return 0, ErrRdFrmWRONLY } select { case <-f.opened: @@ -158,14 +180,14 @@ case <-f.opened: return f.file.Read(b) case <-f.closed: - return 0, errors.New("reading from a closed fifo") + return 0, ErrReadClosed } } // Write from byte array to a fifo. func (f *fifo) Write(b []byte) (int, error) { if f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 { - return 0, errors.New("writing to read-only fifo") + return 0, ErrWrToRDONLY } select { case <-f.opened: @@ -176,7 +198,7 @@ case <-f.opened: return f.file.Write(b) case <-f.closed: - return 0, errors.New("writing to a closed fifo") + return 0, ErrWriteClosed } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/.gitattributes containerd-1.5.9/vendor/github.com/containerd/fifo/.gitattributes --- containerd-1.2.6/vendor/github.com/containerd/fifo/.gitattributes 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/.gitattributes 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +*.go text eol=lf diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/.gitignore containerd-1.5.9/vendor/github.com/containerd/fifo/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/fifo/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +coverage.txt +vendor/ diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/fifo/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/fifo/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,20 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +run: + timeout: 3m + skip-dirs: + - vendor diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/go.mod containerd-1.5.9/vendor/github.com/containerd/fifo/go.mod --- containerd-1.2.6/vendor/github.com/containerd/fifo/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,9 @@ +module github.com/containerd/fifo + +go 1.13 + +require ( + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.6.1 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/go.sum containerd-1.5.9/vendor/github.com/containerd/fifo/go.sum --- containerd-1.2.6/vendor/github.com/containerd/fifo/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/handle_linux.go containerd-1.5.9/vendor/github.com/containerd/fifo/handle_linux.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/handle_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/handle_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -27,6 +27,7 @@ "github.com/pkg/errors" ) +//nolint:golint const O_PATH = 010000000 type handle struct { @@ -56,9 +57,10 @@ h := &handle{ f: f, name: fn, - dev: uint64(stat.Dev), - ino: stat.Ino, - fd: fd, + //nolint:unconvert + dev: uint64(stat.Dev), + ino: stat.Ino, + fd: fd, } // check /proc just in case @@ -83,6 +85,7 @@ if err := syscall.Stat(h.procPath(), &stat); err != nil { return "", errors.Wrapf(err, "path %v could not be statted", h.procPath()) } + //nolint:unconvert if uint64(stat.Dev) != h.dev || stat.Ino != h.ino { return "", errors.Errorf("failed to verify handle %v/%v %v/%v", stat.Dev, h.dev, stat.Ino, h.ino) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/handle_nolinux.go containerd-1.5.9/vendor/github.com/containerd/fifo/handle_nolinux.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/handle_nolinux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/handle_nolinux.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux,!windows /* Copyright The containerd Authors. @@ -38,8 +38,8 @@ h := &handle{ fn: fn, - dev: uint64(stat.Dev), - ino: uint64(stat.Ino), + dev: uint64(stat.Dev), //nolint: unconvert + ino: uint64(stat.Ino), //nolint: unconvert } return h, nil @@ -50,7 +50,7 @@ if err := syscall.Stat(h.fn, &stat); err != nil { return "", errors.Wrapf(err, "path %v could not be statted", h.fn) } - if uint64(stat.Dev) != h.dev || uint64(stat.Ino) != h.ino { + if uint64(stat.Dev) != h.dev || uint64(stat.Ino) != h.ino { //nolint: unconvert return "", errors.Errorf("failed to verify handle %v/%v %v/%v for %v", stat.Dev, h.dev, stat.Ino, h.ino, h.fn) } return h.fn, nil diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/Makefile containerd-1.5.9/vendor/github.com/containerd/fifo/Makefile --- containerd-1.2.6/vendor/github.com/containerd/fifo/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,24 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.PHONY: check test deps + +test: deps + go test -v -race ./... + +deps: + go mod vendor + +check: + GOGC=75 golangci-lint run diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/mkfifo_nosolaris.go containerd-1.5.9/vendor/github.com/containerd/fifo/mkfifo_nosolaris.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/mkfifo_nosolaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/mkfifo_nosolaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -// +build !solaris - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package fifo - -import "syscall" - -func mkfifo(path string, mode uint32) (err error) { - return syscall.Mkfifo(path, mode) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/mkfifo_solaris.go containerd-1.5.9/vendor/github.com/containerd/fifo/mkfifo_solaris.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/mkfifo_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/mkfifo_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -// +build solaris - -/* - Copyright The containerd Authors. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package fifo - -import ( - "golang.org/x/sys/unix" -) - -func mkfifo(path string, mode uint32) (err error) { - return unix.Mkfifo(path, mode) -} diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/raw.go containerd-1.5.9/vendor/github.com/containerd/fifo/raw.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/raw.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/raw.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,114 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fifo + +import ( + "syscall" +) + +// SyscallConn provides raw access to the fifo's underlying filedescrptor. +// See syscall.Conn for guarantees provided by this interface. +func (f *fifo) SyscallConn() (syscall.RawConn, error) { + // deterministic check for closed + select { + case <-f.closed: + return nil, ErrClosed + default: + } + + select { + case <-f.closed: + return nil, ErrClosed + case <-f.opened: + return f.file.SyscallConn() + default: + } + + // Not opened and not closed, this means open is non-blocking AND it's not open yet + // Use rawConn to deal with non-blocking open. + rc := &rawConn{f: f, ready: make(chan struct{})} + go func() { + select { + case <-f.closed: + return + case <-f.opened: + rc.raw, rc.err = f.file.SyscallConn() + close(rc.ready) + } + }() + + return rc, nil +} + +type rawConn struct { + f *fifo + ready chan struct{} + raw syscall.RawConn + err error +} + +func (r *rawConn) Control(f func(fd uintptr)) error { + select { + case <-r.f.closed: + return ErrCtrlClosed + case <-r.ready: + } + + if r.err != nil { + return r.err + } + + return r.raw.Control(f) +} + +func (r *rawConn) Read(f func(fd uintptr) (done bool)) error { + if r.f.flag&syscall.O_WRONLY > 0 { + return ErrRdFrmWRONLY + } + + select { + case <-r.f.closed: + return ErrReadClosed + case <-r.ready: + } + + if r.err != nil { + return r.err + } + + return r.raw.Read(f) +} + +func (r *rawConn) Write(f func(fd uintptr) (done bool)) error { + if r.f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 { + return ErrWrToRDONLY + } + + select { + case <-r.f.closed: + return ErrWriteClosed + case <-r.ready: + } + + if r.err != nil { + return r.err + } + + return r.raw.Write(f) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/readme.md containerd-1.5.9/vendor/github.com/containerd/fifo/readme.md --- containerd-1.2.6/vendor/github.com/containerd/fifo/readme.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/readme.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,9 @@ ### fifo -[![Build Status](https://travis-ci.org/containerd/fifo.svg?branch=master)](https://travis-ci.org/containerd/fifo) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/fifo)](https://pkg.go.dev/github.com/containerd/fifo) +[![Build Status](https://github.com/containerd/fifo/workflows/CI/badge.svg)](https://github.com/containerd/fifo/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/containerd/fifo/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/fifo) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/fifo)](https://goreportcard.com/report/github.com/containerd/fifo) Go package for handling fifos in a sane way. @@ -30,3 +33,14 @@ // before open(2) has returned and fifo was never opened. func (f *fifo) Close() error ``` + +## Project details + +The fifo is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/fifo/utils.go containerd-1.5.9/vendor/github.com/containerd/fifo/utils.go --- containerd-1.2.6/vendor/github.com/containerd/fifo/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/fifo/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,35 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package fifo + +import "os" + +// IsFifo checks if a file is a (named pipe) fifo +// if the file does not exist then it returns false +func IsFifo(path string) (bool, error) { + stat, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + if stat.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { + return true, nil + } + return false, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/cni.go containerd-1.5.9/vendor/github.com/containerd/go-cni/cni.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/cni.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/cni.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,24 +17,55 @@ package cni import ( + "context" "fmt" "strings" "sync" cnilibrary "github.com/containernetworking/cni/libcni" + "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" "github.com/pkg/errors" ) type CNI interface { // Setup setup the network for the namespace - Setup(id string, path string, opts ...NamespaceOpts) (*CNIResult, error) + Setup(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error) // Remove tears down the network of the namespace. - Remove(id string, path string, opts ...NamespaceOpts) error + Remove(ctx context.Context, id string, path string, opts ...NamespaceOpts) error // Load loads the cni network config - Load(opts ...CNIOpt) error + Load(opts ...Opt) error // Status checks the status of the cni initialization Status() error + // GetConfig returns a copy of the CNI plugin configurations as parsed by CNI + GetConfig() *ConfigResult +} + +type ConfigResult struct { + PluginDirs []string + PluginConfDir string + PluginMaxConfNum int + Prefix string + Networks []*ConfNetwork +} + +type ConfNetwork struct { + Config *NetworkConfList + IFName string +} + +// NetworkConfList is a source bytes to string version of cnilibrary.NetworkConfigList +type NetworkConfList struct { + Name string + CNIVersion string + Plugins []*NetworkConf + Source string +} + +// NetworkConf is a source bytes to string conversion of cnilibrary.NetworkConfig +type NetworkConf struct { + Network *types.NetConf + Source string } type libcni struct { @@ -49,9 +80,10 @@ func defaultCNIConfig() *libcni { return &libcni{ config: config{ - pluginDirs: []string{DefaultCNIDir}, - pluginConfDir: DefaultNetDir, - prefix: DefaultPrefix, + pluginDirs: []string{DefaultCNIDir}, + pluginConfDir: DefaultNetDir, + pluginMaxConfNum: DefaultMaxConfNum, + prefix: DefaultPrefix, }, cniConfig: &cnilibrary.CNIConfig{ Path: []string{DefaultCNIDir}, @@ -60,7 +92,8 @@ } } -func New(config ...CNIOpt) (CNI, error) { +// New creates a new libcni instance. +func New(config ...Opt) (CNI, error) { cni := defaultCNIConfig() var err error for _, c := range config { @@ -71,7 +104,8 @@ return cni, nil } -func (c *libcni) Load(opts ...CNIOpt) error { +// Load loads the latest config from cni config files. +func (c *libcni) Load(opts ...Opt) error { var err error c.Lock() defer c.Unlock() @@ -87,47 +121,63 @@ return nil } +// Status returns the status of CNI initialization. func (c *libcni) Status() error { c.RLock() defer c.RUnlock() - return c.status() + if len(c.networks) < c.networkCount { + return ErrCNINotInitialized + } + return nil } -// Setup setups the network in the namespace -func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResult, error) { +// Networks returns all the configured networks. +// NOTE: Caller MUST NOT modify anything in the returned array. +func (c *libcni) Networks() []*Network { c.RLock() defer c.RUnlock() - if err := c.status(); err != nil { + return append([]*Network{}, c.networks...) +} + +// Setup setups the network in the namespace and returns a Result +func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error) { + if err := c.Status(); err != nil { return nil, err } ns, err := newNamespace(id, path, opts...) if err != nil { return nil, err } + result, err := c.attachNetworks(ctx, ns) + if err != nil { + return nil, err + } + return c.createResult(result) +} + +func (c *libcni) attachNetworks(ctx context.Context, ns *Namespace) ([]*current.Result, error) { var results []*current.Result - for _, network := range c.networks { - r, err := network.Attach(ns) + for _, network := range c.Networks() { + r, err := network.Attach(ctx, ns) if err != nil { return nil, err } results = append(results, r) } - return c.GetCNIResultFromResults(results) + return results, nil } // Remove removes the network config from the namespace -func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error { - c.RLock() - defer c.RUnlock() - if err := c.status(); err != nil { +func (c *libcni) Remove(ctx context.Context, id string, path string, opts ...NamespaceOpts) error { + if err := c.Status(); err != nil { return err } ns, err := newNamespace(id, path, opts...) if err != nil { return err } - for _, network := range c.networks { - if err := network.Remove(ns); err != nil { + for _, network := range c.Networks() { + if err := network.Remove(ctx, ns); err != nil { // Based on CNI spec v0.7.0, empty network namespace is allowed to // do best effort cleanup. However, it is not handled consistently // right now: @@ -143,13 +193,36 @@ return nil } -func (c *libcni) reset() { - c.networks = nil +// GetConfig returns a copy of the CNI plugin configurations as parsed by CNI +func (c *libcni) GetConfig() *ConfigResult { + c.RLock() + defer c.RUnlock() + r := &ConfigResult{ + PluginDirs: c.config.pluginDirs, + PluginConfDir: c.config.pluginConfDir, + PluginMaxConfNum: c.config.pluginMaxConfNum, + Prefix: c.config.prefix, + } + for _, network := range c.networks { + conf := &NetworkConfList{ + Name: network.config.Name, + CNIVersion: network.config.CNIVersion, + Source: string(network.config.Bytes), + } + for _, plugin := range network.config.Plugins { + conf.Plugins = append(conf.Plugins, &NetworkConf{ + Network: plugin.Network, + Source: string(plugin.Bytes), + }) + } + r.Networks = append(r.Networks, &ConfNetwork{ + Config: conf, + IFName: network.ifName, + }) + } + return r } -func (c *libcni) status() error { - if len(c.networks) < c.networkCount { - return ErrCNINotInitialized - } - return nil +func (c *libcni) reset() { + c.networks = nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/deprecated.go containerd-1.5.9/vendor/github.com/containerd/go-cni/deprecated.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/deprecated.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/deprecated.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cni + +import "github.com/containernetworking/cni/pkg/types/current" + +// Deprecated: use cni.Opt instead +type CNIOpt = Opt //nolint: golint // type name will be used as cni.CNIOpt by other packages, and that stutters + +// Deprecated: use cni.Result instead +type CNIResult = Result //nolint: golint // type name will be used as cni.CNIResult by other packages, and that stutters + +// GetCNIResultFromResults creates a Result from the given slice of current.Result, +// adding structured data containing the interface configuration for each of the +// interfaces created in the namespace. It returns an error if validation of +// results fails, or if a network could not be found. +// Deprecated: do not use +func (c *libcni) GetCNIResultFromResults(results []*current.Result) (*Result, error) { + return c.createResult(results) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/errors.go containerd-1.5.9/vendor/github.com/containerd/go-cni/errors.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/errors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/errors.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,3 +1,19 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package cni import ( @@ -13,27 +29,27 @@ ErrLoad = errors.New("failed to load cni config") ) -// IsCNINotInitialized returns true if the error is due cni config not being intialized +// IsCNINotInitialized returns true if the error is due to cni config not being initialized func IsCNINotInitialized(err error) bool { - return errors.Cause(err) == ErrCNINotInitialized + return errors.Is(err, ErrCNINotInitialized) } // IsInvalidConfig returns true if the error is invalid cni config func IsInvalidConfig(err error) bool { - return errors.Cause(err) == ErrInvalidConfig + return errors.Is(err, ErrInvalidConfig) } // IsNotFound returns true if the error is due to a missing config or result func IsNotFound(err error) bool { - return errors.Cause(err) == ErrNotFound + return errors.Is(err, ErrNotFound) } // IsReadFailure return true if the error is a config read failure func IsReadFailure(err error) bool { - return errors.Cause(err) == ErrRead + return errors.Is(err, ErrRead) } // IsInvalidResult return true if the error is due to invalid cni result func IsInvalidResult(err error) bool { - return errors.Cause(err) == ErrInvalidResult + return errors.Is(err, ErrInvalidResult) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/go-cni/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/go-cni/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,23 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +# FIXME: re-enable after fixing GoDoc in this repository +#issues: +# include: +# - EXC0002 + +run: + timeout: 2m diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/go.mod containerd-1.5.9/vendor/github.com/containerd/go-cni/go.mod --- containerd-1.2.6/vendor/github.com/containerd/go-cni/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +module github.com/containerd/go-cni + +require ( + github.com/containernetworking/cni v0.8.0 + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/onsi/ginkgo v1.10.3 // indirect + github.com/onsi/gomega v1.7.1 // indirect + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.6.1 +) + +go 1.13 diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/go.sum containerd-1.5.9/vendor/github.com/containerd/go-cni/go.sum --- containerd-1.2.6/vendor/github.com/containerd/go-cni/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,42 @@ +github.com/containernetworking/cni v0.8.0 h1:BT9lpgGoH4jw3lFC7Odz2prU5ruiYKcgAjMCbgybcKI= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/helper.go containerd-1.5.9/vendor/github.com/containerd/go-cni/helper.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/helper.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/helper.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,10 +24,10 @@ func validateInterfaceConfig(ipConf *current.IPConfig, ifs int) error { if ipConf == nil { - return fmt.Errorf("invalid IP configuration") + return fmt.Errorf("invalid IP configuration (nil)") } if ipConf.Interface != nil && *ipConf.Interface > ifs { - return fmt.Errorf("invalid IP configuration with invalid interface %d", *ipConf.Interface) + return fmt.Errorf("invalid IP configuration (interface number %d is > number of interfaces %d)", *ipConf.Interface, ifs) } return nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/namespace.go containerd-1.5.9/vendor/github.com/containerd/go-cni/namespace.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/namespace.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/namespace.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,8 @@ package cni import ( + "context" + cnilibrary "github.com/containernetworking/cni/libcni" "github.com/containernetworking/cni/pkg/types/current" ) @@ -27,16 +29,16 @@ ifName string } -func (n *Network) Attach(ns *Namespace) (*current.Result, error) { - r, err := n.cni.AddNetworkList(n.config, ns.config(n.ifName)) +func (n *Network) Attach(ctx context.Context, ns *Namespace) (*current.Result, error) { + r, err := n.cni.AddNetworkList(ctx, n.config, ns.config(n.ifName)) if err != nil { return nil, err } return current.NewResultFromResult(r) } -func (n *Network) Remove(ns *Namespace) error { - return n.cni.DelNetworkList(n.config, ns.config(n.ifName)) +func (n *Network) Remove(ctx context.Context, ns *Namespace) error { + return n.cni.DelNetworkList(ctx, n.config, ns.config(n.ifName)) } type Namespace struct { diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/namespace_opts.go containerd-1.5.9/vendor/github.com/containerd/go-cni/namespace_opts.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/namespace_opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/namespace_opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -33,6 +33,23 @@ } } +// WithCapabilityBandWitdh adds support for traffic shaping: +// https://github.com/heptio/cni-plugins/tree/master/plugins/meta/bandwidth +func WithCapabilityBandWidth(bandWidth BandWidth) NamespaceOpts { + return func(c *Namespace) error { + c.capabilityArgs["bandwidth"] = bandWidth + return nil + } +} + +// WithCapabilityDNS adds support for dns +func WithCapabilityDNS(dns DNS) NamespaceOpts { + return func(c *Namespace) error { + c.capabilityArgs["dns"] = dns + return nil + } +} + func WithCapability(name string, capability interface{}) NamespaceOpts { return func(c *Namespace) error { c.capabilityArgs[name] = capability diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/opts.go containerd-1.5.9/vendor/github.com/containerd/go-cni/opts.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/opts.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/opts.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,11 +24,12 @@ "github.com/pkg/errors" ) -type CNIOpt func(c *libcni) error +// Opt sets options for a CNI instance +type Opt func(c *libcni) error // WithInterfacePrefix sets the prefix for network interfaces // e.g. eth or wlan -func WithInterfacePrefix(prefix string) CNIOpt { +func WithInterfacePrefix(prefix string) Opt { return func(c *libcni) error { c.prefix = prefix return nil @@ -37,7 +38,7 @@ // WithPluginDir can be used to set the locations of // the cni plugin binaries -func WithPluginDir(dirs []string) CNIOpt { +func WithPluginDir(dirs []string) Opt { return func(c *libcni) error { c.pluginDirs = dirs c.cniConfig = &cnilibrary.CNIConfig{Path: dirs} @@ -47,17 +48,26 @@ // WithPluginConfDir can be used to configure the // cni configuration directory. -func WithPluginConfDir(dir string) CNIOpt { +func WithPluginConfDir(dir string) Opt { return func(c *libcni) error { c.pluginConfDir = dir return nil } } +// WithPluginMaxConfNum can be used to configure the +// max cni plugin config file num. +func WithPluginMaxConfNum(max int) Opt { + return func(c *libcni) error { + c.pluginMaxConfNum = max + return nil + } +} + // WithMinNetworkCount can be used to configure the -// minimum networks to be configured and initalized +// minimum networks to be configured and initialized // for the status to report success. By default its 1. -func WithMinNetworkCount(count int) CNIOpt { +func WithMinNetworkCount(count int) Opt { return func(c *libcni) error { c.networkCount = count return nil @@ -85,7 +95,13 @@ // WithConf can be used to load config directly // from byte. -func WithConf(bytes []byte) CNIOpt { +func WithConf(bytes []byte) Opt { + return WithConfIndex(bytes, 0) +} + +// WithConfIndex can be used to load config directly +// from byte and set the interface name's index. +func WithConfIndex(bytes []byte, index int) Opt { return func(c *libcni) error { conf, err := cnilibrary.ConfFromBytes(bytes) if err != nil { @@ -98,7 +114,7 @@ c.networks = append(c.networks, &Network{ cni: c.cniConfig, config: confList, - ifName: getIfName(c.prefix, 0), + ifName: getIfName(c.prefix, index), }) return nil } @@ -107,7 +123,7 @@ // WithConfFile can be used to load network config // from an .conf file. Supported with absolute fileName // with path only. -func WithConfFile(fileName string) CNIOpt { +func WithConfFile(fileName string) Opt { return func(c *libcni) error { conf, err := cnilibrary.ConfFromFile(fileName) if err != nil { @@ -127,10 +143,28 @@ } } +// WithConfListBytes can be used to load network config list directly +// from byte +func WithConfListBytes(bytes []byte) Opt { + return func(c *libcni) error { + confList, err := cnilibrary.ConfListFromBytes(bytes) + if err != nil { + return err + } + i := len(c.networks) + c.networks = append(c.networks, &Network{ + cni: c.cniConfig, + config: confList, + ifName: getIfName(c.prefix, i), + }) + return nil + } +} + // WithConfListFile can be used to load network config // from an .conflist file. Supported with absolute fileName // with path only. -func WithConfListFile(fileName string) CNIOpt { +func WithConfListFile(fileName string) Opt { return func(c *libcni) error { confList, err := cnilibrary.ConfListFromFile(fileName) if err != nil { @@ -153,7 +187,7 @@ // the convention chosen is - the first network configuration in the sorted // list of network conf files as the default network. func WithDefaultConf(c *libcni) error { - return loadFromConfDir(c, 1) + return loadFromConfDir(c, c.pluginMaxConfNum) } // WithAllConf can be used to detect all network config @@ -205,11 +239,11 @@ confList, err = cnilibrary.ConfListFromConf(conf) if err != nil { - return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to list: %v", confFile, err) + return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to CNI config list: %v", confFile, err) } } if len(confList.Plugins) == 0 { - return errors.Wrapf(ErrInvalidConfig, "CNI config list %s has no networks, skipping", confFile) + return errors.Wrapf(ErrInvalidConfig, "CNI config list in config file %s has no networks, skipping", confFile) } networks = append(networks, &Network{ diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/README.md containerd-1.5.9/vendor/github.com/containerd/go-cni/README.md --- containerd-1.2.6/vendor/github.com/containerd/go-cni/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,7 +1,10 @@ -[![Build Status](https://travis-ci.org/containerd/go-cni.svg?branch=master)](https://travis-ci.org/containerd/go-cni) - # go-cni +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/go-cni)](https://pkg.go.dev/github.com/containerd/go-cni) +[![Build Status](https://github.com/containerd/go-cni/workflows/CI/badge.svg)](https://github.com/containerd/go-cni/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/containerd/go-cni/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/go-cni) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/go-cni)](https://goreportcard.com/report/github.com/containerd/go-cni) + A generic CNI library to provide APIs for CNI plugin interactions. The library provides APIs to: - Load CNI network config from different sources @@ -12,38 +15,81 @@ go-cni aims to support plugins that implement [Container Network Interface](https://github.com/containernetworking/cni) ## Usage -``` +```go +package main + +import ( + "context" + "fmt" + "log" + + gocni "github.com/containerd/go-cni" +) + func main() { - id := "123456" - netns := "/proc/9999/ns/net" + id := "example" + netns := "/var/run/netns/example-ns-1" + + // CNI allows multiple CNI configurations and the network interface + // will be named by eth0, eth1, ..., ethN. + ifPrefixName := "eth" defaultIfName := "eth0" - // Initialize library - l = gocni.New(gocni.WithMinNetworkCount(2), - gocni.WithPluginConfDir("/etc/mycni/net.d"), - gocni.WithPluginDir([]string{"/opt/mycni/bin", "/opt/cni/bin"}), - gocni.WithDefaultIfName(defaultIfName)) - + + // Initializes library + l, err := gocni.New( + // one for loopback network interface + gocni.WithMinNetworkCount(2), + gocni.WithPluginConfDir("/etc/cni/net.d"), + gocni.WithPluginDir([]string{"/opt/cni/bin"}), + // Sets the prefix for network interfaces, eth by default + gocni.WithInterfacePrefix(ifPrefixName)) + if err != nil { + log.Fatalf("failed to initialize cni library: %v", err) + } + // Load the cni configuration - err:= l.Load(gocni.WithLoNetwork,gocni.WithDefaultConf) - if err != nil{ - log.Errorf("failed to load cni configuration: %v", err) - return + if err := l.Load(gocni.WithLoNetwork, gocni.WithDefaultConf); err != nil { + log.Fatalf("failed to load cni configuration: %v", err) } - + // Setup network for namespace. labels := map[string]string{ "K8S_POD_NAMESPACE": "namespace1", "K8S_POD_NAME": "pod1", "K8S_POD_INFRA_CONTAINER_ID": id, + // Plugin tolerates all Args embedded by unknown labels, like + // K8S_POD_NAMESPACE/NAME/INFRA_CONTAINER_ID... + "IgnoreUnknown": "1", } - result, err := l.Setup(id, netns, gocni.WithLabels(labels)) + + ctx := context.Background() + + // Teardown network + defer func() { + if err := l.Remove(ctx, id, netns, gocni.WithLabels(labels)); err != nil { + log.Fatalf("failed to teardown network: %v", err) + } + }() + + // Setup network + result, err := l.Setup(ctx, id, netns, gocni.WithLabels(labels)) if err != nil { - log.Errorf("failed to setup network for namespace %q: %v",id, err) - return + log.Fatalf("failed to setup network for namespace: %v", err) } - + // Get IP of the default interface IP := result.Interfaces[defaultIfName].IPConfigs[0].IP.String() fmt.Printf("IP of the default interface %s:%s", defaultIfName, IP) } ``` + +## Project details + +The go-cni is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/result.go containerd-1.5.9/vendor/github.com/containerd/go-cni/result.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/result.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/result.go 2022-01-05 17:30:58.000000000 +0000 @@ -29,7 +29,17 @@ Gateway net.IP } -type CNIResult struct { +// Result contains the network information returned by CNI.Setup +// +// a) Interfaces list. Depending on the plugin, this can include the sandbox +// (eg, container or hypervisor) interface name and/or the host interface +// name, the hardware addresses of each interface, and details about the +// sandbox (if any) the interface is in. +// b) IP configuration assigned to each interface. The IPv4 and/or IPv6 addresses, +// gateways, and routes assigned to sandbox and/or host interfaces. +// c) DNS information. Dictionary that includes DNS information for nameservers, +// domain, search domains and options. +type Result struct { Interfaces map[string]*Config DNS []types.DNS Routes []*types.Route @@ -41,20 +51,14 @@ Sandbox string } -// GetCNIResultFromResults returns a structured data containing the -// interface configuration for each of the interfaces created in the namespace. -// Conforms with -// Result: -// a) Interfaces list. Depending on the plugin, this can include the sandbox -// (eg, container or hypervisor) interface name and/or the host interface -// name, the hardware addresses of each interface, and details about the -// sandbox (if any) the interface is in. -// b) IP configuration assigned to each interface. The IPv4 and/or IPv6 addresses, -// gateways, and routes assigned to sandbox and/or host interfaces. -// c) DNS information. Dictionary that includes DNS information for nameservers, -// domain, search domains and options. -func (c *libcni) GetCNIResultFromResults(results []*current.Result) (*CNIResult, error) { - r := &CNIResult{ +// createResult creates a Result from the given slice of current.Result, adding +// structured data containing the interface configuration for each of the +// interfaces created in the namespace. It returns an error if validation of +// results fails, or if a network could not be found. +func (c *libcni) createResult(results []*current.Result) (*Result, error) { + c.RLock() + defer c.RUnlock() + r := &Result{ Interfaces: make(map[string]*Config), } @@ -76,7 +80,7 @@ // interfaces for _, ipConf := range result.IPs { if err := validateInterfaceConfig(ipConf, len(result.Interfaces)); err != nil { - return nil, errors.Wrapf(ErrInvalidResult, "failed to valid interface config: %v", err) + return nil, errors.Wrapf(ErrInvalidResult, "invalid interface config: %v", err) } name := c.getInterfaceName(result.Interfaces, ipConf) r.Interfaces[name].IPConfigs = append(r.Interfaces[name].IPConfigs, @@ -86,7 +90,7 @@ r.Routes = append(r.Routes, result.Routes...) } if _, ok := r.Interfaces[defaultInterface(c.prefix)]; !ok { - return nil, errors.Wrapf(ErrNotFound, "default network not found") + return nil, errors.Wrapf(ErrNotFound, "default network not found for: %s", defaultInterface(c.prefix)) } return r, nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/types.go containerd-1.5.9/vendor/github.com/containerd/go-cni/types.go --- containerd-1.2.6/vendor/github.com/containerd/go-cni/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,14 +20,16 @@ CNIPluginName = "cni" DefaultNetDir = "/etc/cni/net.d" DefaultCNIDir = "/opt/cni/bin" + DefaultMaxConfNum = 1 VendorCNIDirTemplate = "%s/opt/%s/bin" DefaultPrefix = "eth" ) type config struct { - pluginDirs []string - pluginConfDir string - prefix string + pluginDirs []string + pluginConfDir string + pluginMaxConfNum int + prefix string } type PortMapping struct { @@ -43,3 +45,21 @@ RangeEnd string Gateway string } + +// BandWidth defines the ingress/egress rate and burst limits +type BandWidth struct { + IngressRate uint64 + IngressBurst uint64 + EgressRate uint64 + EgressBurst uint64 +} + +// DNS defines the dns config +type DNS struct { + // List of DNS servers of the cluster. + Servers []string + // List of DNS search domains of the cluster. + Searches []string + // List of DNS options. + Options []string +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-cni/vendor.conf containerd-1.5.9/vendor/github.com/containerd/go-cni/vendor.conf --- containerd-1.2.6/vendor/github.com/containerd/go-cni/vendor.conf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-cni/vendor.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -github.com/stretchr/testify b89eecf5ca5db6d3ba60b237ffe3df7bafb7662f -github.com/davecgh/go-spew 8991bc29aa16c548c550c7ff78260e27b9ab7c73 -github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2 -github.com/stretchr/objx 8a3f7159479fbc75b30357fbc48f380b7320f08e -github.com/containernetworking/cni 142cde0c766cd6055cc7fdfdcb44579c0c9c35bf -github.com/pkg/errors v0.8.0 diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/command_linux.go containerd-1.5.9/vendor/github.com/containerd/go-runc/command_linux.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/command_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/command_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,6 +20,7 @@ "context" "os" "os/exec" + "strings" "syscall" ) @@ -32,10 +33,24 @@ cmd.SysProcAttr = &syscall.SysProcAttr{ Setpgid: r.Setpgid, } - cmd.Env = os.Environ() + cmd.Env = filterEnv(os.Environ(), "NOTIFY_SOCKET") // NOTIFY_SOCKET introduces a special behavior in runc but should only be set if invoked from systemd if r.PdeathSignal != 0 { cmd.SysProcAttr.Pdeathsig = r.PdeathSignal } return cmd } + +func filterEnv(in []string, names ...string) []string { + out := make([]string, 0, len(in)) +loop0: + for _, v := range in { + for _, k := range names { + if strings.HasPrefix(v, k+"=") { + continue loop0 + } + } + out = append(out, v) + } + return out +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/go.mod containerd-1.5.9/vendor/github.com/containerd/go-runc/go.mod --- containerd-1.2.6/vendor/github.com/containerd/go-runc/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +module github.com/containerd/go-runc + +go 1.13 + +require ( + github.com/containerd/console v1.0.1 + github.com/opencontainers/runtime-spec v1.0.2 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/go.sum containerd-1.5.9/vendor/github.com/containerd/go-runc/go.sum --- containerd-1.2.6/vendor/github.com/containerd/go-runc/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f h1:6Sc1XOXTulBN6imkqo6XoAXDEzoQ4/ro6xy7Vn8+rOM= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/io_unix.go containerd-1.5.9/vendor/github.com/containerd/go-runc/io_unix.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/io_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/io_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -20,7 +20,9 @@ import ( "github.com/pkg/errors" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" + "runtime" ) // NewPipeIO creates pipe pairs to be used with runc @@ -47,7 +49,13 @@ } pipes = append(pipes, stdin) if err = unix.Fchown(int(stdin.r.Fd()), uid, gid); err != nil { - return nil, errors.Wrap(err, "failed to chown stdin") + // TODO: revert with proper darwin solution, skipping for now + // as darwin chown is returning EINVAL on anonymous pipe + if runtime.GOOS == "darwin" { + logrus.WithError(err).Debug("failed to chown stdin, ignored") + } else { + return nil, errors.Wrap(err, "failed to chown stdin") + } } } if option.OpenStdout { @@ -56,7 +64,13 @@ } pipes = append(pipes, stdout) if err = unix.Fchown(int(stdout.w.Fd()), uid, gid); err != nil { - return nil, errors.Wrap(err, "failed to chown stdout") + // TODO: revert with proper darwin solution, skipping for now + // as darwin chown is returning EINVAL on anonymous pipe + if runtime.GOOS == "darwin" { + logrus.WithError(err).Debug("failed to chown stdout, ignored") + } else { + return nil, errors.Wrap(err, "failed to chown stdout") + } } } if option.OpenStderr { @@ -65,7 +79,13 @@ } pipes = append(pipes, stderr) if err = unix.Fchown(int(stderr.w.Fd()), uid, gid); err != nil { - return nil, errors.Wrap(err, "failed to chown stderr") + // TODO: revert with proper darwin solution, skipping for now + // as darwin chown is returning EINVAL on anonymous pipe + if runtime.GOOS == "darwin" { + logrus.WithError(err).Debug("failed to chown stderr, ignored") + } else { + return nil, errors.Wrap(err, "failed to chown stderr") + } } } return &pipeIO{ diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/README.md containerd-1.5.9/vendor/github.com/containerd/go-runc/README.md --- containerd-1.2.6/vendor/github.com/containerd/go-runc/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,7 +1,7 @@ # go-runc [![Build Status](https://travis-ci.org/containerd/go-runc.svg?branch=master)](https://travis-ci.org/containerd/go-runc) - +[![codecov](https://codecov.io/gh/containerd/go-runc/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/go-runc) This is a package for consuming the [runc](https://github.com/opencontainers/runc) binary in your Go applications. It tries to expose all the settings and features of the runc CLI. If there is something missing then add it, its opensource! @@ -12,3 +12,14 @@ ## Docs Docs can be found at [godoc.org](https://godoc.org/github.com/containerd/go-runc). + +## Project details + +The go-runc is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/runc.go containerd-1.5.9/vendor/github.com/containerd/go-runc/runc.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/runc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/runc.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ package runc import ( + "bytes" "context" "encoding/json" "errors" @@ -28,7 +29,6 @@ "path/filepath" "strconv" "strings" - "syscall" "time" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -54,29 +54,15 @@ DefaultCommand = "runc" ) -// Runc is the client to the runc cli -type Runc struct { - //If command is empty, DefaultCommand is used - Command string - Root string - Debug bool - Log string - LogFormat Format - PdeathSignal syscall.Signal - Setpgid bool - Criu string - SystemdCgroup bool - Rootless *bool // nil stands for "auto" -} - // List returns all containers created inside the provided runc root directory func (r *Runc) List(context context.Context) ([]*Container, error) { - data, err := cmdOutput(r.command(context, "list", "--format=json"), false) + data, err := cmdOutput(r.command(context, "list", "--format=json"), false, nil) + defer putBuf(data) if err != nil { return nil, err } var out []*Container - if err := json.Unmarshal(data, &out); err != nil { + if err := json.Unmarshal(data.Bytes(), &out); err != nil { return nil, err } return out, nil @@ -84,12 +70,13 @@ // State returns the state for the container provided by id func (r *Runc) State(context context.Context, id string) (*Container, error) { - data, err := cmdOutput(r.command(context, "state", id), true) + data, err := cmdOutput(r.command(context, "state", id), true, nil) + defer putBuf(data) if err != nil { - return nil, fmt.Errorf("%s: %s", err, data) + return nil, fmt.Errorf("%s: %s", err, data.String()) } var c Container - if err := json.Unmarshal(data, &c); err != nil { + if err := json.Unmarshal(data.Bytes(), &c); err != nil { return nil, err } return &c, nil @@ -108,6 +95,7 @@ NoPivot bool NoNewKeyring bool ExtraFiles []*os.File + Started chan<- int } func (o *CreateOpts) args() (out []string, err error) { @@ -153,9 +141,10 @@ cmd.ExtraFiles = opts.ExtraFiles if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, nil) + defer putBuf(data) if err != nil { - return fmt.Errorf("%s: %s", err, data) + return fmt.Errorf("%s: %s", err, data.String()) } return nil } @@ -172,7 +161,7 @@ } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) } return err } @@ -187,6 +176,7 @@ PidFile string ConsoleSocket ConsoleSocket Detach bool + Started chan<- int } func (o *ExecOpts) args() (out []string, err error) { @@ -206,9 +196,12 @@ return out, nil } -// Exec executres and additional process inside the container based on a full +// Exec executes an additional process inside the container based on a full // OCI Process specification func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts *ExecOpts) error { + if opts.Started != nil { + defer close(opts.Started) + } f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "runc-process") if err != nil { return err @@ -232,9 +225,10 @@ opts.Set(cmd) } if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, opts.Started) + defer putBuf(data) if err != nil { - return fmt.Errorf("%s: %s", err, data) + return fmt.Errorf("%w: %s", err, data.String()) } return nil } @@ -242,6 +236,9 @@ if err != nil { return err } + if opts.Started != nil { + opts.Started <- cmd.Process.Pid + } if opts != nil && opts.IO != nil { if c, ok := opts.IO.(StartCloser); ok { if err := c.CloseAfterStart(); err != nil { @@ -251,7 +248,7 @@ } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) } return err } @@ -259,6 +256,9 @@ // Run runs the create, start, delete lifecycle of the container // and returns its exit status after it has exited func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) (int, error) { + if opts.Started != nil { + defer close(opts.Started) + } args := []string{"run", "--bundle", bundle} if opts != nil { oargs, err := opts.args() @@ -275,7 +275,14 @@ if err != nil { return -1, err } - return Monitor.Wait(cmd, ec) + if opts.Started != nil { + opts.Started <- cmd.Process.Pid + } + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) + } + return status, err } type DeleteOpts struct { @@ -394,12 +401,13 @@ // Ps lists all the processes inside the container returning their pids func (r *Runc) Ps(context context.Context, id string) ([]int, error) { - data, err := cmdOutput(r.command(context, "ps", "--format", "json", id), true) + data, err := cmdOutput(r.command(context, "ps", "--format", "json", id), true, nil) + defer putBuf(data) if err != nil { - return nil, fmt.Errorf("%s: %s", err, data) + return nil, fmt.Errorf("%s: %s", err, data.String()) } var pids []int - if err := json.Unmarshal(data, &pids); err != nil { + if err := json.Unmarshal(data.Bytes(), &pids); err != nil { return nil, err } return pids, nil @@ -407,12 +415,13 @@ // Top lists all the processes inside the container returning the full ps data func (r *Runc) Top(context context.Context, id string, psOptions string) (*TopResults, error) { - data, err := cmdOutput(r.command(context, "ps", "--format", "table", id, psOptions), true) + data, err := cmdOutput(r.command(context, "ps", "--format", "table", id, psOptions), true, nil) + defer putBuf(data) if err != nil { - return nil, fmt.Errorf("%s: %s", err, data) + return nil, fmt.Errorf("%s: %s", err, data.String()) } - topResults, err := ParsePSOutput(data) + topResults, err := ParsePSOutput(data.Bytes()) if err != nil { return nil, fmt.Errorf("%s: ", err) } @@ -441,6 +450,10 @@ // EmptyNamespaces creates a namespace for the container but does not save its properties // Provide the namespaces you wish to be checkpointed without their settings on restore EmptyNamespaces []string + // LazyPages uses userfaultfd to lazily restore memory pages + LazyPages bool + // StatusFile is the file criu writes \0 to once lazy-pages is ready + StatusFile *os.File } type CgroupMode string @@ -482,6 +495,9 @@ for _, ns := range o.EmptyNamespaces { out = append(out, "--empty-ns", ns) } + if o.LazyPages { + out = append(out, "--lazy-pages") + } return out } @@ -500,13 +516,23 @@ // Checkpoint allows you to checkpoint a container using criu func (r *Runc) Checkpoint(context context.Context, id string, opts *CheckpointOpts, actions ...CheckpointAction) error { args := []string{"checkpoint"} + extraFiles := []*os.File{} if opts != nil { args = append(args, opts.args()...) + if opts.StatusFile != nil { + // pass the status file to the child process + extraFiles = []*os.File{opts.StatusFile} + // set status-fd to 3 as this will be the file descriptor + // of the first file passed with cmd.ExtraFiles + args = append(args, "--status-fd", "3") + } } for _, a := range actions { args = a(args) } - return r.runOrError(r.command(context, append(args, id)...)) + cmd := r.command(context, append(args, id)...) + cmd.ExtraFiles = extraFiles + return r.runOrError(cmd) } type RestoreOpts struct { @@ -570,7 +596,11 @@ } } } - return Monitor.Wait(cmd, ec) + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) + } + return status, err } // Update updates the current container with the provided resource spec @@ -597,42 +627,33 @@ // Version returns the runc and runtime-spec versions func (r *Runc) Version(context context.Context) (Version, error) { - data, err := cmdOutput(r.command(context, "--version"), false) + data, err := cmdOutput(r.command(context, "--version"), false, nil) + defer putBuf(data) if err != nil { return Version{}, err } - return parseVersion(data) + return parseVersion(data.Bytes()) } func parseVersion(data []byte) (Version, error) { var v Version parts := strings.Split(strings.TrimSpace(string(data)), "\n") - if len(parts) != 3 { - return v, nil - } - for i, p := range []struct { - dest *string - split string - }{ - { - dest: &v.Runc, - split: "version ", - }, - { - dest: &v.Commit, - split: ": ", - }, - { - dest: &v.Spec, - split: ": ", - }, - } { - p2 := strings.Split(parts[i], p.split) - if len(p2) != 2 { - return v, fmt.Errorf("unable to parse version line %q", parts[i]) + + if len(parts) > 0 { + if !strings.HasPrefix(parts[0], "runc version ") { + return v, nil + } + v.Runc = parts[0][13:] + + for _, part := range parts[1:] { + if strings.HasPrefix(part, "commit: ") { + v.Commit = part[8:] + } else if strings.HasPrefix(part, "spec: ") { + v.Spec = part[6:] + } } - *p.dest = p2[1] } + return v, nil } @@ -674,20 +695,22 @@ } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) } return err } - data, err := cmdOutput(cmd, true) + data, err := cmdOutput(cmd, true, nil) + defer putBuf(data) if err != nil { - return fmt.Errorf("%s: %s", err, data) + return fmt.Errorf("%s: %s", err, data.String()) } return nil } -func cmdOutput(cmd *exec.Cmd, combined bool) ([]byte, error) { +// callers of cmdOutput are expected to call putBuf on the returned Buffer +// to ensure it is released back to the shared pool after use. +func cmdOutput(cmd *exec.Cmd, combined bool, started chan<- int) (*bytes.Buffer, error) { b := getBuf() - defer putBuf(b) cmd.Stdout = b if combined { @@ -697,11 +720,22 @@ if err != nil { return nil, err } + if started != nil { + started <- cmd.Process.Pid + } status, err := Monitor.Wait(cmd, ec) if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + err = fmt.Errorf("%s did not terminate successfully: %w", cmd.Args[0], &ExitError{status}) } - return b.Bytes(), err + return b, err +} + +type ExitError struct { + Status int +} + +func (e *ExitError) Error() string { + return fmt.Sprintf("exit status %d", e.Status) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/runc_unix.go containerd-1.5.9/vendor/github.com/containerd/go-runc/runc_unix.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/runc_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/runc_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,38 @@ +//+build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "golang.org/x/sys/unix" +) + +// Runc is the client to the runc cli +type Runc struct { + //If command is empty, DefaultCommand is used + Command string + Root string + Debug bool + Log string + LogFormat Format + PdeathSignal unix.Signal + Setpgid bool + Criu string + SystemdCgroup bool + Rootless *bool // nil stands for "auto" +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/runc_windows.go containerd-1.5.9/vendor/github.com/containerd/go-runc/runc_windows.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/runc_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/runc_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +// Runc is the client to the runc cli +type Runc struct { + //If command is empty, DefaultCommand is used + Command string + Root string + Debug bool + Log string + LogFormat Format + Setpgid bool + Criu string + SystemdCgroup bool + Rootless *bool // nil stands for "auto" +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/.travis.yml containerd-1.5.9/vendor/github.com/containerd/go-runc/.travis.yml --- containerd-1.2.6/vendor/github.com/containerd/go-runc/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +language: go +go: + - 1.13.x + - 1.14.x + - 1.15.x + +install: + - go get -t ./... + - go get -u github.com/vbatts/git-validation + - go get -u github.com/kunalkushwaha/ltag + +before_script: + - pushd ..; git clone https://github.com/containerd/project; popd + +script: + - DCO_VERBOSITY=-q ../project/script/validate/dco + - ../project/script/validate/fileheader ../project/ + - go test -v -race -covermode=atomic -coverprofile=coverage.txt ./... + +after_success: + - bash <(curl -s https://codecov.io/bash) diff -Nru containerd-1.2.6/vendor/github.com/containerd/go-runc/utils.go containerd-1.5.9/vendor/github.com/containerd/go-runc/utils.go --- containerd-1.2.6/vendor/github.com/containerd/go-runc/utils.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/go-runc/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -57,6 +57,10 @@ } func putBuf(b *bytes.Buffer) { + if b == nil { + return + } + b.Reset() bytesBufferPool.Put(b) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/CHANGES containerd-1.5.9/vendor/github.com/containerd/imgcrypt/CHANGES --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/CHANGES 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/CHANGES 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,9 @@ +CHANGES + +v1.1.1: + - rebased on ocicrypt 1.1.1 + +v1.1.0: + - rebased on ocicrypt 1.1.0 + - added pkcs11 support; experimental + - added keyprovider support diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/.gitignore containerd-1.5.9/vendor/github.com/containerd/imgcrypt/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,3 @@ +*~ +/ctr +/ctd-decoder diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/imgcrypt/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,20 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + +run: + skip-dirs: + - cmd/ctr/commands/run + - cmd/ctr/commands/images + - cmd\\ctr\\commands\\run + - cmd\\ctr\\commands\\images diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/go.mod containerd-1.5.9/vendor/github.com/containerd/imgcrypt/go.mod --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +module github.com/containerd/imgcrypt + +go 1.13 + +require ( + github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958 + github.com/Microsoft/hcsshim v0.8.16 + github.com/containerd/console v1.0.2 + github.com/containerd/containerd v1.5.0-rc.0 + github.com/containerd/typeurl v1.0.1 + github.com/containers/ocicrypt v1.1.1 + github.com/gogo/protobuf v1.3.2 + github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/image-spec v1.0.1 + github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + github.com/urfave/cli v1.22.2 + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a + google.golang.org/grpc v1.33.2 +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/go.sum containerd-1.5.9/vendor/github.com/containerd/imgcrypt/go.sum --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,890 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958 h1:koVgEW/cX7NavmMAkL6LgoMZJ9gJnxuWMwwfw5A2s34= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16 h1:8/auA4LFIZFTGrqfKhGBSXwM6/4X1fHa/xniyEHu8ac= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0 h1:Fv93L3KKckEcEHR3oApXVzyBTDA8WAm6VXhPE00N3f8= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0 h1:fVmAxX648SbHlWm3UnrkKQrZ+aeXznUnZttjbIYCF60= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d h1:u6sWqdNGAy7+O8qG/r1dqdnZE7IdEjteK3WGuvbfreo= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0 h1:e+50zk22gvHLJKe8+d+xSMyA88PPQk/XfWuUw1BdnPA= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1 h1:PvuK4E3D5S5q6IqsPDCy928FhP0LUIGcmZ/Yhgp5Djw= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1 h1:prL8l9w3ntVqXvNH1CiNn5ENjcCnr38JqpSyvKKB4GI= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d h1:pNa8metDkwZjb9g4T8s+krQ+HRgZAkqnXml+wNir/+s= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 h1:lIOOHPEbXzO3vnmx2gok1Tfs31Q8GQqKLc8vVqyQq/I= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/images/encryption/client.go containerd-1.5.9/vendor/github.com/containerd/imgcrypt/images/encryption/client.go --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/images/encryption/client.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/images/encryption/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package encryption + +import ( + "context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/containers" + "github.com/containerd/containerd/diff" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/imgcrypt" + "github.com/containerd/typeurl" + encconfig "github.com/containers/ocicrypt/config" + "github.com/gogo/protobuf/types" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +// WithDecryptedUnpack allows to pass parameters the 'layertool' needs to the applier +func WithDecryptedUnpack(data *imgcrypt.Payload) diff.ApplyOpt { + return func(_ context.Context, desc ocispec.Descriptor, c *diff.ApplyConfig) error { + if c.ProcessorPayloads == nil { + c.ProcessorPayloads = make(map[string]*types.Any) + } + data.Descriptor = desc + any, err := typeurl.MarshalAny(data) + if err != nil { + return errors.Wrapf(err, "failed to marshal payload") + } + + for _, id := range imgcrypt.PayloadToolIDs { + c.ProcessorPayloads[id] = any + } + return nil + } +} + +// WithUnpackConfigApplyOpts allows to pass an ApplyOpt +func WithUnpackConfigApplyOpts(opt diff.ApplyOpt) containerd.UnpackOpt { + return func(_ context.Context, uc *containerd.UnpackConfig) error { + uc.ApplyOpts = append(uc.ApplyOpts, opt) + return nil + } +} + +// WithUnpackOpts is used to add unpack options to the unpacker. +func WithUnpackOpts(opts []containerd.UnpackOpt) containerd.RemoteOpt { + return func(_ *containerd.Client, c *containerd.RemoteContext) error { + c.UnpackOpts = append(c.UnpackOpts, opts...) + return nil + } +} + +// WithAuthorizationCheck checks the authorization of keys used for encrypted containers +// be checked upon creation of a container +func WithAuthorizationCheck(dc *encconfig.DecryptConfig) containerd.NewContainerOpts { + return func(ctx context.Context, client *containerd.Client, c *containers.Container) error { + image, err := client.ImageService().Get(ctx, c.Image) + if errdefs.IsNotFound(err) { + // allow creation of container without a existing image + return nil + } else if err != nil { + return err + } + + return CheckAuthorization(ctx, client.ContentStore(), image.Target, dc) + } +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go containerd-1.5.9/vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/images/encryption/encryption.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,468 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package encryption + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "math/rand" + + "github.com/containerd/containerd/images" + "github.com/containers/ocicrypt" + encconfig "github.com/containers/ocicrypt/config" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/platforms" + encocispec "github.com/containers/ocicrypt/spec" + digest "github.com/opencontainers/go-digest" + specs "github.com/opencontainers/image-spec/specs-go" + "github.com/pkg/errors" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +type cryptoOp int + +const ( + cryptoOpEncrypt cryptoOp = iota + cryptoOpDecrypt = iota + cryptoOpUnwrapOnly = iota +) + +// LayerFilter allows to select Layers by certain criteria +type LayerFilter func(desc ocispec.Descriptor) bool + +// IsEncryptedDiff returns true if mediaType is a known encrypted media type. +func IsEncryptedDiff(ctx context.Context, mediaType string) bool { + switch mediaType { + case encocispec.MediaTypeLayerGzipEnc, encocispec.MediaTypeLayerEnc: + return true + } + return false +} + +// HasEncryptedLayer returns true if any LayerInfo indicates that the layer is encrypted +func HasEncryptedLayer(ctx context.Context, layerInfos []ocispec.Descriptor) bool { + for i := 0; i < len(layerInfos); i++ { + if IsEncryptedDiff(ctx, layerInfos[i].MediaType) { + return true + } + } + return false +} + +// encryptLayer encrypts the layer using the CryptoConfig and creates a new OCI Descriptor. +// A call to this function may also only manipulate the wrapped keys list. +// The caller is expected to store the returned encrypted data and OCI Descriptor +func encryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderAt, desc ocispec.Descriptor) (ocispec.Descriptor, io.Reader, ocicrypt.EncryptLayerFinalizer, error) { + var ( + size int64 + d digest.Digest + err error + ) + + encLayerReader, encLayerFinalizer, err := ocicrypt.EncryptLayer(cc.EncryptConfig, ocicrypt.ReaderFromReaderAt(dataReader), desc) + if err != nil { + return ocispec.Descriptor{}, nil, nil, err + } + + // were data touched ? + if encLayerReader != nil { + size = 0 + d = "" + } else { + size = desc.Size + d = desc.Digest + } + + newDesc := ocispec.Descriptor{ + Digest: d, + Size: size, + Platform: desc.Platform, + } + + switch desc.MediaType { + case images.MediaTypeDockerSchema2LayerGzip: + newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc + case images.MediaTypeDockerSchema2Layer: + newDesc.MediaType = encocispec.MediaTypeLayerEnc + case encocispec.MediaTypeLayerGzipEnc: + newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc + case encocispec.MediaTypeLayerEnc: + newDesc.MediaType = encocispec.MediaTypeLayerEnc + + // TODO: Mediatypes to be added in ocispec + case ocispec.MediaTypeImageLayerGzip: + newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc + case ocispec.MediaTypeImageLayer: + newDesc.MediaType = encocispec.MediaTypeLayerEnc + + default: + return ocispec.Descriptor{}, nil, nil, errors.Errorf("Encryption: unsupporter layer MediaType: %s\n", desc.MediaType) + } + + return newDesc, encLayerReader, encLayerFinalizer, nil +} + +// DecryptLayer decrypts the layer using the DecryptConfig and creates a new OCI Descriptor. +// The caller is expected to store the returned plain data and OCI Descriptor +func DecryptLayer(dc *encconfig.DecryptConfig, dataReader io.Reader, desc ocispec.Descriptor, unwrapOnly bool) (ocispec.Descriptor, io.Reader, digest.Digest, error) { + resultReader, layerDigest, err := ocicrypt.DecryptLayer(dc, dataReader, desc, unwrapOnly) + if err != nil || unwrapOnly { + return ocispec.Descriptor{}, nil, "", err + } + + newDesc := ocispec.Descriptor{ + Size: 0, + Platform: desc.Platform, + } + + switch desc.MediaType { + case encocispec.MediaTypeLayerGzipEnc: + newDesc.MediaType = images.MediaTypeDockerSchema2LayerGzip + case encocispec.MediaTypeLayerEnc: + newDesc.MediaType = images.MediaTypeDockerSchema2Layer + default: + return ocispec.Descriptor{}, nil, "", errors.Errorf("Decryption: unsupporter layer MediaType: %s\n", desc.MediaType) + } + return newDesc, resultReader, layerDigest, nil +} + +// decryptLayer decrypts the layer using the CryptoConfig and creates a new OCI Descriptor. +// The caller is expected to store the returned plain data and OCI Descriptor +func decryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderAt, desc ocispec.Descriptor, unwrapOnly bool) (ocispec.Descriptor, io.Reader, error) { + resultReader, d, err := ocicrypt.DecryptLayer(cc.DecryptConfig, ocicrypt.ReaderFromReaderAt(dataReader), desc, unwrapOnly) + if err != nil || unwrapOnly { + return ocispec.Descriptor{}, nil, err + } + + newDesc := ocispec.Descriptor{ + Digest: d, + Size: 0, + Platform: desc.Platform, + } + + switch desc.MediaType { + case encocispec.MediaTypeLayerGzipEnc: + newDesc.MediaType = images.MediaTypeDockerSchema2LayerGzip + case encocispec.MediaTypeLayerEnc: + newDesc.MediaType = images.MediaTypeDockerSchema2Layer + default: + return ocispec.Descriptor{}, nil, errors.Errorf("Decryption: unsupporter layer MediaType: %s\n", desc.MediaType) + } + return newDesc, resultReader, nil +} + +// cryptLayer handles the changes due to encryption or decryption of a layer +func cryptLayer(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, cryptoOp cryptoOp) (ocispec.Descriptor, error) { + var ( + resultReader io.Reader + newDesc ocispec.Descriptor + encLayerFinalizer ocicrypt.EncryptLayerFinalizer + ) + + dataReader, err := cs.ReaderAt(ctx, desc) + if err != nil { + return ocispec.Descriptor{}, err + } + defer dataReader.Close() + + if cryptoOp == cryptoOpEncrypt { + newDesc, resultReader, encLayerFinalizer, err = encryptLayer(cc, dataReader, desc) + } else { + newDesc, resultReader, err = decryptLayer(cc, dataReader, desc, cryptoOp == cryptoOpUnwrapOnly) + } + if err != nil || cryptoOp == cryptoOpUnwrapOnly { + return ocispec.Descriptor{}, err + } + + newDesc.Annotations = ocicrypt.FilterOutAnnotations(desc.Annotations) + + // some operations, such as changing recipients, may not touch the layer at all + if resultReader != nil { + var ref string + // If we have the digest, write blob with checks + haveDigest := newDesc.Digest.String() != "" + if haveDigest { + ref = fmt.Sprintf("layer-%s", newDesc.Digest.String()) + } else { + ref = fmt.Sprintf("blob-%d-%d", rand.Int(), rand.Int()) + } + + if haveDigest { + if err := content.WriteBlob(ctx, cs, ref, resultReader, newDesc); err != nil { + return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config") + } + } else { + newDesc.Digest, newDesc.Size, err = ingestReader(ctx, cs, ref, resultReader) + if err != nil { + return ocispec.Descriptor{}, err + } + } + } + + // After performing encryption, call finalizer to get annotations + if encLayerFinalizer != nil { + annotations, err := encLayerFinalizer() + if err != nil { + return ocispec.Descriptor{}, errors.Wrap(err, "Error getting annotations from encLayer finalizer") + } + for k, v := range annotations { + newDesc.Annotations[k] = v + } + } + return newDesc, err +} + +func ingestReader(ctx context.Context, cs content.Ingester, ref string, r io.Reader) (digest.Digest, int64, error) { + cw, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) + if err != nil { + return "", 0, errors.Wrap(err, "failed to open writer") + } + defer cw.Close() + + if _, err := content.CopyReader(cw, r); err != nil { + return "", 0, errors.Wrap(err, "copy failed") + } + + st, err := cw.Status() + if err != nil { + return "", 0, errors.Wrap(err, "failed to get state") + } + + if err := cw.Commit(ctx, st.Offset, ""); err != nil { + if !errdefs.IsAlreadyExists(err) { + return "", 0, errors.Wrapf(err, "failed commit on ref %q", ref) + } + } + + return cw.Digest(), st.Offset, nil +} + +// Encrypt or decrypt all the Children of a given descriptor +func cryptChildren(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter, cryptoOp cryptoOp, thisPlatform *ocispec.Platform) (ocispec.Descriptor, bool, error) { + children, err := images.Children(ctx, cs, desc) + if err != nil { + if errdefs.IsNotFound(err) { + return desc, false, nil + } + return ocispec.Descriptor{}, false, err + } + + var newLayers []ocispec.Descriptor + var config ocispec.Descriptor + modified := false + + for _, child := range children { + // we only encrypt child layers and have to update their parents if encryption happened + switch child.MediaType { + case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: + config = child + case images.MediaTypeDockerSchema2LayerGzip, images.MediaTypeDockerSchema2Layer, + ocispec.MediaTypeImageLayerGzip, ocispec.MediaTypeImageLayer: + if cryptoOp == cryptoOpEncrypt && lf(child) { + nl, err := cryptLayer(ctx, cs, child, cc, cryptoOp) + if err != nil { + return ocispec.Descriptor{}, false, err + } + modified = true + newLayers = append(newLayers, nl) + } else { + newLayers = append(newLayers, child) + } + case encocispec.MediaTypeLayerGzipEnc, encocispec.MediaTypeLayerEnc: + // this one can be decrypted but also its recipients list changed + if lf(child) { + nl, err := cryptLayer(ctx, cs, child, cc, cryptoOp) + if err != nil || cryptoOp == cryptoOpUnwrapOnly { + return ocispec.Descriptor{}, false, err + } + modified = true + newLayers = append(newLayers, nl) + } else { + newLayers = append(newLayers, child) + } + case images.MediaTypeDockerSchema2LayerForeign, images.MediaTypeDockerSchema2LayerForeignGzip: + // never encrypt/decrypt + newLayers = append(newLayers, child) + default: + return ocispec.Descriptor{}, false, errors.Errorf("bad/unhandled MediaType %s in encryptChildren\n", child.MediaType) + } + } + + if modified && len(newLayers) > 0 { + newManifest := ocispec.Manifest{ + Versioned: specs.Versioned{ + SchemaVersion: 2, + }, + Config: config, + Layers: newLayers, + } + + mb, err := json.MarshalIndent(newManifest, "", " ") + if err != nil { + return ocispec.Descriptor{}, false, errors.Wrap(err, "failed to marshal image") + } + + newDesc := ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageManifest, + Size: int64(len(mb)), + Digest: digest.Canonical.FromBytes(mb), + Platform: desc.Platform, + } + + labels := map[string]string{} + labels["containerd.io/gc.ref.content.0"] = newManifest.Config.Digest.String() + for i, ch := range newManifest.Layers { + labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String() + } + + ref := fmt.Sprintf("manifest-%s", newDesc.Digest.String()) + + if err := content.WriteBlob(ctx, cs, ref, bytes.NewReader(mb), newDesc, content.WithLabels(labels)); err != nil { + return ocispec.Descriptor{}, false, errors.Wrap(err, "failed to write config") + } + return newDesc, true, nil + } + + return desc, modified, nil +} + +// cryptManifest encrypts or decrypts the children of a top level manifest +func cryptManifest(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter, cryptoOp cryptoOp) (ocispec.Descriptor, bool, error) { + p, err := content.ReadBlob(ctx, cs, desc) + if err != nil { + return ocispec.Descriptor{}, false, err + } + var manifest ocispec.Manifest + if err := json.Unmarshal(p, &manifest); err != nil { + return ocispec.Descriptor{}, false, err + } + platform := platforms.DefaultSpec() + newDesc, modified, err := cryptChildren(ctx, cs, desc, cc, lf, cryptoOp, &platform) + if err != nil || cryptoOp == cryptoOpUnwrapOnly { + return ocispec.Descriptor{}, false, err + } + return newDesc, modified, nil +} + +// cryptManifestList encrypts or decrypts the children of a top level manifest list +func cryptManifestList(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter, cryptoOp cryptoOp) (ocispec.Descriptor, bool, error) { + // read the index; if any layer is encrypted and any manifests change we will need to rewrite it + b, err := content.ReadBlob(ctx, cs, desc) + if err != nil { + return ocispec.Descriptor{}, false, err + } + + var index ocispec.Index + if err := json.Unmarshal(b, &index); err != nil { + return ocispec.Descriptor{}, false, err + } + + var newManifests []ocispec.Descriptor + modified := false + for _, manifest := range index.Manifests { + newManifest, m, err := cryptChildren(ctx, cs, manifest, cc, lf, cryptoOp, manifest.Platform) + if err != nil || cryptoOp == cryptoOpUnwrapOnly { + return ocispec.Descriptor{}, false, err + } + if m { + modified = true + } + newManifests = append(newManifests, newManifest) + } + + if modified { + // we need to update the index + newIndex := ocispec.Index{ + Versioned: index.Versioned, + Manifests: newManifests, + } + + mb, err := json.MarshalIndent(newIndex, "", " ") + if err != nil { + return ocispec.Descriptor{}, false, errors.Wrap(err, "failed to marshal index") + } + + newDesc := ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageIndex, + Size: int64(len(mb)), + Digest: digest.Canonical.FromBytes(mb), + } + + labels := map[string]string{} + for i, m := range newIndex.Manifests { + labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String() + } + + ref := fmt.Sprintf("index-%s", newDesc.Digest.String()) + + if err = content.WriteBlob(ctx, cs, ref, bytes.NewReader(mb), newDesc, content.WithLabels(labels)); err != nil { + return ocispec.Descriptor{}, false, errors.Wrap(err, "failed to write index") + } + return newDesc, true, nil + } + + return desc, false, nil +} + +// cryptImage is the dispatcher to encrypt/decrypt an image; it accepts either an OCI descriptor +// representing a manifest list or a single manifest +func cryptImage(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter, cryptoOp cryptoOp) (ocispec.Descriptor, bool, error) { + if cc == nil { + return ocispec.Descriptor{}, false, errors.Wrapf(errdefs.ErrInvalidArgument, "CryptoConfig must not be nil") + } + switch desc.MediaType { + case ocispec.MediaTypeImageIndex, images.MediaTypeDockerSchema2ManifestList: + return cryptManifestList(ctx, cs, desc, cc, lf, cryptoOp) + case ocispec.MediaTypeImageManifest, images.MediaTypeDockerSchema2Manifest: + return cryptManifest(ctx, cs, desc, cc, lf, cryptoOp) + default: + return ocispec.Descriptor{}, false, errors.Errorf("CryptImage: Unhandled media type: %s", desc.MediaType) + } +} + +// EncryptImage encrypts an image; it accepts either an OCI descriptor representing a manifest list or a single manifest +func EncryptImage(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter) (ocispec.Descriptor, bool, error) { + return cryptImage(ctx, cs, desc, cc, lf, cryptoOpEncrypt) +} + +// DecryptImage decrypts an image; it accepts either an OCI descriptor representing a manifest list or a single manifest +func DecryptImage(ctx context.Context, cs content.Store, desc ocispec.Descriptor, cc *encconfig.CryptoConfig, lf LayerFilter) (ocispec.Descriptor, bool, error) { + return cryptImage(ctx, cs, desc, cc, lf, cryptoOpDecrypt) +} + +// CheckAuthorization checks whether a user has the right keys to be allowed to access an image (every layer) +// It takes decrypting of the layers only as far as decrypting the asymmetrically encrypted data +// The decryption is only done for the current platform +func CheckAuthorization(ctx context.Context, cs content.Store, desc ocispec.Descriptor, dc *encconfig.DecryptConfig) error { + cc := encconfig.InitDecryption(dc.Parameters) + + lf := func(desc ocispec.Descriptor) bool { + return true + } + + _, _, err := cryptImage(ctx, cs, desc, &cc, lf, cryptoOpUnwrapOnly) + if err != nil { + return errors.Wrapf(err, "you are not authorized to use this image") + } + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/LICENSE containerd-1.5.9/vendor/github.com/containerd/imgcrypt/LICENSE --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright The containerd Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + 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. diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/MAINTAINERS containerd-1.5.9/vendor/github.com/containerd/imgcrypt/MAINTAINERS --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/MAINTAINERS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/MAINTAINERS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,9 @@ +# imgcrypt maintainers +# +# As a containerd sub-project, containerd maintainers are also included from https://github.com/containerd/project/blob/master/MAINTAINERS. +# See https://github.com/containerd/project/blob/master/GOVERNANCE.md for description of maintainer role +# +# MAINTAINERS +# GitHub ID, Name, Email address +stefanberger, Stefan Berger, stefanb@linux.ibm.com +lumjjb, Brandon Lum, lumjjb@gmail.com diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/Makefile containerd-1.5.9/vendor/github.com/containerd/imgcrypt/Makefile --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# Base path used to install. +DESTDIR ?= /usr/local + +COMMANDS=ctd-decoder ctr-enc + +BINARIES=$(addprefix bin/,$(COMMANDS)) + +.PHONY: check build ctd-decoder + +all: build + +build: $(BINARIES) + +FORCE: + +bin/ctd-decoder: cmd/ctd-decoder FORCE + go build -o $@ -v ./cmd/ctd-decoder/ + +bin/ctr-enc: cmd/ctr FORCE + go build -o $@ -v ./cmd/ctr/ + +check: + @echo "$@" + @golangci-lint run + @script/check_format.sh + +install: + @echo "$@" + @mkdir -p $(DESTDIR)/bin + @install $(BINARIES) $(DESTDIR)/bin + +uninstall: + @echo "$@" + @rm -f $(addprefix $(DESTDIR)/bin/,$(notdir $(BINARIES))) + +clean: + @echo "$@" + @rm -f $(BINARIES) + +test: + @echo "$@" + @go test ./... diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/payload.go containerd-1.5.9/vendor/github.com/containerd/imgcrypt/payload.go --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/payload.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/payload.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,43 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package imgcrypt + +import ( + "github.com/containerd/typeurl" + encconfig "github.com/containers/ocicrypt/config" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +const ( + PayloadURI = "io.containerd.ocicrypt.v1.Payload" +) + +var PayloadToolIDs = []string{ + "io.containerd.ocicrypt.decoder.v1.tar", + "io.containerd.ocicrypt.decoder.v1.tar.gzip", +} + +func init() { + typeurl.Register(&Payload{}, PayloadURI) +} + +// Payload holds data that the external layer decryption tool +// needs for decrypting a layer +type Payload struct { + DecryptConfig encconfig.DecryptConfig + Descriptor ocispec.Descriptor +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/imgcrypt/README.md containerd-1.5.9/vendor/github.com/containerd/imgcrypt/README.md --- containerd-1.2.6/vendor/github.com/containerd/imgcrypt/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/imgcrypt/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,103 @@ +# imgcrypt image encryption library and command line tool + +Project `imgcrypt` is a non-core subproject of containerd. + +The `imgcrypt` library provides API exensions for containerd to support encrypted container images and implements +the `ctd-decoder` command line tool for use by containerd to decrypt encrypted container images. An extended version +of containerd's `ctr` tool (`ctr-enc') with support for encrypting and decrypting container images is also provided. + +`imgcrypt` relies on the [`ocicrypt`](https://github.com/containers/ocicrypt) library for crypto functions on image layers. + +# Usage + +`imgcrypt` requires containerd 1.3 or later. Containerd 1.4 or later is required when used with Kubernetes. +For configuration instructions for kubernetes, please consult the [CRI decryption document](https://github.com/containerd/containerd/blob/master/docs/decryption.md). + +Build and install `imgcrypt`: + +``` +# make +# sudo make install +``` + +Start containerd with a configuration file that looks as follows. To avoid interference with a containerd from a Docker +installation we use /tmp for directories. Also, we build containerd 1.3 from the source but do not install it. + +``` +# cat config.toml +disable_plugins = ["cri"] +root = "/tmp/var/lib/containerd" +state = "/tmp/run/containerd" +[grpc] + address = "/tmp/run/containerd/containerd.sock" + uid = 0 + gid = 0 +[stream_processors] + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"] + accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"] + returns = "application/vnd.oci.image.layer.v1.tar+gzip" + path = "/usr/local/bin/ctd-decoder" + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"] + accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"] + returns = "application/vnd.oci.image.layer.v1.tar" + path = "/usr/local/bin/ctd-decoder" + +# sudo ~/src/github.com/containerd/containerd/bin/containerd -c config.toml +``` + +Create an RSA key pair using the openssl command line tool and encrypted an image: + +``` +# openssl genrsa -out mykey.pem +Generating RSA private key, 2048 bit long modulus (2 primes) +...............................................+++++ +............................+++++ +e is 65537 (0x010001) +# openssl rsa -in mykey.pem -pubout -out mypubkey.pem +writing RSA key +# sudo chmod 0666 /tmp/run/containerd/containerd.sock +# CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock" +# $CTR images pull --all-platforms docker.io/library/bash:latest +[...] +# $CTR images layerinfo --platform linux/amd64 docker.io/library/bash:latest + # DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS + 0 sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609 linux/amd64 2789669 + 1 sha256:7dd01fd971d4ec7058c5636a505327b24e5fc8bd7f62816a9d518472bd9b15c0 linux/amd64 3174665 + 2 sha256:691cfbca522787898c8b37f063dd20e5524e7d103e1a3b298bd2e2b8da54faf5 linux/amd64 340 +# $CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest bash.enc:latest +Encrypting docker.io/library/bash:latest to bash.enc:latest +$ $CTR images layerinfo --platform linux/amd64 bash.enc:latest + # DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS + 0 sha256:360be141b01f69b25427a9085b36ba8ad7d7a335449013fa6b32c1ecb894ab5b linux/amd64 2789669 jwe [jwe] + 1 sha256:ac601e66cdd275ee0e10afead03a2722e153a60982122d2d369880ea54fe82f8 linux/amd64 3174665 jwe [jwe] + 2 sha256:41e47064fd00424e328915ad2f7f716bd86ea2d0d8315edaf33ecaa6a2464530 linux/amd64 340 jwe [jwe] +``` + +Start a local image registry so we can push the encrypted image to it. A recent versions of the registry is required +to accept encrypted container images. +``` +# docker pull registry:latest +# docker run -d -p 5000:5000 --restart=always --name registry registry +``` + +Push the encrypted image to the local registry, pull it using `ctr-enc`, and then run the image. +``` +# $CTR images tag bash.enc:latest localhost:5000/bash.enc:latest +# $CTR images push localhost:5000/bash.enc:latest +# $CTR images rm localhost:5000/bash.enc:latest bash.enc:latest +# $CTR images pull localhost:5000/bash.enc:latest +# sudo $CTR run --rm localhost:5000/bash.enc:latest test echo 'Hello World!' +ctr: you are not authorized to use this image: missing private key needed for decryption +# sudo $CTR run --rm --key mykey.pem localhost:5000/bash.enc:latest test echo 'Hello World!' +Hello World! +``` + +## Project details + +**imgcrypt** is a non-core containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/client.go containerd-1.5.9/vendor/github.com/containerd/nri/client.go --- containerd-1.2.6/vendor/github.com/containerd/nri/client.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,196 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package nri + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os" + "os/exec" + "sync" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/oci" + types "github.com/containerd/nri/types/v1" + "github.com/pkg/errors" +) + +const ( + // DefaultBinaryPath for nri plugins + DefaultBinaryPath = "/opt/nri/bin" + // DefaultConfPath for the global nri configuration + DefaultConfPath = "/etc/nri/conf.json" + // Version of NRI + Version = "0.1" +) + +var appendPathOnce sync.Once + +// New nri client +func New() (*Client, error) { + conf, err := loadConfig(DefaultConfPath) + if err != nil { + return nil, err + } + + appendPathOnce.Do(func() { + err = os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), DefaultBinaryPath)) + }) + if err != nil { + return nil, err + } + + return &Client{ + conf: conf, + }, nil +} + +// Client for calling nri plugins +type Client struct { + conf *types.ConfigList +} + +// Sandbox information +type Sandbox struct { + // ID of the sandbox + ID string + // Labels of the sandbox + Labels map[string]string +} + +// Invoke the ConfList of nri plugins +func (c *Client) Invoke(ctx context.Context, task containerd.Task, state types.State) ([]*types.Result, error) { + return c.InvokeWithSandbox(ctx, task, state, nil) +} + +// InvokeWithSandbox invokes the ConfList of nri plugins +func (c *Client) InvokeWithSandbox(ctx context.Context, task containerd.Task, state types.State, sandbox *Sandbox) ([]*types.Result, error) { + if len(c.conf.Plugins) == 0 { + return nil, nil + } + spec, err := task.Spec(ctx) + if err != nil { + return nil, err + } + rs, err := createSpec(spec) + if err != nil { + return nil, err + } + r := &types.Request{ + Version: c.conf.Version, + ID: task.ID(), + Pid: int(task.Pid()), + State: state, + Spec: rs, + } + if sandbox != nil { + r.SandboxID = sandbox.ID + r.Labels = sandbox.Labels + } + for _, p := range c.conf.Plugins { + r.Conf = p.Conf + result, err := c.invokePlugin(ctx, p.Type, r) + if err != nil { + return nil, errors.Wrapf(err, "plugin: %s", p.Type) + } + r.Results = append(r.Results, result) + } + return r.Results, nil +} + +func (c *Client) invokePlugin(ctx context.Context, name string, r *types.Request) (*types.Result, error) { + payload, err := json.Marshal(r) + if err != nil { + return nil, err + } + cmd := exec.CommandContext(ctx, name, "invoke") + cmd.Stdin = bytes.NewBuffer(payload) + cmd.Stderr = os.Stderr + + out, err := cmd.Output() + msg := "output:" + if len(out) > 0 { + msg = fmt.Sprintf("%s %q", msg, out) + } else { + msg = fmt.Sprintf("%s ", msg) + } + if err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + // ExitError is returned when there is a non-zero exit status + msg = fmt.Sprintf("%s exit code: %d", msg, exitErr.ExitCode()) + } else { + // plugin did not get a chance to run, return exec err + return nil, err + } + } + var result types.Result + if err := json.Unmarshal(out, &result); err != nil { + return nil, errors.Errorf("failed to unmarshal plugin output: %s: %s", err.Error(), msg) + } + if result.Err() != nil { + return nil, result.Err() + } + return &result, nil +} + +func loadConfig(path string) (*types.ConfigList, error) { + f, err := os.Open(path) + if err != nil { + // if we don't have a config list on disk, create a new one for use + if os.IsNotExist(err) { + return &types.ConfigList{ + Version: Version, + }, nil + } + return nil, err + } + var c types.ConfigList + err = json.NewDecoder(f).Decode(&c) + f.Close() + if err != nil { + return nil, err + } + return &c, nil +} + +func createSpec(spec *oci.Spec) (*types.Spec, error) { + s := types.Spec{ + Namespaces: make(map[string]string), + Annotations: spec.Annotations, + } + switch { + case spec.Linux != nil: + s.CgroupsPath = spec.Linux.CgroupsPath + data, err := json.Marshal(spec.Linux.Resources) + if err != nil { + return nil, err + } + s.Resources = json.RawMessage(data) + for _, ns := range spec.Linux.Namespaces { + s.Namespaces[string(ns.Type)] = ns.Path + } + case spec.Windows != nil: + data, err := json.Marshal(spec.Windows.Resources) + if err != nil { + return nil, err + } + s.Resources = json.RawMessage(data) + } + return &s, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/.golangci.yml containerd-1.5.9/vendor/github.com/containerd/nri/.golangci.yml --- containerd-1.2.6/vendor/github.com/containerd/nri/.golangci.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/.golangci.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,22 @@ +linters: + enable: + - structcheck + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign + - vet + - unused + - misspell + disable: + - errcheck + +issues: + include: + - EXC0002 + +run: + timeout: 2m diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/go.mod containerd-1.5.9/vendor/github.com/containerd/nri/go.mod --- containerd-1.2.6/vendor/github.com/containerd/nri/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +module github.com/containerd/nri + +go 1.14 + +require ( + // when updating containerd, adjust the replace rules accordingly + github.com/containerd/containerd v1.5.0-beta.3 + github.com/pkg/errors v0.9.1 +) + +replace ( + github.com/gogo/googleapis => github.com/gogo/googleapis v1.3.2 + github.com/golang/protobuf => github.com/golang/protobuf v1.3.5 + google.golang.org/genproto => google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 + google.golang.org/grpc => google.golang.org/grpc v1.27.1 +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/go.sum containerd-1.5.9/vendor/github.com/containerd/nri/go.sum --- containerd-1.2.6/vendor/github.com/containerd/nri/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,786 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3 h1:mw6pDQqv38/WGF1cO/jF5t/jyAJ2yi7CmtFLLO5tGFI= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15 h1:Aof83YILRs2Vx3GhHqlvvfyx1asRJKMFIMeVlHsZKtI= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3 h1:4FA+QBaydEHlwxg0lMN3rhwoDaQy6LKhVWR4qvq4BuA= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0 h1:Fv93L3KKckEcEHR3oApXVzyBTDA8WAm6VXhPE00N3f8= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3 h1:hIqwXglcRyu4qbOmm+pBfQ1gf3wl3VziUAZED5ng2v8= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c h1:1c6xmkNiu6Jnr6AKGM91GGNsfU+nPNFvw9BZFSo0E+c= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328 h1:PRTagVMbJcCezLcHXe8UJvR1oBzp2lG3CEumeFOLOds= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1 h1:PvuK4E3D5S5q6IqsPDCy928FhP0LUIGcmZ/Yhgp5Djw= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c= +github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d h1:pNa8metDkwZjb9g4T8s+krQ+HRgZAkqnXml+wNir/+s= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 h1:YzfoEYWbODU5Fbt37+h7X16BWQbad7Q4S6gclTKFXM8= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/LICENSE containerd-1.5.9/vendor/github.com/containerd/nri/LICENSE --- containerd-1.2.6/vendor/github.com/containerd/nri/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/Makefile containerd-1.5.9/vendor/github.com/containerd/nri/Makefile --- containerd-1.2.6/vendor/github.com/containerd/nri/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: + go build -v diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/README.md containerd-1.5.9/vendor/github.com/containerd/nri/README.md --- containerd-1.2.6/vendor/github.com/containerd/nri/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,167 @@ +# nri - Node Resource Interface + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/nri)](https://pkg.go.dev/github.com/containerd/nri) +[![Build Status](https://github.com/containerd/nri/workflows/CI/badge.svg)](https://github.com/containerd/nri/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/containerd/nri/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/nri) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/nri)](https://goreportcard.com/report/github.com/containerd/nri) + +*This project is currently in DRAFT status* + +This project is a WIP for a new, CNI like, interface for managing resources on a node for Pods and Containers. + +## Documentation + +The basic interface, concepts and plugin design of the Container Network Interface (CNI) is an elegant way to handle multiple implementations of the network stack for containers. +This concept can be used for additional interfaces to customize a container's runtime environment. +This proposal covers a new interface for resource management on a node with a structured API and plugin design for containers. + +## Lifecycle + +The big selling point for CNI is that it has a structured interface for modifying the network namespace for a container. +This is different from generic hooks as they lack a type safe API injected into the lifecycle of a container. +The lifecycle point that CNI and NRI plugins will be injected into is the point between `Create` and `Start` of the container's init process. + +`Create->NRI->Start` + +## Configuration + +Configuration is split into two parts. One is the payload that is specific to a plugin invocation while the second is the host level configuration and options that specify what plugins to run and provide additional configuration to a plugin. + +### Filepath and Binaries + +Plugin binary paths can be configured via the consumer but will default to `/opt/nri/bin`. +Binaries are named with their type as the binary name, same as the CNI plugin naming scheme. + +### Host Level Config + +The config's default location will be `/etc/nri/resource.d/*.conf`. + +```json +{ + "version": "0.1", + "plugins": [ + { + "type": "konfine", + "conf": { + "systemReserved": [0, 1] + } + }, + { + "type": "clearcfs" + } + ] +} +``` + +### Input + +Input to a plugin is provided via `STDIN` as a `json` payload. + +```json +{ + "version": "0.1", + "state": "create", + "id": "redis", + "pid": 1234, + "spec": { + "resources": {}, + "cgroupsPath": "default/redis", + "namespaces": { + "pid": "/proc/44/ns/pid", + "mount": "/proc/44/ns/mnt", + "net": "/proc/44/ns/net" + }, + "annotations": { + "qos.class": "ls" + } + } +} +``` + +### Output + +```json +{ + "version": "0.1", + "state": "create", + "id": "redis", + "pid": 1234, + "cgroupsPath": "qos-ls/default/redis" +} +``` + +## Commands + +* Invoke - provides invocations into different lifecycle changes of a container + - states: `setup|pause|resume|update|delete` + +## Packages + +A Go based API and client package will be created for both producers of plugins and consumers, commonly being the container runtime (containerd). + +### Sample Plugin + +**clearcfs** + +Clear the cfs quotas for `ls` services. + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/containerd/containerd/pkg/nri/skel" + "github.com/containerd/containerd/pkg/nri/types" + "github.com/sirupsen/logrus" +) + +var max = []byte("max") + +// clearCFS clears any cfs quotas for the containers +type clearCFS struct { +} + +func (c *clearCFS) Type() string { + return "clearcfs" +} + +func (c *clearCFS) Invoke(ctx context.Context, r *types.Request) (*types.Result, error) { + result := r.NewResult() + if r.State != types.Create { + return result, nil + } + switch r.Spec.Annotations["qos.class"] { + case "ls": + logrus.Debugf("clearing cfs for %s", r.ID) + group, err := cg.Load(r.Spec.CgroupsPath) + if err != nil { + return nil, err + } + return result, group.Write(cg.CFSMax) + } + return result, nil +} + +func main() { + ctx := context.Background() + if err := skel.Run(ctx, &clearCFS{}); err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } +} +``` + +## Project details + +nri is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/nri/types/v1/types.go containerd-1.5.9/vendor/github.com/containerd/nri/types/v1/types.go --- containerd-1.2.6/vendor/github.com/containerd/nri/types/v1/types.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/nri/types/v1/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,133 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1 + +import ( + "encoding/json" + + "github.com/pkg/errors" +) + +// Plugin type and configuration +type Plugin struct { + // Type of plugin + Type string `json:"type"` + // Conf for the specific plugin + Conf json.RawMessage `json:"conf,omitempty"` +} + +// ConfigList for the global configuration of NRI +// +// Normally located at /etc/nri/conf.json +type ConfigList struct { + // Verion of the list + Version string `json:"version"` + // Plugins + Plugins []*Plugin `json:"plugins"` +} + +// Spec for the container being processed +type Spec struct { + // Resources struct from the OCI specification + // + // Can be WindowsResources or LinuxResources + Resources json.RawMessage `json:"resources"` + // Namespaces for the container + Namespaces map[string]string `json:"namespaces,omitempty"` + // CgroupsPath for the container + CgroupsPath string `json:"cgroupsPath,omitempty"` + // Annotations passed down to the OCI runtime specification + Annotations map[string]string `json:"annotations,omitempty"` +} + +// State of the request +type State string + +const ( + // Create the initial resource for the container + Create State = "create" + // Delete any resources for the container + Delete State = "delete" + // Update the resources for the container + Update State = "update" + // Pause action of the container + Pause State = "pause" + // Resume action for the container + Resume State = "resume" +) + +// Request for a plugin invocation +type Request struct { + // Conf specific for the plugin + Conf json.RawMessage `json:"conf,omitempty"` + + // Version of the plugin + Version string `json:"version"` + // State action for the request + State State `json:"state"` + // ID for the container + ID string `json:"id"` + // SandboxID for the sandbox that the request belongs to + // + // If ID and SandboxID are the same, this is a request for the sandbox + // SandboxID is empty for a non sandboxed container + SandboxID string `json:"sandboxID,omitempty"` + // Pid of the container + // + // -1 if there is no pid + Pid int `json:"pid,omitempty"` + // Spec generated from the OCI runtime specification + Spec *Spec `json:"spec"` + // Labels of a sandbox + Labels map[string]string `json:"labels,omitempty"` + // Results from previous plugins in the chain + Results []*Result `json:"results,omitempty"` +} + +// IsSandbox returns true if the request is for a sandbox +func (r *Request) IsSandbox() bool { + return r.ID == r.SandboxID +} + +// NewResult returns a result from the original request +func (r *Request) NewResult(plugin string) *Result { + return &Result{ + Plugin: plugin, + Version: r.Version, + Metadata: make(map[string]string), + } +} + +// Result of the plugin invocation +type Result struct { + // Plugin name that populated the result + Plugin string `json:"plugin"` + // Version of the plugin + Version string `json:"version"` + // Error message in case of failures + Error string `json:"error"` + // Metadata specific to actions taken by the plugin + Metadata map[string]string `json:"metadata,omitempty"` +} + +// Err creates an Error object if ErrorMessage is populated +func (r *Result) Err() error { + if r.Error != "" { + return errors.New(r.Error) + } + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/channel.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/channel.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/channel.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/channel.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,13 +18,12 @@ import ( "bufio" - "context" "encoding/binary" + "fmt" "io" "net" "sync" - "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -98,7 +97,7 @@ // returned will be valid and caller should send that along to // the correct consumer. The bytes on the underlying channel // will be discarded. -func (ch *channel) recv(ctx context.Context) (messageHeader, []byte, error) { +func (ch *channel) recv() (messageHeader, []byte, error) { mh, err := readMessageHeader(ch.hrbuf[:], ch.br) if err != nil { return messageHeader{}, nil, err @@ -106,7 +105,7 @@ if mh.Length > uint32(messageLengthMax) { if _, err := ch.br.Discard(int(mh.Length)); err != nil { - return mh, nil, errors.Wrapf(err, "failed to discard after receiving oversized message") + return mh, nil, fmt.Errorf("failed to discard after receiving oversized message: %w", err) } return mh, nil, status.Errorf(codes.ResourceExhausted, "message length %v exceed maximum message size of %v", mh.Length, messageLengthMax) @@ -114,13 +113,13 @@ p := ch.getmbuf(int(mh.Length)) if _, err := io.ReadFull(ch.br, p); err != nil { - return messageHeader{}, nil, errors.Wrapf(err, "failed reading message") + return messageHeader{}, nil, fmt.Errorf("failed reading message: %w", err) } return mh, p, nil } -func (ch *channel) send(ctx context.Context, streamID uint32, t messageType, p []byte) error { +func (ch *channel) send(streamID uint32, t messageType, p []byte) error { if err := writeMessageHeader(ch.bw, ch.hwbuf[:], messageHeader{Length: uint32(len(p)), StreamID: streamID, Type: t}); err != nil { return err } diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/client.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/client.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/client.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/client.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,16 +18,18 @@ import ( "context" + "errors" "io" "net" "os" "strings" "sync" "syscall" + "time" "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -35,28 +37,58 @@ // closed. var ErrClosed = errors.New("ttrpc: closed") +// Client for a ttrpc server type Client struct { codec codec conn net.Conn channel *channel calls chan *callRequest - closed chan struct{} - closeOnce sync.Once - closeFunc func() - done chan struct{} - err error + ctx context.Context + closed func() + + closeOnce sync.Once + userCloseFunc func() + userCloseWaitCh chan struct{} + + errOnce sync.Once + err error + interceptor UnaryClientInterceptor +} + +// ClientOpts configures a client +type ClientOpts func(c *Client) + +// WithOnClose sets the close func whenever the client's Close() method is called +func WithOnClose(onClose func()) ClientOpts { + return func(c *Client) { + c.userCloseFunc = onClose + } } -func NewClient(conn net.Conn) *Client { +// WithUnaryClientInterceptor sets the provided client interceptor +func WithUnaryClientInterceptor(i UnaryClientInterceptor) ClientOpts { + return func(c *Client) { + c.interceptor = i + } +} + +func NewClient(conn net.Conn, opts ...ClientOpts) *Client { + ctx, cancel := context.WithCancel(context.Background()) c := &Client{ - codec: codec{}, - conn: conn, - channel: newChannel(conn), - calls: make(chan *callRequest), - closed: make(chan struct{}), - done: make(chan struct{}), - closeFunc: func() {}, + codec: codec{}, + conn: conn, + channel: newChannel(conn), + calls: make(chan *callRequest), + closed: cancel, + ctx: ctx, + userCloseFunc: func() {}, + userCloseWaitCh: make(chan struct{}), + interceptor: defaultClientInterceptor, + } + + for _, o := range opts { + o(c) } go c.run() @@ -86,7 +118,18 @@ cresp = &Response{} ) - if err := c.dispatch(ctx, creq, cresp); err != nil { + if metadata, ok := GetMetadata(ctx); ok { + metadata.setRequest(creq) + } + + if dl, ok := ctx.Deadline(); ok { + creq.TimeoutNano = dl.Sub(time.Now()).Nanoseconds() + } + + info := &UnaryClientInfo{ + FullMethod: fullPath(service, method), + } + if err := c.interceptor(ctx, creq, cresp, info, c.dispatch); err != nil { return err } @@ -94,16 +137,16 @@ return err } - if cresp.Status == nil { - return errors.New("no status provided on response") + if cresp.Status != nil && cresp.Status.Code != int32(codes.OK) { + return status.ErrorProto(cresp.Status) } - - return status.ErrorProto(cresp.Status) + return nil } func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error { errs := make(chan error, 1) call := &callRequest{ + ctx: ctx, req: req, resp: resp, errs: errs, @@ -113,8 +156,8 @@ case <-ctx.Done(): return ctx.Err() case c.calls <- call: - case <-c.done: - return c.err + case <-c.ctx.Done(): + return c.error() } select { @@ -122,22 +165,27 @@ return ctx.Err() case err := <-errs: return filterCloseErr(err) - case <-c.done: - return c.err + case <-c.ctx.Done(): + return c.error() } } func (c *Client) Close() error { c.closeOnce.Do(func() { - close(c.closed) + c.closed() }) - return nil } -// OnClose allows a close func to be called when the server is closed -func (c *Client) OnClose(closer func()) { - c.closeFunc = closer +// UserOnCloseWait is used to blocks untils the user's on-close callback +// finishes. +func (c *Client) UserOnCloseWait(ctx context.Context) error { + select { + case <-c.userCloseWaitCh: + return nil + case <-ctx.Done(): + return ctx.Err() + } } type message struct { @@ -146,101 +194,175 @@ err error } +// callMap provides access to a map of active calls, guarded by a mutex. +type callMap struct { + m sync.Mutex + activeCalls map[uint32]*callRequest + closeErr error +} + +// newCallMap returns a new callMap with an empty set of active calls. +func newCallMap() *callMap { + return &callMap{ + activeCalls: make(map[uint32]*callRequest), + } +} + +// set adds a call entry to the map with the given streamID key. +func (cm *callMap) set(streamID uint32, cr *callRequest) error { + cm.m.Lock() + defer cm.m.Unlock() + if cm.closeErr != nil { + return cm.closeErr + } + cm.activeCalls[streamID] = cr + return nil +} + +// get looks up the call entry for the given streamID key, then removes it +// from the map and returns it. +func (cm *callMap) get(streamID uint32) (cr *callRequest, ok bool, err error) { + cm.m.Lock() + defer cm.m.Unlock() + if cm.closeErr != nil { + return nil, false, cm.closeErr + } + cr, ok = cm.activeCalls[streamID] + if ok { + delete(cm.activeCalls, streamID) + } + return +} + +// abort sends the given error to each active call, and clears the map. +// Once abort has been called, any subsequent calls to the callMap will return the error passed to abort. +func (cm *callMap) abort(err error) error { + cm.m.Lock() + defer cm.m.Unlock() + if cm.closeErr != nil { + return cm.closeErr + } + for streamID, call := range cm.activeCalls { + call.errs <- err + delete(cm.activeCalls, streamID) + } + cm.closeErr = err + return nil +} + func (c *Client) run() { var ( - streamID uint32 = 1 - waiters = make(map[uint32]*callRequest) - calls = c.calls - incoming = make(chan *message) - shutdown = make(chan struct{}) - shutdownErr error + waiters = newCallMap() + receiverDone = make(chan struct{}) ) + // Sender goroutine + // Receives calls from dispatch, adds them to the set of active calls, and sends them + // to the server. go func() { - defer close(shutdown) - - // start one more goroutine to recv messages without blocking. + var streamID uint32 = 1 for { - mh, p, err := c.channel.recv(context.TODO()) - if err != nil { - _, ok := status.FromError(err) - if !ok { - // treat all errors that are not an rpc status as terminal. - // all others poison the connection. - shutdownErr = err - return + select { + case <-c.ctx.Done(): + return + case call := <-c.calls: + id := streamID + streamID += 2 // enforce odd client initiated request ids + if err := waiters.set(id, call); err != nil { + call.errs <- err // errs is buffered so should not block. + continue + } + if err := c.send(id, messageTypeRequest, call.req); err != nil { + call.errs <- err // errs is buffered so should not block. + waiters.get(id) // remove from waiters set } } + } + }() + + // Receiver goroutine + // Receives responses from the server, looks up the call info in the set of active calls, + // and notifies the caller of the response. + go func() { + defer close(receiverDone) + for { select { - case incoming <- &message{ - messageHeader: mh, - p: p[:mh.Length], - err: err, - }: - case <-c.done: + case <-c.ctx.Done(): + c.setError(c.ctx.Err()) return + default: + mh, p, err := c.channel.recv() + if err != nil { + _, ok := status.FromError(err) + if !ok { + // treat all errors that are not an rpc status as terminal. + // all others poison the connection. + c.setError(filterCloseErr(err)) + return + } + } + msg := &message{ + messageHeader: mh, + p: p[:mh.Length], + err: err, + } + call, ok, err := waiters.get(mh.StreamID) + if err != nil { + logrus.Errorf("ttrpc: failed to look up active call: %s", err) + continue + } + if !ok { + logrus.Errorf("ttrpc: received message for unknown channel %v", mh.StreamID) + continue + } + call.errs <- c.recv(call.resp, msg) } } }() - defer c.conn.Close() - defer close(c.done) - defer c.closeFunc() + defer func() { + c.conn.Close() + c.userCloseFunc() + close(c.userCloseWaitCh) + }() for { select { - case call := <-calls: - if err := c.send(call.ctx, streamID, messageTypeRequest, call.req); err != nil { - call.errs <- err - continue - } - - waiters[streamID] = call - streamID += 2 // enforce odd client initiated request ids - case msg := <-incoming: - call, ok := waiters[msg.StreamID] - if !ok { - logrus.Errorf("ttrpc: received message for unknown channel %v", msg.StreamID) - continue - } - - call.errs <- c.recv(call.resp, msg) - delete(waiters, msg.StreamID) - case <-shutdown: - if shutdownErr != nil { - shutdownErr = filterCloseErr(shutdownErr) - } else { - shutdownErr = ErrClosed - } - - shutdownErr = errors.Wrapf(shutdownErr, "ttrpc: client shutting down") - - c.err = shutdownErr - for _, waiter := range waiters { - waiter.errs <- shutdownErr - } + case <-receiverDone: + // The receiver has exited. + // don't return out, let the close of the context trigger the abort of waiters c.Close() - return - case <-c.closed: - if c.err == nil { - c.err = ErrClosed - } - // broadcast the shutdown error to the remaining waiters. - for _, waiter := range waiters { - waiter.errs <- c.err - } + case <-c.ctx.Done(): + // Abort all active calls. This will also prevent any new calls from being added + // to waiters. + waiters.abort(c.error()) return } } } -func (c *Client) send(ctx context.Context, streamID uint32, mtype messageType, msg interface{}) error { +func (c *Client) error() error { + c.errOnce.Do(func() { + if c.err == nil { + c.err = ErrClosed + } + }) + return c.err +} + +func (c *Client) setError(err error) { + c.errOnce.Do(func() { + c.err = err + }) +} + +func (c *Client) send(streamID uint32, mtype messageType, msg interface{}) error { p, err := c.codec.Marshal(msg) if err != nil { return err } - return c.channel.send(ctx, streamID, mtype, p) + return c.channel.send(streamID, mtype, p) } func (c *Client) recv(resp *Response, msg *message) error { @@ -249,7 +371,7 @@ } if msg.Type != messageTypeResponse { - return errors.New("unkown message type received") + return errors.New("unknown message type received") } defer c.channel.putmbuf(msg.p) @@ -261,22 +383,25 @@ // // This purposely ignores errors with a wrapped cause. func filterCloseErr(err error) error { - if err == nil { + switch { + case err == nil: return nil - } - - if err == io.EOF { + case err == io.EOF: return ErrClosed - } - - if strings.Contains(err.Error(), "use of closed network connection") { + case errors.Is(err, io.EOF): return ErrClosed - } + case strings.Contains(err.Error(), "use of closed network connection"): + return ErrClosed + default: + // if we have an epipe on a write or econnreset on a read , we cast to errclosed + var oerr *net.OpError + if errors.As(err, &oerr) && (oerr.Op == "write" || oerr.Op == "read") { + serr, sok := oerr.Err.(*os.SyscallError) + if sok && ((serr.Err == syscall.EPIPE && oerr.Op == "write") || + (serr.Err == syscall.ECONNRESET && oerr.Op == "read")) { - // if we have an epipe on a write, we cast to errclosed - if oerr, ok := err.(*net.OpError); ok && oerr.Op == "write" { - if serr, ok := oerr.Err.(*os.SyscallError); ok && serr.Err == syscall.EPIPE { - return ErrClosed + return ErrClosed + } } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/codec.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/codec.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/codec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/codec.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,8 +17,9 @@ package ttrpc import ( + "fmt" + "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" ) type codec struct{} @@ -28,7 +29,7 @@ case proto.Message: return proto.Marshal(v) default: - return nil, errors.Errorf("ttrpc: cannot marshal unknown type: %T", msg) + return nil, fmt.Errorf("ttrpc: cannot marshal unknown type: %T", msg) } } @@ -37,6 +38,6 @@ case proto.Message: return proto.Unmarshal(p, v) default: - return errors.Errorf("ttrpc: cannot unmarshal into unknown type: %T", msg) + return fmt.Errorf("ttrpc: cannot unmarshal into unknown type: %T", msg) } } diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/config.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/config.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/config.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,12 +16,14 @@ package ttrpc -import "github.com/pkg/errors" +import "errors" type serverConfig struct { - handshaker Handshaker + handshaker Handshaker + interceptor UnaryServerInterceptor } +// ServerOpt for configuring a ttrpc server type ServerOpt func(*serverConfig) error // WithServerHandshaker can be passed to NewServer to ensure that the @@ -37,3 +39,14 @@ return nil } } + +// WithUnaryServerInterceptor sets the provided interceptor on the server +func WithUnaryServerInterceptor(i UnaryServerInterceptor) ServerOpt { + return func(c *serverConfig) error { + if c.interceptor != nil { + return errors.New("only one interceptor allowed per server") + } + c.interceptor = i + return nil + } +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/.gitignore containerd-1.5.9/vendor/github.com/containerd/ttrpc/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/go.mod containerd-1.5.9/vendor/github.com/containerd/ttrpc/go.mod --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,13 @@ +module github.com/containerd/ttrpc + +go 1.13 + +require ( + github.com/gogo/protobuf v1.3.2 + github.com/prometheus/procfs v0.6.0 + github.com/sirupsen/logrus v1.8.1 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c + google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 + google.golang.org/grpc v1.27.1 + google.golang.org/protobuf v1.27.1 +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/go.sum containerd-1.5.9/vendor/github.com/containerd/ttrpc/go.sum --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,99 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 h1:YzfoEYWbODU5Fbt37+h7X16BWQbad7Q4S6gclTKFXM8= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/interceptor.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/interceptor.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/interceptor.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/interceptor.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,50 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ttrpc + +import "context" + +// UnaryServerInfo provides information about the server request +type UnaryServerInfo struct { + FullMethod string +} + +// UnaryClientInfo provides information about the client request +type UnaryClientInfo struct { + FullMethod string +} + +// Unmarshaler contains the server request data and allows it to be unmarshaled +// into a concrete type +type Unmarshaler func(interface{}) error + +// Invoker invokes the client's request and response from the ttrpc server +type Invoker func(context.Context, *Request, *Response) error + +// UnaryServerInterceptor specifies the interceptor function for server request/response +type UnaryServerInterceptor func(context.Context, Unmarshaler, *UnaryServerInfo, Method) (interface{}, error) + +// UnaryClientInterceptor specifies the interceptor function for client request/response +type UnaryClientInterceptor func(context.Context, *Request, *Response, *UnaryClientInfo, Invoker) error + +func defaultServerInterceptor(ctx context.Context, unmarshal Unmarshaler, info *UnaryServerInfo, method Method) (interface{}, error) { + return method(ctx, unmarshal) +} + +func defaultClientInterceptor(ctx context.Context, req *Request, resp *Response, _ *UnaryClientInfo, invoker Invoker) error { + return invoker(ctx, req, resp) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/metadata.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/metadata.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/metadata.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/metadata.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,107 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ttrpc + +import ( + "context" + "strings" +) + +// MD is the user type for ttrpc metadata +type MD map[string][]string + +// Get returns the metadata for a given key when they exist. +// If there is no metadata, a nil slice and false are returned. +func (m MD) Get(key string) ([]string, bool) { + key = strings.ToLower(key) + list, ok := m[key] + if !ok || len(list) == 0 { + return nil, false + } + + return list, true +} + +// Set sets the provided values for a given key. +// The values will overwrite any existing values. +// If no values provided, a key will be deleted. +func (m MD) Set(key string, values ...string) { + key = strings.ToLower(key) + if len(values) == 0 { + delete(m, key) + return + } + m[key] = values +} + +// Append appends additional values to the given key. +func (m MD) Append(key string, values ...string) { + key = strings.ToLower(key) + if len(values) == 0 { + return + } + current, ok := m[key] + if ok { + m.Set(key, append(current, values...)...) + } else { + m.Set(key, values...) + } +} + +func (m MD) setRequest(r *Request) { + for k, values := range m { + for _, v := range values { + r.Metadata = append(r.Metadata, &KeyValue{ + Key: k, + Value: v, + }) + } + } +} + +func (m MD) fromRequest(r *Request) { + for _, kv := range r.Metadata { + m[kv.Key] = append(m[kv.Key], kv.Value) + } +} + +type metadataKey struct{} + +// GetMetadata retrieves metadata from context.Context (previously attached with WithMetadata) +func GetMetadata(ctx context.Context) (MD, bool) { + metadata, ok := ctx.Value(metadataKey{}).(MD) + return metadata, ok +} + +// GetMetadataValue gets a specific metadata value by name from context.Context +func GetMetadataValue(ctx context.Context, name string) (string, bool) { + metadata, ok := GetMetadata(ctx) + if !ok { + return "", false + } + + if list, ok := metadata.Get(name); ok { + return list[0], true + } + + return "", false +} + +// WithMetadata attaches metadata map to a context.Context +func WithMetadata(ctx context.Context, md MD) context.Context { + return context.WithValue(ctx, metadataKey{}, md) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/README.md containerd-1.5.9/vendor/github.com/containerd/ttrpc/README.md --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,7 @@ # ttrpc -[![Build Status](https://travis-ci.org/containerd/ttrpc.svg?branch=master)](https://travis-ci.org/containerd/ttrpc) +[![Build Status](https://github.com/containerd/ttrpc/workflows/CI/badge.svg)](https://github.com/containerd/ttrpc/actions?query=workflow%3ACI) +[![codecov](https://codecov.io/gh/containerd/ttrpc/branch/main/graph/badge.svg)](https://codecov.io/gh/containerd/ttrpc) GRPC for low-memory environments. @@ -40,13 +41,18 @@ # Status -Very new. YMMV. - TODO: -- [X] Plumb error codes and GRPC status -- [X] Remove use of any type and dependency on typeurl package -- [X] Ensure that protocol can support streaming in the future - [ ] Document protocol layout - [ ] Add testing under concurrent load to ensure - [ ] Verify connection error handling + +# Project details + +ttrpc is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/server.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/server.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/server.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/server.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ import ( "context" + "errors" "io" "math/rand" "net" @@ -25,7 +26,6 @@ "sync/atomic" "time" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -53,10 +53,13 @@ return nil, err } } + if config.interceptor == nil { + config.interceptor = defaultServerInterceptor + } return &Server{ config: config, - services: newServiceSet(), + services: newServiceSet(config.interceptor), done: make(chan struct{}), listeners: make(map[net.Listener]struct{}), connections: make(map[*serverConn]struct{}), @@ -206,6 +209,20 @@ s.connections[c] = struct{}{} } +func (s *Server) delConnection(c *serverConn) { + s.mu.Lock() + defer s.mu.Unlock() + + delete(s.connections, c) +} + +func (s *Server) countConnection() int { + s.mu.Lock() + defer s.mu.Unlock() + + return len(s.connections) +} + func (s *Server) closeIdleConns() bool { s.mu.Lock() defer s.mu.Unlock() @@ -310,6 +327,7 @@ defer c.conn.Close() defer cancel() defer close(done) + defer c.server.delConnection(c) go func(recvErr chan error) { defer close(recvErr) @@ -341,7 +359,7 @@ default: // proceed } - mh, p, err := ch.recv(ctx) + mh, p, err := ch.recv() if err != nil { status, ok := status.FromError(err) if !ok { @@ -414,6 +432,9 @@ case request := <-requests: active++ go func(id uint32) { + ctx, cancel := getRequestContext(ctx, request.req) + defer cancel() + p, status := c.server.services.call(ctx, request.req.Service, request.req.Method, request.req.Payload) resp := &Response{ Status: status.Proto(), @@ -435,7 +456,7 @@ return } - if err := ch.send(ctx, response.id, messageTypeResponse, p); err != nil { + if err := ch.send(response.id, messageTypeResponse, p); err != nil { logrus.WithError(err).Error("failed sending message on channel") return } @@ -446,7 +467,12 @@ // branch. Basically, it means that we are no longer receiving // requests due to a terminal error. recvErr = nil // connection is now "closing" - if err != nil && err != io.EOF { + if err == io.EOF || err == io.ErrUnexpectedEOF { + // The client went away and we should stop processing + // requests, so that the client connection is closed + return + } + if err != nil { logrus.WithError(err).Error("error receiving message") } case <-shutdown: @@ -454,3 +480,21 @@ } } } + +var noopFunc = func() {} + +func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) { + if len(req.Metadata) > 0 { + md := MD{} + md.fromRequest(req) + ctx = WithMetadata(ctx, md) + } + + cancel = noopFunc + if req.TimeoutNano == 0 { + return ctx, cancel + } + + ctx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutNano)) + return ctx, cancel +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/services.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/services.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/services.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/services.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,12 +18,14 @@ import ( "context" + "errors" + "fmt" "io" "os" "path" + "unsafe" "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -37,18 +39,20 @@ } type serviceSet struct { - services map[string]ServiceDesc + services map[string]ServiceDesc + interceptor UnaryServerInterceptor } -func newServiceSet() *serviceSet { +func newServiceSet(interceptor UnaryServerInterceptor) *serviceSet { return &serviceSet{ - services: make(map[string]ServiceDesc), + services: make(map[string]ServiceDesc), + interceptor: interceptor, } } func (s *serviceSet) register(name string, methods map[string]Method) { if _, ok := s.services[name]; ok { - panic(errors.Errorf("duplicate service %v registered", name)) + panic(fmt.Errorf("duplicate service %v registered", name)) } s.services[name] = ServiceDesc{ @@ -76,7 +80,7 @@ switch v := obj.(type) { case proto.Message: if err := proto.Unmarshal(p, v); err != nil { - return status.Errorf(codes.Internal, "ttrpc: error unmarshaling payload: %v", err.Error()) + return status.Errorf(codes.Internal, "ttrpc: error unmarshalling payload: %v", err.Error()) } default: return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v) @@ -84,11 +88,19 @@ return nil } - resp, err := method(ctx, unmarshal) + info := &UnaryServerInfo{ + FullMethod: fullPath(serviceName, methodName), + } + + resp, err := s.interceptor(ctx, unmarshal, info, method) if err != nil { return nil, err } + if isNil(resp) { + return nil, errors.New("ttrpc: marshal called with nil") + } + switch v := resp.(type) { case proto.Message: r, err := proto.Marshal(v) @@ -105,12 +117,12 @@ func (s *serviceSet) resolve(service, method string) (Method, error) { srv, ok := s.services[service] if !ok { - return nil, status.Errorf(codes.NotFound, "service %v", service) + return nil, status.Errorf(codes.Unimplemented, "service %v", service) } mthd, ok := srv.Methods[method] if !ok { - return nil, status.Errorf(codes.NotFound, "method %v", method) + return nil, status.Errorf(codes.Unimplemented, "method %v", method) } return mthd, nil @@ -146,5 +158,9 @@ } func fullPath(service, method string) string { - return "/" + path.Join("/", service, method) + return "/" + path.Join(service, method) +} + +func isNil(resp interface{}) bool { + return (*[2]uintptr)(unsafe.Pointer(&resp))[1] == 0 } diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/types.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/types.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -23,9 +23,11 @@ ) type Request struct { - Service string `protobuf:"bytes,1,opt,name=service,proto3"` - Method string `protobuf:"bytes,2,opt,name=method,proto3"` - Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"` + Service string `protobuf:"bytes,1,opt,name=service,proto3"` + Method string `protobuf:"bytes,2,opt,name=method,proto3"` + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"` + TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,proto3"` + Metadata []*KeyValue `protobuf:"bytes,5,rep,name=metadata,proto3"` } func (r *Request) Reset() { *r = Request{} } @@ -40,3 +42,22 @@ func (r *Response) Reset() { *r = Response{} } func (r *Response) String() string { return fmt.Sprintf("%+#v", r) } func (r *Response) ProtoMessage() {} + +type StringList struct { + List []string `protobuf:"bytes,1,rep,name=list,proto3"` +} + +func (r *StringList) Reset() { *r = StringList{} } +func (r *StringList) String() string { return fmt.Sprintf("%+#v", r) } +func (r *StringList) ProtoMessage() {} + +func makeStringList(item ...string) StringList { return StringList{List: item} } + +type KeyValue struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3"` + Value string `protobuf:"bytes,2,opt,name=value,proto3"` +} + +func (m *KeyValue) Reset() { *m = KeyValue{} } +func (*KeyValue) ProtoMessage() {} +func (m *KeyValue) String() string { return fmt.Sprintf("%+#v", m) } diff -Nru containerd-1.2.6/vendor/github.com/containerd/ttrpc/unixcreds_linux.go containerd-1.5.9/vendor/github.com/containerd/ttrpc/unixcreds_linux.go --- containerd-1.2.6/vendor/github.com/containerd/ttrpc/unixcreds_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/ttrpc/unixcreds_linux.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,11 +18,12 @@ import ( "context" + "errors" + "fmt" "net" "os" "syscall" - "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -31,12 +32,12 @@ func (fn UnixCredentialsFunc) Handshake(ctx context.Context, conn net.Conn) (net.Conn, interface{}, error) { uc, err := requireUnixSocket(conn) if err != nil { - return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: require unix socket") + return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: require unix socket: %w", err) } rs, err := uc.SyscallConn() if err != nil { - return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed") + return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed: %w", err) } var ( ucred *unix.Ucred @@ -45,15 +46,15 @@ if err := rs.Control(func(fd uintptr) { ucred, ucredErr = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED) }); err != nil { - return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed") + return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed: %w", err) } if ucredErr != nil { - return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials") + return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials: %w", err) } if err := fn(ucred); err != nil { - return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: credential check failed") + return nil, nil, fmt.Errorf("ttrpc.UnixCredentialsFunc: credential check failed: %w", err) } return uc, ucred, nil @@ -93,7 +94,7 @@ func requireUidGid(ucred *unix.Ucred, uid, gid int) error { if (uid != -1 && uint32(uid) != ucred.Uid) || (gid != -1 && uint32(gid) != ucred.Gid) { - return errors.Wrap(syscall.EPERM, "ttrpc: invalid credentials") + return fmt.Errorf("ttrpc: invalid credentials: %v", syscall.EPERM) } return nil } diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/doc.go containerd-1.5.9/vendor/github.com/containerd/typeurl/doc.go --- containerd-1.2.6/vendor/github.com/containerd/typeurl/doc.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/doc.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package typeurl + +// Package typeurl assists with managing the registration, marshaling, and +// unmarshaling of types encoded as protobuf.Any. +// +// A protobuf.Any is a proto message that can contain any arbitrary data. It +// consists of two components, a TypeUrl and a Value, and its proto definition +// looks like this: +// +// message Any { +// string type_url = 1; +// bytes value = 2; +// } +// +// The TypeUrl is used to distinguish the contents from other proto.Any +// messages. This typeurl library manages these URLs to enable automagic +// marshaling and unmarshaling of the contents. +// +// For example, consider this go struct: +// +// type Foo struct { +// Field1 string +// Field2 string +// } +// +// To use typeurl, types must first be registered. This is typically done in +// the init function +// +// func init() { +// typeurl.Register(&Foo{}, "Foo") +// } +// +// This will register the type Foo with the url path "Foo". The arguments to +// Register are variadic, and are used to construct a url path. Consider this +// example, from the github.com/containerd/containerd/client package: +// +// func init() { +// const prefix = "types.containerd.io" +// // register TypeUrls for commonly marshaled external types +// major := strconv.Itoa(specs.VersionMajor) +// typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec") +// // this function has more Register calls, which are elided. +// } +// +// This registers several types under a more complex url, which ends up mapping +// to `types.containerd.io/opencontainers/runtime-spec/1/Spec` (or some other +// value for major). +// +// Once a type is registered, it can be marshaled to a proto.Any message simply +// by calling `MarshalAny`, like this: +// +// foo := &Foo{Field1: "value1", Field2: "value2"} +// anyFoo, err := typeurl.MarshalAny(foo) +// +// MarshalAny will resolve the correct URL for the type. If the type in +// question implements the proto.Message interface, then it will be marshaled +// as a proto message. Otherwise, it will be marshaled as json. This means that +// typeurl will work on any arbitrary data, whether or not it has a proto +// definition, as long as it can be serialized to json. +// +// To unmarshal, the process is simply inverse: +// +// iface, err := typeurl.UnmarshalAny(anyFoo) +// foo := iface.(*Foo) +// +// The correct type is automatically chosen from the type registry, and the +// returned interface can be cast straight to that type. diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/.gitignore containerd-1.5.9/vendor/github.com/containerd/typeurl/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/typeurl/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +*.test +coverage.txt diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/go.mod containerd-1.5.9/vendor/github.com/containerd/typeurl/go.mod --- containerd-1.2.6/vendor/github.com/containerd/typeurl/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,8 @@ +module github.com/containerd/typeurl + +go 1.13 + +require ( + github.com/gogo/protobuf v1.3.2 + github.com/pkg/errors v0.9.1 +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/go.sum containerd-1.5.9/vendor/github.com/containerd/typeurl/go.sum --- containerd-1.2.6/vendor/github.com/containerd/typeurl/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,33 @@ +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/LICENSE containerd-1.5.9/vendor/github.com/containerd/typeurl/LICENSE --- containerd-1.2.6/vendor/github.com/containerd/typeurl/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -1,6 +1,7 @@ + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -175,24 +176,13 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] + Copyright The containerd Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + 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, diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/README.md containerd-1.5.9/vendor/github.com/containerd/typeurl/README.md --- containerd-1.2.6/vendor/github.com/containerd/typeurl/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -1,9 +1,20 @@ # typeurl -[![Build Status](https://travis-ci.org/containerd/typeurl.svg?branch=master)](https://travis-ci.org/containerd/typeurl) - +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/typeurl)](https://pkg.go.dev/github.com/containerd/typeurl) +[![Build Status](https://github.com/containerd/typeurl/workflows/CI/badge.svg)](https://github.com/containerd/typeurl/actions?query=workflow%3ACI) [![codecov](https://codecov.io/gh/containerd/typeurl/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/typeurl) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/typeurl)](https://goreportcard.com/report/github.com/containerd/typeurl) A Go package for managing the registration, marshaling, and unmarshaling of encoded types. -This package helps when types are sent over a GRPC API and marshaled as a [protobuf.Any](). +This package helps when types are sent over a GRPC API and marshaled as a [protobuf.Any](https://github.com/gogo/protobuf/blob/master/protobuf/google/protobuf/any.proto). + +## Project details + +**typeurl** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/typeurl/types.go containerd-1.5.9/vendor/github.com/containerd/typeurl/types.go --- containerd-1.2.6/vendor/github.com/containerd/typeurl/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/typeurl/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -28,13 +28,25 @@ ) var ( - mu sync.Mutex + mu sync.RWMutex registry = make(map[reflect.Type]string) ) -var ErrNotFound = errors.New("not found") +// Definitions of common error types used throughout typeurl. +// +// These error types are used with errors.Wrap and errors.Wrapf to add context +// to an error. +// +// To detect an error class, use errors.Is() functions to tell whether an +// error is of this type. +var ( + ErrNotFound = errors.New("not found") +) -// Register a type with the base url of the type +// Register a type with a base URL for JSON marshaling. When the MarshalAny and +// UnmarshalAny functions are called they will treat the Any type value as JSON. +// To use protocol buffers for handling the Any value the proto.Register +// function should be used instead of this function. func Register(v interface{}, args ...string) { var ( t = tryDereference(v) @@ -44,18 +56,18 @@ defer mu.Unlock() if et, ok := registry[t]; ok { if et != p { - panic(errors.Errorf("type registred with alternate path %q != %q", et, p)) + panic(errors.Errorf("type registered with alternate path %q != %q", et, p)) } return } registry[t] = p } -// TypeURL returns the type url for a registred type +// TypeURL returns the type url for a registered type. func TypeURL(v interface{}) (string, error) { - mu.Lock() + mu.RLock() u, ok := registry[tryDereference(v)] - mu.Unlock() + mu.RUnlock() if !ok { // fallback to the proto registry if it is a proto message pb, ok := v.(proto.Message) @@ -67,7 +79,7 @@ return u, nil } -// Is returns true if the type of the Any is the same as v +// Is returns true if the type of the Any is the same as v. func Is(any *types.Any, v interface{}) bool { // call to check that v is a pointer tryDereference(v) @@ -78,7 +90,10 @@ return any.TypeUrl == url } -// MarshalAny marshals the value v into an any with the correct TypeUrl +// MarshalAny marshals the value v into an any with the correct TypeUrl. +// If the provided object is already a proto.Any message, then it will be +// returned verbatim. If it is of type proto.Message, it will be marshaled as a +// protocol buffer. Otherwise, the object will be marshaled to json. func MarshalAny(v interface{}) (*types.Any, error) { var marshal func(v interface{}) ([]byte, error) switch t := v.(type) { @@ -108,18 +123,56 @@ }, nil } -// UnmarshalAny unmarshals the any type into a concrete type +// UnmarshalAny unmarshals the any type into a concrete type. func UnmarshalAny(any *types.Any) (interface{}, error) { - t, err := getTypeByUrl(any.TypeUrl) + return UnmarshalByTypeURL(any.TypeUrl, any.Value) +} + +// UnmarshalByTypeURL unmarshals the given type and value to into a concrete type. +func UnmarshalByTypeURL(typeURL string, value []byte) (interface{}, error) { + return unmarshal(typeURL, value, nil) +} + +// UnmarshalTo unmarshals the any type into a concrete type passed in the out +// argument. It is identical to UnmarshalAny, but lets clients provide a +// destination type through the out argument. +func UnmarshalTo(any *types.Any, out interface{}) error { + return UnmarshalToByTypeURL(any.TypeUrl, any.Value, out) +} + +// UnmarshalTo unmarshals the given type and value into a concrete type passed +// in the out argument. It is identical to UnmarshalByTypeURL, but lets clients +// provide a destination type through the out argument. +func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error { + _, err := unmarshal(typeURL, value, out) + return err +} + +func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) { + t, err := getTypeByUrl(typeURL) if err != nil { return nil, err } - v := reflect.New(t.t).Interface() + + if v == nil { + v = reflect.New(t.t).Interface() + } else { + // Validate interface type provided by client + vURL, err := TypeURL(v) + if err != nil { + return nil, err + } + if typeURL != vURL { + return nil, errors.Errorf("can't unmarshal type %q to output %q", typeURL, vURL) + } + } + if t.isProto { - err = proto.Unmarshal(any.Value, v.(proto.Message)) + err = proto.Unmarshal(value, v.(proto.Message)) } else { - err = json.Unmarshal(any.Value, v) + err = json.Unmarshal(value, v) } + return v, err } @@ -129,13 +182,16 @@ } func getTypeByUrl(url string) (urlType, error) { + mu.RLock() for t, u := range registry { if u == url { + mu.RUnlock() return urlType{ t: t, }, nil } } + mu.RUnlock() // fallback to proto registry t := proto.MessageType(url) if t != nil { diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/codecov.yml containerd-1.5.9/vendor/github.com/containerd/zfs/codecov.yml --- containerd-1.2.6/vendor/github.com/containerd/zfs/codecov.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/codecov.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +comment: false diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/.gitignore containerd-1.5.9/vendor/github.com/containerd/zfs/.gitignore --- containerd-1.2.6/vendor/github.com/containerd/zfs/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,4 @@ +*.test + +# Support running go modules in vendor mode for local development +/vendor/ diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/go.mod containerd-1.5.9/vendor/github.com/containerd/zfs/go.mod --- containerd-1.2.6/vendor/github.com/containerd/zfs/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,10 @@ +module github.com/containerd/zfs + +go 1.16 + +require ( + github.com/containerd/containerd v1.5.0-beta.3 + github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e + github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible + github.com/pkg/errors v0.9.1 +) diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/go.sum containerd-1.5.9/vendor/github.com/containerd/zfs/go.sum --- containerd-1.2.6/vendor/github.com/containerd/zfs/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,834 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3 h1:mw6pDQqv38/WGF1cO/jF5t/jyAJ2yi7CmtFLLO5tGFI= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15 h1:Aof83YILRs2Vx3GhHqlvvfyx1asRJKMFIMeVlHsZKtI= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68 h1:hkGVFjz+plgr5UfxZUTPFbUFIF/Km6/s+RVRIRHLrrY= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3 h1:hIqwXglcRyu4qbOmm+pBfQ1gf3wl3VziUAZED5ng2v8= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e h1:6JKvHHt396/qabvMhnhUZvWaHZzfVfldxE60TK8YLhg= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1 h1:PvuK4E3D5S5q6IqsPDCy928FhP0LUIGcmZ/Yhgp5Djw= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/moby/sys/mountinfo v0.4.0 h1:1KInV3Huv18akCu58V7lzNlt+jFmqlu1EaErnEHE/VM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/plugin/plugin.go containerd-1.5.9/vendor/github.com/containerd/zfs/plugin/plugin.go --- containerd-1.2.6/vendor/github.com/containerd/zfs/plugin/plugin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/plugin/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,58 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package plugin + +import ( + "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" + "github.com/containerd/zfs" + "github.com/pkg/errors" +) + +// Config represents configuration for the zfs plugin +type Config struct { + // Root directory for the plugin + RootPath string `toml:"root_path"` +} + +func init() { + plugin.Register(&plugin.Registration{ + Type: plugin.SnapshotPlugin, + ID: "zfs", + Config: &Config{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) + + // get config + config, ok := ic.Config.(*Config) + if !ok { + return nil, errors.New("invalid zfs configuration") + } + // use default ic.Root as root path if config doesn't have a valid root path + root := ic.Root + if len(config.RootPath) != 0 { + root = config.RootPath + } + ic.Meta.Exports["root"] = root + snapshotter, err := zfs.NewSnapshotter(root) + if err != nil { + return nil, errors.Wrap(plugin.ErrSkipPlugin, err.Error()) + } + return snapshotter, nil + }, + }) +} diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/README.md containerd-1.5.9/vendor/github.com/containerd/zfs/README.md --- containerd-1.2.6/vendor/github.com/containerd/zfs/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -7,26 +7,11 @@ This plugin is tested on Linux with Ubuntu. It should be compatible with FreeBSD. - -## Compile - -To compile containerd with ZFS support, add the import into the `$GOPATH/src/github.com/containerd/containerd/cmd/containerd/builtins_zfs.go` file. - -```go -// +build linux freebsd - -package main - -import ( - _ "github.com/containerd/zfs" -) -``` - -Please refer to [`.travis.yml`](.travis.yml) for the latest containerd version known to work with. - - ## Usage +The plugin is built-in by default since containerd 1.1. +No need to recompile containerd or execute a proxy snapshotter process. + 1. Set up a ZFS filesystem. The ZFS filesystem name is arbitrary but the mount point needs to be `/var/lib/containerd/io.containerd.snapshotter.v1.zfs`, when the containerd root is set to `/var/lib/containerd`. ```console @@ -36,3 +21,13 @@ 2. Start containerd. 3. e.g. `ctr pull --snapshotter=zfs ...` + +## Project details + +The zfs plugin is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff -Nru containerd-1.2.6/vendor/github.com/containerd/zfs/zfs.go containerd-1.5.9/vendor/github.com/containerd/zfs/zfs.go --- containerd-1.2.6/vendor/github.com/containerd/zfs/zfs.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containerd/zfs/zfs.go 2022-01-05 17:30:58.000000000 +0000 @@ -1,15 +1,30 @@ // +build linux freebsd +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package zfs import ( "context" + "math" "path/filepath" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" zfs "github.com/mistifyio/go-zfs" @@ -21,19 +36,10 @@ // active := filepath.Join(dataset.Name, id) // committed := active + "@" + snapshotSuffix snapshotSuffix = "snapshot" -) -func init() { - plugin.Register(&plugin.Registration{ - Type: plugin.SnapshotPlugin, - ID: "zfs", - InitFn: func(ic *plugin.InitContext) (interface{}, error) { - ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) - ic.Meta.Exports["root"] = ic.Root - return NewSnapshotter(ic.Root) - }, - }) -} + // Using this typed MaxInt64 to prevent integer overlow on 32bit + maxSnapshotSize int64 = math.MaxInt64 +) type snapshotter struct { dataset *zfs.Dataset @@ -103,7 +109,7 @@ if err != nil { return snapshots.Info{}, err } - defer t.Rollback() + defer t.Rollback() //nolint:errcheck _, info, _, err := storage.GetInfo(ctx, key) if err != nil { return snapshots.Info{}, err @@ -114,17 +120,50 @@ // Usage retrieves the disk usage of the top-level snapshot. func (z *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { - return snapshots.Usage{}, errors.New("zfs does not implement Usage() yet") + return z.usage(ctx, key) +} + +func (z *snapshotter) usage(ctx context.Context, key string) (snapshots.Usage, error) { + ctx, t, err := z.ms.TransactionContext(ctx, false) + if err != nil { + return snapshots.Usage{}, err + } + id, info, usage, err := storage.GetInfo(ctx, key) + t.Rollback() //nolint:errcheck + + if err != nil { + return snapshots.Usage{}, err + } + + if info.Kind == snapshots.KindActive { + activeName := filepath.Join(z.dataset.Name, id) + sDataset, err := zfs.GetDataset(activeName) + + if err != nil { + return snapshots.Usage{}, err + } + + if int64(sDataset.Used) > maxSnapshotSize { + return snapshots.Usage{}, errors.Errorf("Dataset size exceeds maximum snapshot size of %d bytes", maxSnapshotSize) + } + + usage = snapshots.Usage{ + Size: int64(sDataset.Used), + Inodes: -1, + } + } + + return usage, nil } // Walk the committed snapshots. -func (z *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshots.Info) error) error { +func (z *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error { ctx, t, err := z.ms.TransactionContext(ctx, false) if err != nil { return err } - defer t.Rollback() - return storage.WalkInfo(ctx, fn) + defer t.Rollback() //nolint:errcheck + return storage.WalkInfo(ctx, fn, filters...) } func (z *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { @@ -199,6 +238,11 @@ } func (z *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) (err error) { + usage, err := z.usage(ctx, key) + if err != nil { + return errors.Wrap(err, "failed to compute usage") + } + ctx, t, err := z.ms.TransactionContext(ctx, true) if err != nil { return err @@ -211,7 +255,7 @@ } }() - id, err := storage.CommitActive(ctx, key, name, snapshots.Usage{}) + id, err := storage.CommitActive(ctx, key, name, usage, opts...) if err != nil { return errors.Wrap(err, "failed to commit") } @@ -247,7 +291,7 @@ return nil, err } s, err := storage.GetSnapshot(ctx, key) - t.Rollback() + t.Rollback() //nolint:errcheck if err != nil { return nil, errors.Wrap(err, "failed to get active snapshot") } @@ -282,18 +326,20 @@ datasetName := filepath.Join(z.dataset.Name, id) if k == snapshots.KindCommitted { - datasetName += "@" + snapshotSuffix + snapshotName := datasetName + "@" + snapshotSuffix + snapshot, err := zfs.GetDataset(snapshotName) + if err != nil { + return err + } + if err = destroySnapshot(snapshot); err != nil { + return err + } } dataset, err := zfs.GetDataset(datasetName) if err != nil { return err } - if k == snapshots.KindCommitted { - err = destroySnapshot(dataset) - } else { - err = destroy(dataset) - } - if err != nil { + if err = destroy(dataset); err != nil { return err } err = t.Commit() @@ -309,7 +355,7 @@ info, err = storage.UpdateInfo(ctx, info, fieldpaths...) if err != nil { - t.Rollback() + t.Rollback() //nolint:errcheck return snapshots.Info{}, err } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/libcni/api.go containerd-1.5.9/vendor/github.com/containernetworking/cni/libcni/api.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/libcni/api.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/libcni/api.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,14 +15,32 @@ package libcni import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" "os" + "path/filepath" "strings" "github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/types" + "github.com/containernetworking/cni/pkg/utils" "github.com/containernetworking/cni/pkg/version" ) +var ( + CacheDir = "/var/lib/cni" +) + +const ( + CNICacheV1 = "cniCacheV1" +) + +// A RuntimeConf holds the arguments to one invocation of a CNI plugin +// excepting the network configuration, with the nested exception that +// the `runtimeConfig` from the network configuration is included +// here. type RuntimeConf struct { ContainerID string NetNS string @@ -34,6 +52,9 @@ // in this map which match the capabilities of the plugin are passed // to the plugin CapabilityArgs map[string]interface{} + + // DEPRECATED. Will be removed in a future release. + CacheDir string } type NetworkConfig struct { @@ -42,33 +63,64 @@ } type NetworkConfigList struct { - Name string - CNIVersion string - Plugins []*NetworkConfig - Bytes []byte + Name string + CNIVersion string + DisableCheck bool + Plugins []*NetworkConfig + Bytes []byte } type CNI interface { - AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) - DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error + AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) + CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error + DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error + GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) + GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) + + AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) + CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error + DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error + GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) + GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) - AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) - DelNetwork(net *NetworkConfig, rt *RuntimeConf) error + ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error) + ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) } type CNIConfig struct { - Path []string + Path []string + exec invoke.Exec + cacheDir string } // CNIConfig implements the CNI interface var _ CNI = &CNIConfig{} -func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) { +// NewCNIConfig returns a new CNIConfig object that will search for plugins +// in the given paths and use the given exec interface to run those plugins, +// or if the exec interface is not given, will use a default exec handler. +func NewCNIConfig(path []string, exec invoke.Exec) *CNIConfig { + return NewCNIConfigWithCacheDir(path, "", exec) +} + +// NewCNIConfigWithCacheDir returns a new CNIConfig object that will search for plugins +// in the given paths use the given exec interface to run those plugins, +// or if the exec interface is not given, will use a default exec handler. +// The given cache directory will be used for temporary data storage when needed. +func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec) *CNIConfig { + return &CNIConfig{ + Path: path, + cacheDir: cacheDir, + exec: exec, + } +} + +func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) { var err error inject := map[string]interface{}{ - "name": list.Name, - "cniVersion": list.CNIVersion, + "name": name, + "cniVersion": cniVersion, } // Add previous plugin result if prevResult != nil { @@ -92,7 +144,7 @@ // These capabilities arguments are filtered through the plugin's advertised // capabilities from its config JSON, and any keys in the CapabilityArgs // matching plugin capabilities are added to the "runtimeConfig" dictionary -// sent to the plugin via JSON on stdin. For exmaple, if the plugin's +// sent to the plugin via JSON on stdin. For example, if the plugin's // capabilities include "portMappings", and the CapabilityArgs map includes a // "portMappings" key, that key and its value are added to the "runtimeConfig" // dictionary to be passed to the plugin's stdin. @@ -119,91 +171,493 @@ return orig, nil } +// ensure we have a usable exec if the CNIConfig was not given one +func (c *CNIConfig) ensureExec() invoke.Exec { + if c.exec == nil { + c.exec = &invoke.DefaultExec{ + RawExec: &invoke.RawExec{Stderr: os.Stderr}, + PluginDecoder: version.PluginDecoder{}, + } + } + return c.exec +} + +type cachedInfo struct { + Kind string `json:"kind"` + ContainerID string `json:"containerId"` + Config []byte `json:"config"` + IfName string `json:"ifName"` + NetworkName string `json:"networkName"` + CniArgs [][2]string `json:"cniArgs,omitempty"` + CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"` + RawResult map[string]interface{} `json:"result,omitempty"` + Result types.Result `json:"-"` +} + +// getCacheDir returns the cache directory in this order: +// 1) global cacheDir from CNIConfig object +// 2) deprecated cacheDir from RuntimeConf object +// 3) fall back to default cache directory +func (c *CNIConfig) getCacheDir(rt *RuntimeConf) string { + if c.cacheDir != "" { + return c.cacheDir + } + if rt.CacheDir != "" { + return rt.CacheDir + } + return CacheDir +} + +func (c *CNIConfig) getCacheFilePath(netName string, rt *RuntimeConf) (string, error) { + if netName == "" || rt.ContainerID == "" || rt.IfName == "" { + return "", fmt.Errorf("cache file path requires network name (%q), container ID (%q), and interface name (%q)", netName, rt.ContainerID, rt.IfName) + } + return filepath.Join(c.getCacheDir(rt), "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName)), nil +} + +func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string, rt *RuntimeConf) error { + cached := cachedInfo{ + Kind: CNICacheV1, + ContainerID: rt.ContainerID, + Config: config, + IfName: rt.IfName, + NetworkName: netName, + CniArgs: rt.Args, + CapabilityArgs: rt.CapabilityArgs, + } + + // We need to get type.Result into cachedInfo as JSON map + // Marshal to []byte, then Unmarshal into cached.RawResult + data, err := json.Marshal(result) + if err != nil { + return err + } + + err = json.Unmarshal(data, &cached.RawResult) + if err != nil { + return err + } + + newBytes, err := json.Marshal(&cached) + if err != nil { + return err + } + + fname, err := c.getCacheFilePath(netName, rt) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil { + return err + } + + return ioutil.WriteFile(fname, newBytes, 0600) +} + +func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error { + fname, err := c.getCacheFilePath(netName, rt) + if err != nil { + // Ignore error + return nil + } + return os.Remove(fname) +} + +func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { + var bytes []byte + + fname, err := c.getCacheFilePath(netName, rt) + if err != nil { + return nil, nil, err + } + bytes, err = ioutil.ReadFile(fname) + if err != nil { + // Ignore read errors; the cached result may not exist on-disk + return nil, nil, nil + } + + unmarshaled := cachedInfo{} + if err := json.Unmarshal(bytes, &unmarshaled); err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %v", netName, err) + } + if unmarshaled.Kind != CNICacheV1 { + return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind) + } + + newRt := *rt + if unmarshaled.CniArgs != nil { + newRt.Args = unmarshaled.CniArgs + } + newRt.CapabilityArgs = unmarshaled.CapabilityArgs + + return unmarshaled.Config, &newRt, nil +} + +func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) { + fname, err := c.getCacheFilePath(netName, rt) + if err != nil { + return nil, err + } + data, err := ioutil.ReadFile(fname) + if err != nil { + // Ignore read errors; the cached result may not exist on-disk + return nil, nil + } + + // Read the version of the cached result + decoder := version.ConfigDecoder{} + resultCniVersion, err := decoder.Decode(data) + if err != nil { + return nil, err + } + + // Ensure we can understand the result + result, err := version.NewResult(resultCniVersion, data) + if err != nil { + return nil, err + } + + // Convert to the config version to ensure plugins get prevResult + // in the same version as the config. The cached result version + // should match the config version unless the config was changed + // while the container was running. + result, err = result.GetAsVersion(cniVersion) + if err != nil && resultCniVersion != cniVersion { + return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err) + } + return result, err +} + +func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) { + fname, err := c.getCacheFilePath(netName, rt) + if err != nil { + return nil, err + } + fdata, err := ioutil.ReadFile(fname) + if err != nil { + // Ignore read errors; the cached result may not exist on-disk + return nil, nil + } + + cachedInfo := cachedInfo{} + if err := json.Unmarshal(fdata, &cachedInfo); err != nil || cachedInfo.Kind != CNICacheV1 { + return c.getLegacyCachedResult(netName, cniVersion, rt) + } + + newBytes, err := json.Marshal(&cachedInfo.RawResult) + if err != nil { + return nil, fmt.Errorf("failed to marshal cached network %q config: %v", netName, err) + } + + // Read the version of the cached result + decoder := version.ConfigDecoder{} + resultCniVersion, err := decoder.Decode(newBytes) + if err != nil { + return nil, err + } + + // Ensure we can understand the result + result, err := version.NewResult(resultCniVersion, newBytes) + if err != nil { + return nil, err + } + + // Convert to the config version to ensure plugins get prevResult + // in the same version as the config. The cached result version + // should match the config version unless the config was changed + // while the container was running. + result, err = result.GetAsVersion(cniVersion) + if err != nil && resultCniVersion != cniVersion { + return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err) + } + return result, err +} + +// GetNetworkListCachedResult returns the cached Result of the previous +// AddNetworkList() operation for a network list, or an error. +func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { + return c.getCachedResult(list.Name, list.CNIVersion, rt) +} + +// GetNetworkCachedResult returns the cached Result of the previous +// AddNetwork() operation for a network, or an error. +func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) { + return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) +} + +// GetNetworkListCachedConfig copies the input RuntimeConf to output +// RuntimeConf with fields updated with info from the cached Config. +func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { + return c.getCachedConfig(list.Name, rt) +} + +// GetNetworkCachedConfig copies the input RuntimeConf to output +// RuntimeConf with fields updated with info from the cached Config. +func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { + return c.getCachedConfig(net.Network.Name, rt) +} + +func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) { + c.ensureExec() + pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) + if err != nil { + return nil, err + } + if err := utils.ValidateContainerID(rt.ContainerID); err != nil { + return nil, err + } + if err := utils.ValidateNetworkName(name); err != nil { + return nil, err + } + if err := utils.ValidateInterfaceName(rt.IfName); err != nil { + return nil, err + } + + newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) + if err != nil { + return nil, err + } + + return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec) +} + // AddNetworkList executes a sequence of plugins with the ADD command -func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { - var prevResult types.Result +func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { + var err error + var result types.Result for _, net := range list.Plugins { - pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) + result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt) if err != nil { return nil, err } + } - newConf, err := buildOneConfig(list, net, prevResult, rt) - if err != nil { - return nil, err - } + if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil { + return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err) + } - prevResult, err = invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args("ADD", rt)) - if err != nil { - return nil, err - } + return result, nil +} + +func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error { + c.ensureExec() + pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) + if err != nil { + return err } - return prevResult, nil + newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) + if err != nil { + return err + } + + return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("CHECK", rt), c.exec) } -// DelNetworkList executes a sequence of plugins with the DEL command -func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) error { - for i := len(list.Plugins) - 1; i >= 0; i-- { - net := list.Plugins[i] +// CheckNetworkList executes a sequence of plugins with the CHECK command +func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error { + // CHECK was added in CNI spec version 0.4.0 and higher + if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { + return err + } else if !gtet { + return fmt.Errorf("configuration version %q does not support the CHECK command", list.CNIVersion) + } - pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) - if err != nil { + if list.DisableCheck { + return nil + } + + cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt) + if err != nil { + return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err) + } + + for _, net := range list.Plugins { + if err := c.checkNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil { return err } + } + + return nil +} + +func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error { + c.ensureExec() + pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) + if err != nil { + return err + } + + newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) + if err != nil { + return err + } + + return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("DEL", rt), c.exec) +} - newConf, err := buildOneConfig(list, net, nil, rt) +// DelNetworkList executes a sequence of plugins with the DEL command +func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error { + var cachedResult types.Result + + // Cached result on DEL was added in CNI spec version 0.4.0 and higher + if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { + return err + } else if gtet { + cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt) if err != nil { - return err + return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err) } + } - if err := invoke.ExecPluginWithoutResult(pluginPath, newConf.Bytes, c.args("DEL", rt)); err != nil { + for i := len(list.Plugins) - 1; i >= 0; i-- { + net := list.Plugins[i] + if err := c.delNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil { return err } } + _ = c.cacheDel(list.Name, rt) return nil } // AddNetwork executes the plugin with the ADD command -func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) { - pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) +func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error) { + result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt) if err != nil { return nil, err } - net, err = injectRuntimeConfig(net, rt) - if err != nil { - return nil, err + if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil { + return nil, fmt.Errorf("failed to set network %q cached result: %v", net.Network.Name, err) } - return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt)) + return result, nil } -// DelNetwork executes the plugin with the DEL command -func (c *CNIConfig) DelNetwork(net *NetworkConfig, rt *RuntimeConf) error { - pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) +// CheckNetwork executes the plugin with the CHECK command +func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error { + // CHECK was added in CNI spec version 0.4.0 and higher + if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil { + return err + } else if !gtet { + return fmt.Errorf("configuration version %q does not support the CHECK command", net.Network.CNIVersion) + } + + cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) if err != nil { + return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err) + } + return c.checkNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt) +} + +// DelNetwork executes the plugin with the DEL command +func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error { + var cachedResult types.Result + + // Cached result on DEL was added in CNI spec version 0.4.0 and higher + if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil { return err + } else if gtet { + cachedResult, err = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) + if err != nil { + return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err) + } + } + + if err := c.delNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil { + return err + } + _ = c.cacheDel(net.Network.Name, rt) + return nil +} + +// ValidateNetworkList checks that a configuration is reasonably valid. +// - all the specified plugins exist on disk +// - every plugin supports the desired version. +// +// Returns a list of all capabilities supported by the configuration, or error +func (c *CNIConfig) ValidateNetworkList(ctx context.Context, list *NetworkConfigList) ([]string, error) { + version := list.CNIVersion + + // holding map for seen caps (in case of duplicates) + caps := map[string]interface{}{} + + errs := []error{} + for _, net := range list.Plugins { + if err := c.validatePlugin(ctx, net.Network.Type, version); err != nil { + errs = append(errs, err) + } + for c, enabled := range net.Network.Capabilities { + if !enabled { + continue + } + caps[c] = struct{}{} + } + } + + if len(errs) > 0 { + return nil, fmt.Errorf("%v", errs) } - net, err = injectRuntimeConfig(net, rt) + // make caps list + cc := make([]string, 0, len(caps)) + for c := range caps { + cc = append(cc, c) + } + + return cc, nil +} + +// ValidateNetwork checks that a configuration is reasonably valid. +// It uses the same logic as ValidateNetworkList) +// Returns a list of capabilities +func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) { + caps := []string{} + for c, ok := range net.Network.Capabilities { + if ok { + caps = append(caps, c) + } + } + if err := c.validatePlugin(ctx, net.Network.Type, net.Network.CNIVersion); err != nil { + return nil, err + } + return caps, nil +} + +// validatePlugin checks that an individual plugin's configuration is sane +func (c *CNIConfig) validatePlugin(ctx context.Context, pluginName, expectedVersion string) error { + c.ensureExec() + pluginPath, err := c.exec.FindInPath(pluginName, c.Path) if err != nil { return err } + if expectedVersion == "" { + expectedVersion = "0.1.0" + } - return invoke.ExecPluginWithoutResult(pluginPath, net.Bytes, c.args("DEL", rt)) + vi, err := invoke.GetVersionInfo(ctx, pluginPath, c.exec) + if err != nil { + return err + } + for _, vers := range vi.SupportedVersions() { + if vers == expectedVersion { + return nil + } + } + return fmt.Errorf("plugin %s does not support config version %q", pluginName, expectedVersion) } // GetVersionInfo reports which versions of the CNI spec are supported by // the given plugin. -func (c *CNIConfig) GetVersionInfo(pluginType string) (version.PluginInfo, error) { - pluginPath, err := invoke.FindInPath(pluginType, c.Path) +func (c *CNIConfig) GetVersionInfo(ctx context.Context, pluginType string) (version.PluginInfo, error) { + c.ensureExec() + pluginPath, err := c.exec.FindInPath(pluginType, c.Path) if err != nil { return nil, err } - return invoke.GetVersionInfo(pluginPath) + return invoke.GetVersionInfo(ctx, pluginPath, c.exec) } // ===== diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/libcni/conf.go containerd-1.5.9/vendor/github.com/containernetworking/cni/libcni/conf.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/libcni/conf.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/libcni/conf.go 2022-01-05 17:30:58.000000000 +0000 @@ -45,6 +45,9 @@ if err := json.Unmarshal(bytes, &conf.Network); err != nil { return nil, fmt.Errorf("error parsing configuration: %s", err) } + if conf.Network.Type == "" { + return nil, fmt.Errorf("error parsing configuration: missing 'type'") + } return conf, nil } @@ -80,10 +83,19 @@ } } + disableCheck := false + if rawDisableCheck, ok := rawList["disableCheck"]; ok { + disableCheck, ok = rawDisableCheck.(bool) + if !ok { + return nil, fmt.Errorf("error parsing configuration list: invalid disableCheck type %T", rawDisableCheck) + } + } + list := &NetworkConfigList{ - Name: name, - CNIVersion: cniVersion, - Bytes: bytes, + Name: name, + DisableCheck: disableCheck, + CNIVersion: cniVersion, + Bytes: bytes, } var plugins []interface{} @@ -102,11 +114,11 @@ for i, conf := range plugins { newBytes, err := json.Marshal(conf) if err != nil { - return nil, fmt.Errorf("Failed to marshal plugin config %d: %v", i, err) + return nil, fmt.Errorf("failed to marshal plugin config %d: %v", i, err) } netConf, err := ConfFromBytes(newBytes) if err != nil { - return nil, fmt.Errorf("Failed to parse plugin config %d: %v", i, err) + return nil, fmt.Errorf("failed to parse plugin config %d: %v", i, err) } list.Plugins = append(list.Plugins, netConf) } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/args.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/args.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/args.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/args.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,6 +15,7 @@ package invoke import ( + "fmt" "os" "strings" ) @@ -22,6 +23,8 @@ type CNIArgs interface { // For use with os/exec; i.e., return nil to inherit the // environment from this process + // For use in delegation; inherit the environment from this + // process and allow overrides AsEnv() []string } @@ -29,7 +32,7 @@ var inheritArgsFromEnv inherited -func (_ *inherited) AsEnv() []string { +func (*inherited) AsEnv() []string { return nil } @@ -57,17 +60,17 @@ pluginArgsStr = stringify(args.PluginArgs) } - // Ensure that the custom values are first, so any value present in - // the process environment won't override them. - env = append([]string{ - "CNI_COMMAND=" + args.Command, - "CNI_CONTAINERID=" + args.ContainerID, - "CNI_NETNS=" + args.NetNS, - "CNI_ARGS=" + pluginArgsStr, - "CNI_IFNAME=" + args.IfName, - "CNI_PATH=" + args.Path, - }, env...) - return env + // Duplicated values which come first will be overridden, so we must put the + // custom values in the end to avoid being overridden by the process environments. + env = append(env, + "CNI_COMMAND="+args.Command, + "CNI_CONTAINERID="+args.ContainerID, + "CNI_NETNS="+args.NetNS, + "CNI_ARGS="+pluginArgsStr, + "CNI_IFNAME="+args.IfName, + "CNI_PATH="+args.Path, + ) + return dedupEnv(env) } // taken from rkt/networking/net_plugin.go @@ -80,3 +83,46 @@ return strings.Join(entries, ";") } + +// DelegateArgs implements the CNIArgs interface +// used for delegation to inherit from environments +// and allow some overrides like CNI_COMMAND +var _ CNIArgs = &DelegateArgs{} + +type DelegateArgs struct { + Command string +} + +func (d *DelegateArgs) AsEnv() []string { + env := os.Environ() + + // The custom values should come in the end to override the existing + // process environment of the same key. + env = append(env, + "CNI_COMMAND="+d.Command, + ) + return dedupEnv(env) +} + +// dedupEnv returns a copy of env with any duplicates removed, in favor of later values. +// Items not of the normal environment "key=value" form are preserved unchanged. +func dedupEnv(env []string) []string { + out := make([]string, 0, len(env)) + envMap := map[string]string{} + + for _, kv := range env { + // find the first "=" in environment, if not, just keep it + eq := strings.Index(kv, "=") + if eq < 0 { + out = append(out, kv) + continue + } + envMap[kv[:eq]] = kv[eq+1:] + } + + for k, v := range envMap { + out = append(out, fmt.Sprintf("%s=%s", k, v)) + } + + return out +} diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,39 +15,66 @@ package invoke import ( - "fmt" + "context" "os" "path/filepath" "github.com/containernetworking/cni/pkg/types" ) -func DelegateAdd(delegatePlugin string, netconf []byte) (types.Result, error) { - if os.Getenv("CNI_COMMAND") != "ADD" { - return nil, fmt.Errorf("CNI_COMMAND is not ADD") +func delegateCommon(delegatePlugin string, exec Exec) (string, Exec, error) { + if exec == nil { + exec = defaultExec } paths := filepath.SplitList(os.Getenv("CNI_PATH")) + pluginPath, err := exec.FindInPath(delegatePlugin, paths) + if err != nil { + return "", nil, err + } + + return pluginPath, exec, nil +} - pluginPath, err := FindInPath(delegatePlugin, paths) +// DelegateAdd calls the given delegate plugin with the CNI ADD action and +// JSON configuration +func DelegateAdd(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) { + pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) if err != nil { return nil, err } - return ExecPluginWithResult(pluginPath, netconf, ArgsFromEnv()) + // DelegateAdd will override the original "CNI_COMMAND" env from process with ADD + return ExecPluginWithResult(ctx, pluginPath, netconf, delegateArgs("ADD"), realExec) } -func DelegateDel(delegatePlugin string, netconf []byte) error { - if os.Getenv("CNI_COMMAND") != "DEL" { - return fmt.Errorf("CNI_COMMAND is not DEL") +// DelegateCheck calls the given delegate plugin with the CNI CHECK action and +// JSON configuration +func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { + pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) + if err != nil { + return err } - paths := filepath.SplitList(os.Getenv("CNI_PATH")) + // DelegateCheck will override the original CNI_COMMAND env from process with CHECK + return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("CHECK"), realExec) +} - pluginPath, err := FindInPath(delegatePlugin, paths) +// DelegateDel calls the given delegate plugin with the CNI DEL action and +// JSON configuration +func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { + pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) if err != nil { return err } - return ExecPluginWithoutResult(pluginPath, netconf, ArgsFromEnv()) + // DelegateDel will override the original CNI_COMMAND env from process with DEL + return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("DEL"), realExec) +} + +// return CNIArgs used by delegation +func delegateArgs(action string) *DelegateArgs { + return &DelegateArgs{ + Command: action, + } } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,6 +15,7 @@ package invoke import ( + "context" "fmt" "os" @@ -22,34 +23,62 @@ "github.com/containernetworking/cni/pkg/version" ) -func ExecPluginWithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) { - return defaultPluginExec.WithResult(pluginPath, netconf, args) -} - -func ExecPluginWithoutResult(pluginPath string, netconf []byte, args CNIArgs) error { - return defaultPluginExec.WithoutResult(pluginPath, netconf, args) -} - -func GetVersionInfo(pluginPath string) (version.PluginInfo, error) { - return defaultPluginExec.GetVersionInfo(pluginPath) -} - -var defaultPluginExec = &PluginExec{ - RawExec: &RawExec{Stderr: os.Stderr}, - VersionDecoder: &version.PluginDecoder{}, -} - -type PluginExec struct { - RawExec interface { - ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) - } - VersionDecoder interface { - Decode(jsonBytes []byte) (version.PluginInfo, error) +// Exec is an interface encapsulates all operations that deal with finding +// and executing a CNI plugin. Tests may provide a fake implementation +// to avoid writing fake plugins to temporary directories during the test. +type Exec interface { + ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) + FindInPath(plugin string, paths []string) (string, error) + Decode(jsonBytes []byte) (version.PluginInfo, error) +} + +// For example, a testcase could pass an instance of the following fakeExec +// object to ExecPluginWithResult() to verify the incoming stdin and environment +// and provide a tailored response: +// +//import ( +// "encoding/json" +// "path" +// "strings" +//) +// +//type fakeExec struct { +// version.PluginDecoder +//} +// +//func (f *fakeExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) { +// net := &types.NetConf{} +// err := json.Unmarshal(stdinData, net) +// if err != nil { +// return nil, fmt.Errorf("failed to unmarshal configuration: %v", err) +// } +// pluginName := path.Base(pluginPath) +// if pluginName != net.Type { +// return nil, fmt.Errorf("plugin name %q did not match config type %q", pluginName, net.Type) +// } +// for _, e := range environ { +// // Check environment for forced failure request +// parts := strings.Split(e, "=") +// if len(parts) > 0 && parts[0] == "FAIL" { +// return nil, fmt.Errorf("failed to execute plugin %s", pluginName) +// } +// } +// return []byte("{\"CNIVersion\":\"0.4.0\"}"), nil +//} +// +//func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) { +// if len(paths) > 0 { +// return path.Join(paths[0], plugin), nil +// } +// return "", fmt.Errorf("failed to find plugin %s in paths %v", plugin, paths) +//} + +func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) { + if exec == nil { + exec = defaultExec } -} -func (e *PluginExec) WithResult(pluginPath string, netconf []byte, args CNIArgs) (types.Result, error) { - stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv()) + stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv()) if err != nil { return nil, err } @@ -64,8 +93,11 @@ return version.NewResult(confVersion, stdoutBytes) } -func (e *PluginExec) WithoutResult(pluginPath string, netconf []byte, args CNIArgs) error { - _, err := e.RawExec.ExecPlugin(pluginPath, netconf, args.AsEnv()) +func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error { + if exec == nil { + exec = defaultExec + } + _, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv()) return err } @@ -73,7 +105,10 @@ // For recent-enough plugins, it uses the information returned by the VERSION // command. For older plugins which do not recognize that command, it reports // version 0.1.0 -func (e *PluginExec) GetVersionInfo(pluginPath string) (version.PluginInfo, error) { +func GetVersionInfo(ctx context.Context, pluginPath string, exec Exec) (version.PluginInfo, error) { + if exec == nil { + exec = defaultExec + } args := &Args{ Command: "VERSION", @@ -83,7 +118,7 @@ Path: "dummy", } stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current())) - stdoutBytes, err := e.RawExec.ExecPlugin(pluginPath, stdin, args.AsEnv()) + stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, stdin, args.AsEnv()) if err != nil { if err.Error() == "unknown CNI_COMMAND: VERSION" { return version.PluginSupports("0.1.0"), nil @@ -91,5 +126,19 @@ return nil, err } - return e.VersionDecoder.Decode(stdoutBytes) + return exec.Decode(stdoutBytes) +} + +// DefaultExec is an object that implements the Exec interface which looks +// for and executes plugins from disk. +type DefaultExec struct { + *RawExec + version.PluginDecoder +} + +// DefaultExec implements the Exec interface +var _ Exec = &DefaultExec{} + +var defaultExec = &DefaultExec{ + RawExec: &RawExec{Stderr: os.Stderr}, } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/find.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/find.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/find.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/find.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,7 @@ "fmt" "os" "path/filepath" + "strings" ) // FindInPath returns the full path of the plugin by searching in the provided path @@ -26,6 +27,10 @@ return "", fmt.Errorf("no plugin name provided") } + if strings.ContainsRune(plugin, os.PathSeparator) { + return "", fmt.Errorf("invalid plugin name: %s", plugin) + } + if len(paths) == 0 { return "", fmt.Errorf("no paths provided") } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build darwin dragonfly freebsd linux netbsd opensbd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package invoke diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,10 +16,13 @@ import ( "bytes" + "context" "encoding/json" "fmt" "io" "os/exec" + "strings" + "time" "github.com/containernetworking/cni/pkg/types" ) @@ -28,32 +31,58 @@ Stderr io.Writer } -func (e *RawExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) { +func (e *RawExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) { stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + c := exec.CommandContext(ctx, pluginPath) + c.Env = environ + c.Stdin = bytes.NewBuffer(stdinData) + c.Stdout = stdout + c.Stderr = stderr + + // Retry the command on "text file busy" errors + for i := 0; i <= 5; i++ { + err := c.Run() + + // Command succeeded + if err == nil { + break + } - c := exec.Cmd{ - Env: environ, - Path: pluginPath, - Args: []string{pluginPath}, - Stdin: bytes.NewBuffer(stdinData), - Stdout: stdout, - Stderr: e.Stderr, - } - if err := c.Run(); err != nil { - return nil, pluginErr(err, stdout.Bytes()) + // If the plugin is currently about to be written, then we wait a + // second and try it again + if strings.Contains(err.Error(), "text file busy") { + time.Sleep(time.Second) + continue + } + + // All other errors except than the busy text file + return nil, e.pluginErr(err, stdout.Bytes(), stderr.Bytes()) } + // Copy stderr to caller's buffer in case plugin printed to both + // stdout and stderr for some reason. Ignore failures as stderr is + // only informational. + if e.Stderr != nil && stderr.Len() > 0 { + _, _ = stderr.WriteTo(e.Stderr) + } return stdout.Bytes(), nil } -func pluginErr(err error, output []byte) error { - if _, ok := err.(*exec.ExitError); ok { - emsg := types.Error{} - if perr := json.Unmarshal(output, &emsg); perr != nil { - emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr) +func (e *RawExec) pluginErr(err error, stdout, stderr []byte) error { + emsg := types.Error{} + if len(stdout) == 0 { + if len(stderr) == 0 { + emsg.Msg = fmt.Sprintf("netplugin failed with no error message: %v", err) + } else { + emsg.Msg = fmt.Sprintf("netplugin failed: %q", string(stderr)) } - return &emsg + } else if perr := json.Unmarshal(stdout, &emsg); perr != nil { + emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(stdout), perr) } + return &emsg +} - return err +func (e *RawExec) FindInPath(plugin string, paths []string) (string, error) { + return FindInPath(plugin, paths) } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/020/types.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/020/types.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/020/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/020/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ import ( "encoding/json" "fmt" + "io" "net" "os" @@ -73,28 +74,18 @@ } func (r *Result) Print() error { + return r.PrintTo(os.Stdout) +} + +func (r *Result) PrintTo(writer io.Writer) error { data, err := json.MarshalIndent(r, "", " ") if err != nil { return err } - _, err = os.Stdout.Write(data) + _, err = writer.Write(data) return err } -// String returns a formatted string in the form of "[IP4: $1,][ IP6: $2,] DNS: $3" where -// $1 represents the receiver's IPv4, $2 represents the receiver's IPv6 and $3 the -// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string. -func (r *Result) String() string { - var str string - if r.IP4 != nil { - str = fmt.Sprintf("IP4:%+v, ", *r.IP4) - } - if r.IP6 != nil { - str += fmt.Sprintf("IP6:%+v, ", *r.IP6) - } - return fmt.Sprintf("%sDNS:%+v", str, r.DNS) -} - // IPConfig contains values necessary to configure an interface type IPConfig struct { IP net.IPNet diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/args.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/args.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/args.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/args.go 2022-01-05 17:30:58.000000000 +0000 @@ -36,7 +36,7 @@ case "0", "false": *b = false default: - return fmt.Errorf("Boolean unmarshal error: invalid input %s", s) + return fmt.Errorf("boolean unmarshal error: invalid input %s", s) } return nil } diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/current/types.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/current/types.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/current/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/current/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -17,6 +17,7 @@ import ( "encoding/json" "fmt" + "io" "net" "os" @@ -24,9 +25,9 @@ "github.com/containernetworking/cni/pkg/types/020" ) -const ImplementedSpecVersion string = "0.3.1" +const ImplementedSpecVersion string = "0.4.0" -var SupportedVersions = []string{"0.3.0", ImplementedSpecVersion} +var SupportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion} func NewResult(data []byte) (types.Result, error) { result := &Result{} @@ -75,13 +76,9 @@ Gateway: oldResult.IP4.Gateway, }) for _, route := range oldResult.IP4.Routes { - gw := route.GW - if gw == nil { - gw = oldResult.IP4.Gateway - } newResult.Routes = append(newResult.Routes, &types.Route{ Dst: route.Dst, - GW: gw, + GW: route.GW, }) } } @@ -93,21 +90,13 @@ Gateway: oldResult.IP6.Gateway, }) for _, route := range oldResult.IP6.Routes { - gw := route.GW - if gw == nil { - gw = oldResult.IP6.Gateway - } newResult.Routes = append(newResult.Routes, &types.Route{ Dst: route.Dst, - GW: gw, + GW: route.GW, }) } } - if len(newResult.IPs) == 0 { - return nil, fmt.Errorf("cannot convert: no valid IP addresses") - } - return newResult, nil } @@ -196,7 +185,7 @@ func (r *Result) GetAsVersion(version string) (types.Result, error) { switch version { - case "0.3.0", ImplementedSpecVersion: + case "0.3.0", "0.3.1", ImplementedSpecVersion: r.CNIVersion = version return r, nil case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]: @@ -206,31 +195,18 @@ } func (r *Result) Print() error { + return r.PrintTo(os.Stdout) +} + +func (r *Result) PrintTo(writer io.Writer) error { data, err := json.MarshalIndent(r, "", " ") if err != nil { return err } - _, err = os.Stdout.Write(data) + _, err = writer.Write(data) return err } -// String returns a formatted string in the form of "[Interfaces: $1,][ IP: $2,] DNS: $3" where -// $1 represents the receiver's Interfaces, $2 represents the receiver's IP addresses and $3 the -// receiver's DNS. If $1 or $2 are nil, they won't be present in the returned string. -func (r *Result) String() string { - var str string - if len(r.Interfaces) > 0 { - str += fmt.Sprintf("Interfaces:%+v, ", r.Interfaces) - } - if len(r.IPs) > 0 { - str += fmt.Sprintf("IP:%+v, ", r.IPs) - } - if len(r.Routes) > 0 { - str += fmt.Sprintf("Routes:%+v, ", r.Routes) - } - return fmt.Sprintf("%sDNS:%+v", str, r.DNS) -} - // Convert this old version result to the current CNI version result func (r *Result) Convert() (*Result, error) { return r, nil diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/types.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/types.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/types/types.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/types/types.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,8 +16,8 @@ import ( "encoding/json" - "errors" "fmt" + "io" "net" "os" ) @@ -63,25 +63,31 @@ Name string `json:"name,omitempty"` Type string `json:"type,omitempty"` Capabilities map[string]bool `json:"capabilities,omitempty"` - IPAM struct { - Type string `json:"type,omitempty"` - } `json:"ipam,omitempty"` - DNS DNS `json:"dns"` + IPAM IPAM `json:"ipam,omitempty"` + DNS DNS `json:"dns"` + + RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` + PrevResult Result `json:"-"` +} + +type IPAM struct { + Type string `json:"type,omitempty"` } // NetConfList describes an ordered list of networks. type NetConfList struct { CNIVersion string `json:"cniVersion,omitempty"` - Name string `json:"name,omitempty"` - Plugins []*NetConf `json:"plugins,omitempty"` + Name string `json:"name,omitempty"` + DisableCheck bool `json:"disableCheck,omitempty"` + Plugins []*NetConf `json:"plugins,omitempty"` } type ResultFactoryFunc func([]byte) (Result, error) // Result is an interface that provides the result of plugin execution type Result interface { - // The highest CNI specification result verison the result supports + // The highest CNI specification result version the result supports // without having to convert Version() string @@ -92,8 +98,8 @@ // Prints the result in JSON format to stdout Print() error - // Returns a JSON string representation of the result - String() string + // Prints the result in JSON format to provided writer + PrintTo(writer io.Writer) error } func PrintResult(result Result, version string) error { @@ -124,9 +130,16 @@ // Well known error codes // see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes const ( - ErrUnknown uint = iota // 0 - ErrIncompatibleCNIVersion // 1 - ErrUnsupportedField // 2 + ErrUnknown uint = iota // 0 + ErrIncompatibleCNIVersion // 1 + ErrUnsupportedField // 2 + ErrUnknownContainer // 3 + ErrInvalidEnvironmentVariables // 4 + ErrIOFailure // 5 + ErrDecodingFailure // 6 + ErrInvalidNetworkConfig // 7 + ErrTryAgainLater uint = 11 + ErrInternal uint = 999 ) type Error struct { @@ -135,6 +148,14 @@ Details string `json:"details,omitempty"` } +func NewError(code uint, msg, details string) *Error { + return &Error{ + Code: code, + Msg: msg, + Details: details, + } +} + func (e *Error) Error() string { details := "" if e.Details != "" { @@ -167,7 +188,7 @@ return nil } -func (r *Route) MarshalJSON() ([]byte, error) { +func (r Route) MarshalJSON() ([]byte, error) { rt := route{ Dst: IPNet(r.Dst), GW: r.GW, @@ -184,6 +205,3 @@ _, err = os.Stdout.Write(data) return err } - -// NotImplementedError is used to indicate that a method is not implemented for the given platform -var NotImplementedError = errors.New("Not Implemented") diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/utils/utils.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/utils/utils.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/utils/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/utils/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +// Copyright 2019 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "bytes" + "fmt" + "regexp" + "unicode" + + "github.com/containernetworking/cni/pkg/types" +) + +const ( + // cniValidNameChars is the regexp used to validate valid characters in + // containerID and networkName + cniValidNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.\-]` + + // maxInterfaceNameLength is the length max of a valid interface name + maxInterfaceNameLength = 15 +) + +var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`) + +// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters +func ValidateContainerID(containerID string) *types.Error { + + if containerID == "" { + return types.NewError(types.ErrUnknownContainer, "missing containerID", "") + } + if !cniReg.MatchString(containerID) { + return types.NewError(types.ErrInvalidEnvironmentVariables, "invalid characters in containerID", containerID) + } + return nil +} + +// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters +func ValidateNetworkName(networkName string) *types.Error { + + if networkName == "" { + return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "") + } + if !cniReg.MatchString(networkName) { + return types.NewError(types.ErrInvalidNetworkConfig, "invalid characters found in network name", networkName) + } + return nil +} + +// ValidateInterfaceName will validate the interface name based on the three rules below +// 1. The name must not be empty +// 2. The name must be less than 16 characters +// 3. The name must not be "." or ".." +// 3. The name must not contain / or : or any whitespace characters +// ref to https://github.com/torvalds/linux/blob/master/net/core/dev.c#L1024 +func ValidateInterfaceName(ifName string) *types.Error { + if len(ifName) == 0 { + return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is empty", "") + } + if len(ifName) > maxInterfaceNameLength { + return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is too long", fmt.Sprintf("interface name should be less than %d characters", maxInterfaceNameLength+1)) + } + if ifName == "." || ifName == ".." { + return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is . or ..", "") + } + for _, r := range bytes.Runes([]byte(ifName)) { + if r == '/' || r == ':' || unicode.IsSpace(r) { + return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name contains / or : or whitespace characters", "") + } + } + + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/version/plugin.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/version/plugin.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/version/plugin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/version/plugin.go 2022-01-05 17:30:58.000000000 +0000 @@ -18,6 +18,8 @@ "encoding/json" "fmt" "io" + "strconv" + "strings" ) // PluginInfo reports information about CNI versioning @@ -79,3 +81,64 @@ } return &info, nil } + +// ParseVersion parses a version string like "3.0.1" or "0.4.5" into major, +// minor, and micro numbers or returns an error +func ParseVersion(version string) (int, int, int, error) { + var major, minor, micro int + if version == "" { + return -1, -1, -1, fmt.Errorf("invalid version %q: the version is empty", version) + } + + parts := strings.Split(version, ".") + if len(parts) >= 4 { + return -1, -1, -1, fmt.Errorf("invalid version %q: too many parts", version) + } + + major, err := strconv.Atoi(parts[0]) + if err != nil { + return -1, -1, -1, fmt.Errorf("failed to convert major version part %q: %v", parts[0], err) + } + + if len(parts) >= 2 { + minor, err = strconv.Atoi(parts[1]) + if err != nil { + return -1, -1, -1, fmt.Errorf("failed to convert minor version part %q: %v", parts[1], err) + } + } + + if len(parts) >= 3 { + micro, err = strconv.Atoi(parts[2]) + if err != nil { + return -1, -1, -1, fmt.Errorf("failed to convert micro version part %q: %v", parts[2], err) + } + } + + return major, minor, micro, nil +} + +// GreaterThanOrEqualTo takes two string versions, parses them into major/minor/micro +// numbers, and compares them to determine whether the first version is greater +// than or equal to the second +func GreaterThanOrEqualTo(version, otherVersion string) (bool, error) { + firstMajor, firstMinor, firstMicro, err := ParseVersion(version) + if err != nil { + return false, err + } + + secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion) + if err != nil { + return false, err + } + + if firstMajor > secondMajor { + return true, nil + } else if firstMajor == secondMajor { + if firstMinor > secondMinor { + return true, nil + } else if firstMinor == secondMinor && firstMicro >= secondMicro { + return true, nil + } + } + return false, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/version/version.go containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/version/version.go --- containerd-1.2.6/vendor/github.com/containernetworking/cni/pkg/version/version.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/pkg/version/version.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,6 +15,7 @@ package version import ( + "encoding/json" "fmt" "github.com/containernetworking/cni/pkg/types" @@ -24,7 +25,7 @@ // Current reports the version of the CNI spec implemented by this library func Current() string { - return "0.3.1" + return "0.4.0" } // Legacy PluginInfo describes a plugin that is backwards compatible with the @@ -35,7 +36,7 @@ // Any future CNI spec versions which meet this definition should be added to // this list. var Legacy = PluginSupports("0.1.0", "0.2.0") -var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1") +var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0") var resultFactories = []struct { supportedVersions []string @@ -59,3 +60,24 @@ return nil, fmt.Errorf("unsupported CNI result version %q", version) } + +// ParsePrevResult parses a prevResult in a NetConf structure and sets +// the NetConf's PrevResult member to the parsed Result object. +func ParsePrevResult(conf *types.NetConf) error { + if conf.RawPrevResult == nil { + return nil + } + + resultBytes, err := json.Marshal(conf.RawPrevResult) + if err != nil { + return fmt.Errorf("could not serialize prevResult: %v", err) + } + + conf.RawPrevResult = nil + conf.PrevResult, err = NewResult(conf.CNIVersion, resultBytes) + if err != nil { + return fmt.Errorf("could not parse prevResult: %v", err) + } + + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containernetworking/cni/README.md containerd-1.5.9/vendor/github.com/containernetworking/cni/README.md --- containerd-1.2.6/vendor/github.com/containernetworking/cni/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containernetworking/cni/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -[![Build Status](https://travis-ci.org/containernetworking/cni.svg?branch=master)](https://travis-ci.org/containernetworking/cni) -[![Coverage Status](https://coveralls.io/repos/github/containernetworking/cni/badge.svg?branch=master)](https://coveralls.io/github/containernetworking/cni?branch=master) -[![Slack Status](https://cryptic-tundra-43194.herokuapp.com/badge.svg)](https://cryptic-tundra-43194.herokuapp.com/) - -![CNI Logo](logo.png) - ---- - -# Community Sync Meeting - -There is a community sync meeting for users and developers every 1-2 months. The next meeting will help on a Google Hangout and the link is in the [agenda](https://docs.google.com/document/d/10ECyT2mBGewsJUcmYmS8QNo1AcNgy2ZIe2xS7lShYhE/edit?usp=sharing) (Notes from previous meeting are also in this doc). The next meeting will be held on *Wednesday, June 21th* at *3:00pm UTC* [Add to Calendar]https://www.worldtimebuddy.com/?qm=1&lid=100,5,2643743,5391959&h=100&date=2017-6-21&sln=15-16). - ---- - -# CNI - the Container Network Interface - -## What is CNI? - -CNI (_Container Network Interface_), a [Cloud Native Computing Foundation](https://cncf.io) project, consists of a specification and libraries for writing plugins to configure network interfaces in Linux containers, along with a number of supported plugins. -CNI concerns itself only with network connectivity of containers and removing allocated resources when the container is deleted. -Because of this focus, CNI has a wide range of support and the specification is simple to implement. - -As well as the [specification](SPEC.md), this repository contains the Go source code of a [library for integrating CNI into applications](libcni) and an [example command-line tool](cnitool) for executing CNI plugins. A [separate repository contains reference plugins](https://github.com/containernetworking/plugins) and a template for making new plugins. - -The template code makes it straight-forward to create a CNI plugin for an existing container networking project. -CNI also makes a good framework for creating a new container networking project from scratch. - -## Why develop CNI? - -Application containers on Linux are a rapidly evolving area, and within this area networking is not well addressed as it is highly environment-specific. -We believe that many container runtimes and orchestrators will seek to solve the same problem of making the network layer pluggable. - -To avoid duplication, we think it is prudent to define a common interface between the network plugins and container execution: hence we put forward this specification, along with libraries for Go and a set of plugins. - -## Who is using CNI? -### Container runtimes -- [rkt - container engine](https://coreos.com/blog/rkt-cni-networking.html) -- [Kurma - container runtime](http://kurma.io/) -- [Kubernetes - a system to simplify container operations](http://kubernetes.io/docs/admin/network-plugins/) -- [OpenShift - Kubernetes with additional enterprise features](https://github.com/openshift/origin/blob/master/docs/openshift_networking_requirements.md) -- [Cloud Foundry - a platform for cloud applications](https://github.com/cloudfoundry-incubator/cf-networking-release) -- [Mesos - a distributed systems kernel](https://github.com/apache/mesos/blob/master/docs/cni.md) - -### 3rd party plugins -- [Project Calico - a layer 3 virtual network](https://github.com/projectcalico/calico-cni) -- [Weave - a multi-host Docker network](https://github.com/weaveworks/weave) -- [Contiv Networking - policy networking for various use cases](https://github.com/contiv/netplugin) -- [SR-IOV](https://github.com/hustcat/sriov-cni) -- [Cilium - BPF & XDP for containers](https://github.com/cilium/cilium) -- [Infoblox - enterprise IP address management for containers](https://github.com/infobloxopen/cni-infoblox) -- [Multus - a Multi plugin](https://github.com/Intel-Corp/multus-cni) -- [Romana - Layer 3 CNI plugin supporting network policy for Kubernetes](https://github.com/romana/kube) -- [CNI-Genie - generic CNI network plugin](https://github.com/Huawei-PaaS/CNI-Genie) -- [Nuage CNI - Nuage Networks SDN plugin for network policy kubernetes support ](https://github.com/nuagenetworks/nuage-cni) -- [Silk - a CNI plugin designed for Cloud Foundry](https://github.com/cloudfoundry-incubator/silk) -- [Linen - a CNI plugin designed for overlay networks with Open vSwitch and fit in SDN/OpenFlow network environment](https://github.com/John-Lin/linen-cni) - -The CNI team also maintains some [core plugins in a separate repository](https://github.com/containernetworking/plugins). - - -## Contributing to CNI - -We welcome contributions, including [bug reports](https://github.com/containernetworking/cni/issues), and code and documentation improvements. -If you intend to contribute to code or documentation, please read [CONTRIBUTING.md](CONTRIBUTING.md). Also see the [contact section](#contact) in this README. - -## How do I use CNI? - -### Requirements - -The CNI spec is language agnostic. To use the Go language libraries in this repository, you'll need a recent version of Go. Our [automated tests](https://travis-ci.org/containernetworking/cni/builds) cover Go versions 1.7 and 1.8. - -### Reference Plugins - -The CNI project maintains a set of [reference plugins](https://github.com/containernetworking/plugins) that implement the CNI specification. -NOTE: the reference plugins used to live in this repository but have been split out into a [separate repository](https://github.com/containernetworking/plugins) as of May 2017. - -### Running the plugins - -After building and installing the [reference plugins](https://github.com/containernetworking/plugins), you can use the `priv-net-run.sh` and `docker-run.sh` scripts in the `scripts/` directory to exercise the plugins. - -**note - priv-net-run.sh depends on `jq`** - -Start out by creating a netconf file to describe a network: - -```bash -$ mkdir -p /etc/cni/net.d -$ cat >/etc/cni/net.d/10-mynet.conf </etc/cni/net.d/99-loopback.conf < 0 { + if pkcs11Config == nil { + return CryptoConfig{}, errors.New("pkcs11Config must not be nil") + } + p11confYaml, err := yaml.Marshal(pkcs11Config) + if err != nil { + return CryptoConfig{}, errors.Wrapf(err, "Could not marshal Pkcs11Config to Yaml") + } + + dc = DecryptConfig{ + Parameters: map[string][][]byte{ + "pkcs11-config": {p11confYaml}, + }, + } + ep["pkcs11-yamls"] = pkcs11Yamls + } + if len(pkcs11Pubkeys) > 0 { + ep["pkcs11-pubkeys"] = pkcs11Pubkeys + } + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// EncryptWithKeyProvider returns a CryptoConfig to encrypt with configured keyprovider parameters +func EncryptWithKeyProvider(keyProviders [][]byte) (CryptoConfig, error) { + dc := DecryptConfig{} + ep := make(map[string][][]byte) + for _, keyProvider := range keyProviders { + keyProvidersStr := string(keyProvider) + idx := strings.Index(keyProvidersStr, ":") + if idx > 0 { + ep[keyProvidersStr[:idx]] = append(ep[keyProvidersStr[:idx]], []byte(keyProvidersStr[idx+1:])) + } else { + ep[keyProvidersStr] = append(ep[keyProvidersStr], []byte("Enabled")) + } + } + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// DecryptWithKeyProvider returns a CryptoConfig to decrypt with configured keyprovider parameters +func DecryptWithKeyProvider(keyProviders [][]byte) (CryptoConfig, error) { + dp := make(map[string][][]byte) + ep := map[string][][]byte{} + for _, keyProvider := range keyProviders { + keyProvidersStr := string(keyProvider) + idx := strings.Index(keyProvidersStr, ":") + if idx > 0 { + dp[keyProvidersStr[:idx]] = append(dp[keyProvidersStr[:idx]], []byte(keyProvidersStr[idx+1:])) + } else { + dp[keyProvidersStr] = append(dp[keyProvidersStr], []byte("Enabled")) + } + } + dc := DecryptConfig{ + Parameters: dp, + } + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// DecryptWithPrivKeys returns a CryptoConfig to decrypt with configured private keys +func DecryptWithPrivKeys(privKeys [][]byte, privKeysPasswords [][]byte) (CryptoConfig, error) { + if len(privKeys) != len(privKeysPasswords) { + return CryptoConfig{}, errors.New("Length of privKeys should match length of privKeysPasswords") + } + + dc := DecryptConfig{ + Parameters: map[string][][]byte{ + "privkeys": privKeys, + "privkeys-passwords": privKeysPasswords, + }, + } + + ep := map[string][][]byte{} + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// DecryptWithX509s returns a CryptoConfig to decrypt with configured x509 certs +func DecryptWithX509s(x509s [][]byte) (CryptoConfig, error) { + dc := DecryptConfig{ + Parameters: map[string][][]byte{ + "x509s": x509s, + }, + } + + ep := map[string][][]byte{} + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// DecryptWithGpgPrivKeys returns a CryptoConfig to decrypt with configured gpg private keys +func DecryptWithGpgPrivKeys(gpgPrivKeys, gpgPrivKeysPwds [][]byte) (CryptoConfig, error) { + dc := DecryptConfig{ + Parameters: map[string][][]byte{ + "gpg-privatekeys": gpgPrivKeys, + "gpg-privatekeys-passwords": gpgPrivKeysPwds, + }, + } + + ep := map[string][][]byte{} + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} + +// DecryptWithPkcs11Yaml returns a CryptoConfig to decrypt with pkcs11 YAML formatted key files +func DecryptWithPkcs11Yaml(pkcs11Config *pkcs11.Pkcs11Config, pkcs11Yamls [][]byte) (CryptoConfig, error) { + p11confYaml, err := yaml.Marshal(pkcs11Config) + if err != nil { + return CryptoConfig{}, errors.Wrapf(err, "Could not marshal Pkcs11Config to Yaml") + } + + dc := DecryptConfig{ + Parameters: map[string][][]byte{ + "pkcs11-yamls": pkcs11Yamls, + "pkcs11-config": {p11confYaml}, + }, + } + + ep := map[string][][]byte{} + + return CryptoConfig{ + EncryptConfig: &EncryptConfig{ + Parameters: ep, + DecryptConfig: dc, + }, + DecryptConfig: &dc, + }, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/config/keyprovider-config/config.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/config/keyprovider-config/config.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/config/keyprovider-config/config.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/config/keyprovider-config/config.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,81 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package config + +import ( + "encoding/json" + "github.com/pkg/errors" + "io/ioutil" + "os" +) + +// Command describes the structure of command, it consist of path and args, where path defines the location of +// binary executable and args are passed on to the binary executable +type Command struct { + Path string `json:"path,omitempty"` + Args []string `json:"args,omitempty"` +} + +// KeyProviderAttrs describes the structure of key provider, it defines the way of invocation to key provider +type KeyProviderAttrs struct { + Command *Command `json:"cmd,omitempty"` + Grpc string `json:"grpc,omitempty"` +} + +// OcicryptConfig represents the format of an ocicrypt_provider.conf config file +type OcicryptConfig struct { + KeyProviderConfig map[string]KeyProviderAttrs `json:"key-providers"` +} + +const ENVVARNAME = "OCICRYPT_KEYPROVIDER_CONFIG" + +// parseConfigFile parses a configuration file; it is not an error if the configuration file does +// not exist, so no error is returned. +func parseConfigFile(filename string) (*OcicryptConfig, error) { + // a non-existent config file is not an error + _, err := os.Stat(filename) + if os.IsNotExist(err) { + return nil, nil + } + + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + ic := &OcicryptConfig{} + err = json.Unmarshal(data, ic) + return ic, err +} + +// getConfiguration tries to read the configuration file at the following locations +// ${OCICRYPT_KEYPROVIDER_CONFIG} == "/etc/ocicrypt_keyprovider.yaml" +// If no configuration file could be found or read a null pointer is returned +func GetConfiguration() (*OcicryptConfig, error) { + var ic *OcicryptConfig + var err error + filename := os.Getenv(ENVVARNAME) + if len(filename) > 0 { + ic, err = parseConfigFile(filename) + if err != nil { + return nil, errors.Wrap(err, "Error while parsing keyprovider config file") + } + } else { + return nil, nil + } + return ic, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/common.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/common.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/common.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/common.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,134 @@ +/* + Copyright The ocicrypt Authors. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs11 + +import ( + "fmt" + "github.com/pkg/errors" + pkcs11uri "github.com/stefanberger/go-pkcs11uri" + "gopkg.in/yaml.v2" +) + +// Pkcs11KeyFile describes the format of the pkcs11 (private) key file. +// It also carries pkcs11 module related environment variables that are transferred to the +// Pkcs11URI object and activated when the pkcs11 module is used. +type Pkcs11KeyFile struct { + Pkcs11 struct { + Uri string `yaml:"uri"` + } `yaml:"pkcs11"` + Module struct { + Env map[string]string `yaml:"env,omitempty"` + } `yaml:"module"` +} + +// Pkcs11KeyFileObject is a representation of the Pkcs11KeyFile with the pkcs11 URI as an object +type Pkcs11KeyFileObject struct { + Uri *pkcs11uri.Pkcs11URI +} + +// ParsePkcs11Uri parses a pkcs11 URI +func ParsePkcs11Uri(uri string) (*pkcs11uri.Pkcs11URI, error) { + p11uri := pkcs11uri.New() + err := p11uri.Parse(uri) + if err != nil { + return nil, errors.Wrapf(err, "Could not parse Pkcs11URI from file") + } + return p11uri, err +} + +// ParsePkcs11KeyFile parses a pkcs11 key file holding a pkcs11 URI describing a private key. +// The file has the following yaml format: +// pkcs11: +// - uri : +// An error is returned if the pkcs11 URI is malformed +func ParsePkcs11KeyFile(yamlstr []byte) (*Pkcs11KeyFileObject, error) { + p11keyfile := Pkcs11KeyFile{} + + err := yaml.Unmarshal([]byte(yamlstr), &p11keyfile) + if err != nil { + return nil, errors.Wrapf(err, "Could not unmarshal pkcs11 keyfile") + } + + p11uri, err := ParsePkcs11Uri(p11keyfile.Pkcs11.Uri) + if err != nil { + return nil, err + } + p11uri.SetEnvMap(p11keyfile.Module.Env) + + return &Pkcs11KeyFileObject{Uri: p11uri}, err +} + +// IsPkcs11PrivateKey checks whether the given YAML represents a Pkcs11 private key +func IsPkcs11PrivateKey(yamlstr []byte) bool { + _, err := ParsePkcs11KeyFile(yamlstr) + return err == nil +} + +// IsPkcs11PublicKey checks whether the given YAML represents a Pkcs11 public key +func IsPkcs11PublicKey(yamlstr []byte) bool { + _, err := ParsePkcs11KeyFile(yamlstr) + return err == nil +} + +// Pkcs11Config describes the layout of a pkcs11 config file +// The file has the following yaml format: +// module-directories: +// - /usr/lib64/pkcs11/ +// allowd-module-paths +// - /usr/lib64/pkcs11/libsofthsm2.so +type Pkcs11Config struct { + ModuleDirectories []string `yaml:"module-directories"` + AllowedModulePaths []string `yaml:"allowed-module-paths"` +} + +// GetDefaultModuleDirectories returns module directories covering +// a variety of Linux distros +func GetDefaultModuleDirectories() []string { + dirs := []string{ + "/usr/lib64/pkcs11/", // Fedora,RHEL,openSUSE + "/usr/lib/pkcs11/", // Fedora,ArchLinux + "/usr/local/lib/pkcs11/", + "/usr/lib/softhsm/", // Debian,Ubuntu + } + + // Debian directory: /usr/lib/(x86_64|aarch64|arm|powerpc64le|s390x)-linux-gnu/ + hosttype, ostype, q := getHostAndOsType() + if len(hosttype) > 0 { + dir := fmt.Sprintf("/usr/lib/%s-%s-%s/", hosttype, ostype, q) + dirs = append(dirs, dir) + } + return dirs +} + +// GetDefaultModuleDirectoresFormatted returns the default module directories formatted for YAML +func GetDefaultModuleDirectoriesYaml(indent string) string { + res := "" + + for _, dir := range GetDefaultModuleDirectories() { + res += indent + "- " + dir + "\n" + } + return res +} + +// ParsePkcs11ConfigFile parses a pkcs11 config file hat influences the module search behavior +// as well as the set of modules that users are allowed to use +func ParsePkcs11ConfigFile(yamlstr []byte) (*Pkcs11Config, error) { + p11conf := Pkcs11Config{} + + err := yaml.Unmarshal([]byte(yamlstr), &p11conf) + if err != nil { + return &p11conf, errors.Wrapf(err, "Could not parse Pkcs11Config") + } + return &p11conf, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,487 @@ +// +build cgo + +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs11 + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "hash" + "net/url" + "os" + "strconv" + "strings" + + "github.com/miekg/pkcs11" + "github.com/pkg/errors" + pkcs11uri "github.com/stefanberger/go-pkcs11uri" +) + +var ( + // OAEPLabel defines the label we use for OAEP encryption; this cannot be changed + OAEPLabel = []byte("") + // OAEPDefaultHash defines the default hash used for OAEP encryption; this cannot be changed + OAEPDefaultHash = "sha1" + + // OAEPSha1Params describes the OAEP parameters with sha1 hash algorithm; needed by SoftHSM + OAEPSha1Params = &pkcs11.OAEPParams{ + HashAlg: pkcs11.CKM_SHA_1, + MGF: pkcs11.CKG_MGF1_SHA1, + SourceType: pkcs11.CKZ_DATA_SPECIFIED, + SourceData: OAEPLabel, + } + // OAEPSha256Params describes the OAEP parameters with sha256 hash algorithm + OAEPSha256Params = &pkcs11.OAEPParams{ + HashAlg: pkcs11.CKM_SHA256, + MGF: pkcs11.CKG_MGF1_SHA256, + SourceType: pkcs11.CKZ_DATA_SPECIFIED, + SourceData: OAEPLabel, + } +) + +// rsaPublicEncryptOAEP encrypts the given plaintext with the given *rsa.PublicKey; the +// environment variable OCICRYPT_OAEP_HASHALG can be set to 'sha1' to force usage of sha1 for OAEP (SoftHSM). +// This function is needed by clients who are using a public key file for pkcs11 encryption +func rsaPublicEncryptOAEP(pubKey *rsa.PublicKey, plaintext []byte) ([]byte, string, error) { + var ( + hashfunc hash.Hash + hashalg string + ) + + oaephash := os.Getenv("OCICRYPT_OAEP_HASHALG") + // The default is 'sha1' + switch strings.ToLower(oaephash) { + case "sha1", "": + hashfunc = sha1.New() + hashalg = "sha1" + case "sha256": + hashfunc = sha256.New() + hashalg = "sha256" + default: + return nil, "", errors.Errorf("Unsupported OAEP hash '%s'", oaephash) + } + ciphertext, err := rsa.EncryptOAEP(hashfunc, rand.Reader, pubKey, plaintext, OAEPLabel) + if err != nil { + return nil, "", errors.Wrapf(err, "rss.EncryptOAEP failed") + } + + return ciphertext, hashalg, nil +} + +// pkcs11UriGetLoginParameters gets the parameters necessary for login from the Pkcs11URI +// PIN and module are mandatory; slot-id is optional and if not found -1 will be returned +// For a privateKeyOperation a PIN is required and if none is given, this function will return an error +func pkcs11UriGetLoginParameters(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperation bool) (string, string, int64, error) { + var ( + pin string + err error + ) + if privateKeyOperation { + if !p11uri.HasPIN() { + return "", "", 0, errors.New("Missing PIN for private key operation") + } + } + // some devices require a PIN to find a *public* key object, others don't + pin, _ = p11uri.GetPIN() + + module, err := p11uri.GetModule() + if err != nil { + return "", "", 0, errors.Wrap(err, "No module available in pkcs11 URI") + } + + slotid := int64(-1) + + slot, ok := p11uri.GetPathAttribute("slot-id", false) + if ok { + slotid, err = strconv.ParseInt(slot, 10, 64) + if err != nil { + return "", "", 0, errors.Wrap(err, "slot-id is not a valid number") + } + if slotid < 0 { + return "", "", 0, fmt.Errorf("slot-id is a negative number") + } + if uint64(slotid) > 0xffffffff { + return "", "", 0, fmt.Errorf("slot-id is larger than 32 bit") + } + } + + return pin, module, slotid, nil +} + +// pkcs11UriGetKeyIdAndLabel gets the key label by retrieving the value of the 'object' attribute +func pkcs11UriGetKeyIdAndLabel(p11uri *pkcs11uri.Pkcs11URI) (string, string, error) { + keyid, ok2 := p11uri.GetPathAttribute("id", false) + label, ok1 := p11uri.GetPathAttribute("object", false) + if !ok1 && !ok2 { + return "", "", errors.New("Neither 'id' nor 'object' attributes were found in pkcs11 URI") + } + return keyid, label, nil +} + +// pkcs11OpenSession opens a session with a pkcs11 device at the given slot and logs in with the given PIN +func pkcs11OpenSession(p11ctx *pkcs11.Ctx, slotid uint, pin string) (session pkcs11.SessionHandle, err error) { + session, err = p11ctx.OpenSession(uint(slotid), pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) + if err != nil { + return 0, errors.Wrapf(err, "OpenSession to slot %d failed", slotid) + } + if len(pin) > 0 { + err = p11ctx.Login(session, pkcs11.CKU_USER, pin) + if err != nil { + _ = p11ctx.CloseSession(session) + return 0, errors.Wrap(err, "Could not login to device") + } + } + return session, nil +} + +// pkcs11UriLogin uses the given pkcs11 URI to select the pkcs11 module (share libary) and to get +// the PIN to use for login; if the URI contains a slot-id, the given slot-id will be used, otherwise +// one slot after the other will be attempted and the first one where login succeeds will be used +func pkcs11UriLogin(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperation bool) (ctx *pkcs11.Ctx, session pkcs11.SessionHandle, err error) { + pin, module, slotid, err := pkcs11UriGetLoginParameters(p11uri, privateKeyOperation) + if err != nil { + return nil, 0, err + } + + p11ctx := pkcs11.New(module) + if p11ctx == nil { + return nil, 0, errors.New("Please check module path, input is: " + module) + } + + err = p11ctx.Initialize() + if err != nil { + p11Err := err.(pkcs11.Error) + if p11Err != pkcs11.CKR_CRYPTOKI_ALREADY_INITIALIZED { + return nil, 0, errors.Wrap(err, "Initialize failed") + } + } + + if slotid >= 0 { + session, err := pkcs11OpenSession(p11ctx, uint(slotid), pin) + return p11ctx, session, err + } else { + slots, err := p11ctx.GetSlotList(true) + if err != nil { + return nil, 0, errors.Wrap(err, "GetSlotList failed") + } + + tokenlabel, ok := p11uri.GetPathAttribute("token", false) + if !ok { + return nil, 0, errors.New("Missing 'token' attribute since 'slot-id' was not given") + } + + for _, slot := range slots { + ti, err := p11ctx.GetTokenInfo(slot) + if err != nil || ti.Label != tokenlabel { + continue + } + + session, err = pkcs11OpenSession(p11ctx, slot, pin) + if err == nil { + return p11ctx, session, err + } + } + if len(pin) > 0 { + return nil, 0, errors.New("Could not create session to any slot and/or log in") + } + return nil, 0, errors.New("Could not create session to any slot") + } +} + +func pkcs11Logout(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) { + _ = ctx.Logout(session) + _ = ctx.CloseSession(session) + _ = ctx.Finalize() + ctx.Destroy() +} + +// findObject finds an object of the given class with the given keyid and/or label +func findObject(p11ctx *pkcs11.Ctx, session pkcs11.SessionHandle, class uint, keyid, label string) (pkcs11.ObjectHandle, error) { + msg := "" + + template := []*pkcs11.Attribute{ + pkcs11.NewAttribute(pkcs11.CKA_CLASS, class), + } + if len(label) > 0 { + template = append(template, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label)) + msg = fmt.Sprintf("label '%s'", label) + } + if len(keyid) > 0 { + template = append(template, pkcs11.NewAttribute(pkcs11.CKA_ID, keyid)) + if len(msg) > 0 { + msg += " and " + } + msg += url.PathEscape(keyid) + } + + if err := p11ctx.FindObjectsInit(session, template); err != nil { + return 0, errors.Wrap(err, "FindObjectsInit failed") + } + + obj, _, err := p11ctx.FindObjects(session, 100) + if err != nil { + return 0, errors.Wrap(err, "FindObjects failed") + } + + if err := p11ctx.FindObjectsFinal(session); err != nil { + return 0, errors.Wrap(err, "FindObjectsFinal failed") + } + if len(obj) > 1 { + return 0, errors.Errorf("There are too many (=%d) keys with %s", len(obj), msg) + } else if len(obj) == 1 { + return obj[0], nil + } + + return 0, errors.Errorf("Could not find any object with %s", msg) +} + +// publicEncryptOAEP uses a public key described by a pkcs11 URI to OAEP encrypt the given plaintext +func publicEncryptOAEP(pubKey *Pkcs11KeyFileObject, plaintext []byte) ([]byte, string, error) { + oldenv, err := setEnvVars(pubKey.Uri.GetEnvMap()) + if err != nil { + return nil, "", err + } + defer restoreEnv(oldenv) + + p11ctx, session, err := pkcs11UriLogin(pubKey.Uri, false) + if err != nil { + return nil, "", err + } + defer pkcs11Logout(p11ctx, session) + + keyid, label, err := pkcs11UriGetKeyIdAndLabel(pubKey.Uri) + if err != nil { + return nil, "", err + } + + p11PubKey, err := findObject(p11ctx, session, pkcs11.CKO_PUBLIC_KEY, keyid, label) + if err != nil { + return nil, "", err + } + + var hashalg string + + var oaep *pkcs11.OAEPParams + oaephash := os.Getenv("OCICRYPT_OAEP_HASHALG") + // the default is sha1 + switch strings.ToLower(oaephash) { + case "sha1", "": + oaep = OAEPSha1Params + hashalg = "sha1" + case "sha256": + oaep = OAEPSha256Params + hashalg = "sha256" + default: + return nil, "", errors.Errorf("Unsupported OAEP hash '%s'", oaephash) + } + + err = p11ctx.EncryptInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_OAEP, oaep)}, p11PubKey) + if err != nil { + return nil, "", errors.Wrap(err, "EncryptInit error") + } + + ciphertext, err := p11ctx.Encrypt(session, plaintext) + if err != nil { + return nil, "", errors.Wrap(err, "Encrypt failed") + } + return ciphertext, hashalg, nil +} + +// privateDecryptOAEP uses a pkcs11 URI describing a private key to OAEP decrypt a ciphertext +func privateDecryptOAEP(privKeyObj *Pkcs11KeyFileObject, ciphertext []byte, hashalg string) ([]byte, error) { + oldenv, err := setEnvVars(privKeyObj.Uri.GetEnvMap()) + if err != nil { + return nil, err + } + defer restoreEnv(oldenv) + + p11ctx, session, err := pkcs11UriLogin(privKeyObj.Uri, true) + if err != nil { + return nil, err + } + defer pkcs11Logout(p11ctx, session) + + keyid, label, err := pkcs11UriGetKeyIdAndLabel(privKeyObj.Uri) + if err != nil { + return nil, err + } + + p11PrivKey, err := findObject(p11ctx, session, pkcs11.CKO_PRIVATE_KEY, keyid, label) + if err != nil { + return nil, err + } + + var oaep *pkcs11.OAEPParams + + // the default is sha1 + switch hashalg { + case "sha1", "": + oaep = OAEPSha1Params + case "sha256": + oaep = OAEPSha256Params + default: + return nil, errors.Errorf("Unsupported hash algorithm '%s' for decryption", hashalg) + } + + err = p11ctx.DecryptInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_OAEP, oaep)}, p11PrivKey) + if err != nil { + return nil, errors.Wrapf(err, "DecryptInit failed") + } + plaintext, err := p11ctx.Decrypt(session, ciphertext) + if err != nil { + return nil, errors.Wrapf(err, "Decrypt failed") + } + return plaintext, err +} + +// +// The following part deals with the JSON formatted message for multiple pkcs11 recipients +// + +// Pkcs11Blob holds the encrypted blobs for all recipients; this is what we will put into the image's annotations +type Pkcs11Blob struct { + Version uint `json:"version"` + Recipients []Pkcs11Recipient `json:"recipients"` +} + +// Pkcs11Recipient holds the b64-encoded and encrypted blob for a particular recipient +type Pkcs11Recipient struct { + Version uint `json:"version"` + Blob string `json:"blob"` + Hash string `json:"hash,omitempty"` +} + +// EncryptMultiple encrypts for one or multiple pkcs11 devices; the public keys passed to this function +// may either be *rsa.PublicKey or *pkcs11uri.Pkcs11URI; the returned byte array is a JSON string of the +// following format: +// { +// recipients: [ // recipient list +// { +// "version": 0, +// "blob": , +// "hash": +// } , +// { +// "version": 0, +// "blob": , +// "hash": +// } , +// [...] +// ] +// } +func EncryptMultiple(pubKeys []interface{}, data []byte) ([]byte, error) { + var ( + ciphertext []byte + err error + pkcs11blob Pkcs11Blob = Pkcs11Blob{Version: 0} + hashalg string + ) + + for _, pubKey := range pubKeys { + switch pkey := pubKey.(type) { + case *rsa.PublicKey: + ciphertext, hashalg, err = rsaPublicEncryptOAEP(pkey, data) + case *Pkcs11KeyFileObject: + ciphertext, hashalg, err = publicEncryptOAEP(pkey, data) + default: + err = errors.Errorf("Unsupported key object type for pkcs11 public key") + } + if err != nil { + return nil, err + } + + if hashalg == OAEPDefaultHash { + hashalg = "" + } + recipient := Pkcs11Recipient{ + Version: 0, + Blob: base64.StdEncoding.EncodeToString(ciphertext), + Hash: hashalg, + } + + pkcs11blob.Recipients = append(pkcs11blob.Recipients, recipient) + } + return json.Marshal(&pkcs11blob) +} + +// Decrypt tries to decrypt one of the recipients' blobs using a pkcs11 private key. +// The input pkcs11blobstr is a string with the following format: +// { +// recipients: [ // recipient list +// { +// "version": 0, +// "blob": , +// "hash": +// } , +// { +// "version": 0, +// "blob": , +// "hash": +// } , +// [...] +// } +func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte, error) { + pkcs11blob := Pkcs11Blob{} + err := json.Unmarshal(pkcs11blobstr, &pkcs11blob) + if err != nil { + return nil, errors.Wrapf(err, "Could not parse Pkcs11Blob") + } + switch pkcs11blob.Version { + case 0: + // latest supported version + default: + return nil, errors.Errorf("Found Pkcs11Blob with version %d but maximum supported version is 0.", pkcs11blob.Version) + } + // since we do trial and error, collect all encountered errors + errs := "" + + for _, recipient := range pkcs11blob.Recipients { + switch recipient.Version { + case 0: + // last supported version + default: + return nil, errors.Errorf("Found Pkcs11Recipient with version %d but maximum supported version is 0.", recipient.Version) + } + + ciphertext, err := base64.StdEncoding.DecodeString(recipient.Blob) + if err != nil || len(ciphertext) == 0 { + // This should never happen... we skip over decoding issues + errs += fmt.Sprintf("Base64 decoding failed: %s\n", err) + continue + } + // try all keys until one works + for _, privKeyObj := range privKeyObjs { + plaintext, err := privateDecryptOAEP(privKeyObj, ciphertext, recipient.Hash) + if err == nil { + return plaintext, nil + } + if uri, err2 := privKeyObj.Uri.Format(); err2 == nil { + errs += fmt.Sprintf("%s : %s\n", uri, err) + } else { + errs += fmt.Sprintf("%s\n", err) + } + } + } + + return nil, errors.Errorf("Could not find a pkcs11 key for decryption:\n%s", errs) +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers_nocgo.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers_nocgo.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers_nocgo.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/pkcs11helpers_nocgo.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,31 @@ +// +build !cgo + +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs11 + +import ( + "github.com/pkg/errors" +) + +func EncryptMultiple(pubKeys []interface{}, data []byte) ([]byte, error) { + return nil, errors.Errorf("ocicrypt pkcs11 not supported on this build") +} + +func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte, error) { + return nil, errors.Errorf("ocicrypt pkcs11 not supported on this build") +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/utils.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/utils.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/crypto/pkcs11/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/crypto/pkcs11/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,114 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs11 + +import ( + "os" + "runtime" + "strings" + "sync" + + "github.com/pkg/errors" +) + +var ( + envLock sync.Mutex +) + +// setEnvVars sets the environment variables given in the map and locks the environment from +// modification with the same function; if successful, you *must* call restoreEnv with the return +// value from this function +func setEnvVars(env map[string]string) ([]string, error) { + envLock.Lock() + + if len(env) == 0 { + return nil, nil + } + + oldenv := os.Environ() + + for k, v := range env { + err := os.Setenv(k, v) + if err != nil { + restoreEnv(oldenv) + return nil, errors.Wrapf(err, "Could not set environment variable '%s' to '%s'", k, v) + } + } + + return oldenv, nil +} + +func arrayToMap(elements []string) map[string]string { + o := make(map[string]string) + + for _, element := range elements { + p := strings.SplitN(element, "=", 2) + if len(p) == 2 { + o[p[0]] = p[1] + } + } + + return o +} + +// restoreEnv restores the environment to be exactly as given in the array of strings +// and unlocks the lock +func restoreEnv(envs []string) { + if envs != nil && len(envs) >= 0 { + target := arrayToMap(envs) + curr := arrayToMap(os.Environ()) + + for nc, vc := range curr { + vt, ok := target[nc] + if !ok { + os.Unsetenv(nc) + } else if vc == vt { + delete(target, nc) + } + } + + for nt, vt := range target { + os.Setenv(nt, vt) + } + } + + envLock.Unlock() +} + +func getHostAndOsType() (string, string, string) { + ht := "" + ot := "" + st := "" + switch runtime.GOOS { + case "linux": + ot = "linux" + st = "gnu" + switch runtime.GOARCH { + case "arm": + ht = "arm" + case "arm64": + ht = "aarch64" + case "amd64": + ht = "x86_64" + case "ppc64le": + ht = "powerpc64le" + case "s390x": + ht = "s390x" + } + } + return ht, ot, st +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/encryption.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/encryption.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/encryption.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/encryption.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,350 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ocicrypt + +import ( + "encoding/base64" + "encoding/json" + "fmt" + keyproviderconfig "github.com/containers/ocicrypt/config/keyprovider-config" + "github.com/containers/ocicrypt/keywrap/keyprovider" + "io" + "strings" + + "github.com/containers/ocicrypt/blockcipher" + "github.com/containers/ocicrypt/config" + "github.com/containers/ocicrypt/keywrap" + "github.com/containers/ocicrypt/keywrap/jwe" + "github.com/containers/ocicrypt/keywrap/pgp" + "github.com/containers/ocicrypt/keywrap/pkcs11" + "github.com/containers/ocicrypt/keywrap/pkcs7" + "github.com/opencontainers/go-digest" + log "github.com/sirupsen/logrus" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +// EncryptLayerFinalizer is a finalizer run to return the annotations to set for +// the encrypted layer +type EncryptLayerFinalizer func() (map[string]string, error) + +func init() { + keyWrappers = make(map[string]keywrap.KeyWrapper) + keyWrapperAnnotations = make(map[string]string) + RegisterKeyWrapper("pgp", pgp.NewKeyWrapper()) + RegisterKeyWrapper("jwe", jwe.NewKeyWrapper()) + RegisterKeyWrapper("pkcs7", pkcs7.NewKeyWrapper()) + RegisterKeyWrapper("pkcs11", pkcs11.NewKeyWrapper()) + ic, err := keyproviderconfig.GetConfiguration() + if err != nil { + log.Error(err) + } else if ic != nil { + for provider, attrs := range ic.KeyProviderConfig { + RegisterKeyWrapper("provider."+provider, keyprovider.NewKeyWrapper(provider, attrs)) + } + } +} + +var keyWrappers map[string]keywrap.KeyWrapper +var keyWrapperAnnotations map[string]string + +// RegisterKeyWrapper allows to register key wrappers by their encryption scheme +func RegisterKeyWrapper(scheme string, iface keywrap.KeyWrapper) { + keyWrappers[scheme] = iface + keyWrapperAnnotations[iface.GetAnnotationID()] = scheme +} + +// GetKeyWrapper looks up the encryptor interface given an encryption scheme (gpg, jwe) +func GetKeyWrapper(scheme string) keywrap.KeyWrapper { + return keyWrappers[scheme] +} + +// GetWrappedKeysMap returns a map of wrappedKeys as values in a +// map with the encryption scheme(s) as the key(s) +func GetWrappedKeysMap(desc ocispec.Descriptor) map[string]string { + wrappedKeysMap := make(map[string]string) + + for annotationsID, scheme := range keyWrapperAnnotations { + if annotation, ok := desc.Annotations[annotationsID]; ok { + wrappedKeysMap[scheme] = annotation + } + } + return wrappedKeysMap +} + +// EncryptLayer encrypts the layer by running one encryptor after the other +func EncryptLayer(ec *config.EncryptConfig, encOrPlainLayerReader io.Reader, desc ocispec.Descriptor) (io.Reader, EncryptLayerFinalizer, error) { + var ( + encLayerReader io.Reader + err error + encrypted bool + bcFin blockcipher.Finalizer + privOptsData []byte + pubOptsData []byte + ) + + if ec == nil { + return nil, nil, errors.New("EncryptConfig must not be nil") + } + + for annotationsID := range keyWrapperAnnotations { + annotation := desc.Annotations[annotationsID] + if annotation != "" { + privOptsData, err = decryptLayerKeyOptsData(&ec.DecryptConfig, desc) + if err != nil { + return nil, nil, err + } + pubOptsData, err = getLayerPubOpts(desc) + if err != nil { + return nil, nil, err + } + // already encrypted! + encrypted = true + } + } + + if !encrypted { + encLayerReader, bcFin, err = commonEncryptLayer(encOrPlainLayerReader, desc.Digest, blockcipher.AES256CTR) + if err != nil { + return nil, nil, err + } + } + + encLayerFinalizer := func() (map[string]string, error) { + // If layer was already encrypted, bcFin should be nil, use existing optsData + if bcFin != nil { + opts, err := bcFin() + if err != nil { + return nil, err + } + privOptsData, err = json.Marshal(opts.Private) + if err != nil { + return nil, errors.Wrapf(err, "could not JSON marshal opts") + } + pubOptsData, err = json.Marshal(opts.Public) + if err != nil { + return nil, errors.Wrapf(err, "could not JSON marshal opts") + } + } + + newAnnotations := make(map[string]string) + keysWrapped := false + for annotationsID, scheme := range keyWrapperAnnotations { + b64Annotations := desc.Annotations[annotationsID] + keywrapper := GetKeyWrapper(scheme) + b64Annotations, err = preWrapKeys(keywrapper, ec, b64Annotations, privOptsData) + if err != nil { + return nil, err + } + if b64Annotations != "" { + keysWrapped = true + newAnnotations[annotationsID] = b64Annotations + } + } + + if !keysWrapped { + return nil, errors.New("no wrapped keys produced by encryption") + } + newAnnotations["org.opencontainers.image.enc.pubopts"] = base64.StdEncoding.EncodeToString(pubOptsData) + + if len(newAnnotations) == 0 { + return nil, errors.New("no encryptor found to handle encryption") + } + + return newAnnotations, err + } + + // if nothing was encrypted, we just return encLayer = nil + return encLayerReader, encLayerFinalizer, err + +} + +// preWrapKeys calls WrapKeys and handles the base64 encoding and concatenation of the +// annotation data +func preWrapKeys(keywrapper keywrap.KeyWrapper, ec *config.EncryptConfig, b64Annotations string, optsData []byte) (string, error) { + newAnnotation, err := keywrapper.WrapKeys(ec, optsData) + if err != nil || len(newAnnotation) == 0 { + return b64Annotations, err + } + b64newAnnotation := base64.StdEncoding.EncodeToString(newAnnotation) + if b64Annotations == "" { + return b64newAnnotation, nil + } + return b64Annotations + "," + b64newAnnotation, nil +} + +// DecryptLayer decrypts a layer trying one keywrap.KeyWrapper after the other to see whether it +// can apply the provided private key +// If unwrapOnly is set we will only try to decrypt the layer encryption key and return +func DecryptLayer(dc *config.DecryptConfig, encLayerReader io.Reader, desc ocispec.Descriptor, unwrapOnly bool) (io.Reader, digest.Digest, error) { + if dc == nil { + return nil, "", errors.New("DecryptConfig must not be nil") + } + privOptsData, err := decryptLayerKeyOptsData(dc, desc) + if err != nil || unwrapOnly { + return nil, "", err + } + + var pubOptsData []byte + pubOptsData, err = getLayerPubOpts(desc) + if err != nil { + return nil, "", err + } + + return commonDecryptLayer(encLayerReader, privOptsData, pubOptsData) +} + +func decryptLayerKeyOptsData(dc *config.DecryptConfig, desc ocispec.Descriptor) ([]byte, error) { + privKeyGiven := false + errs := "" + for annotationsID, scheme := range keyWrapperAnnotations { + b64Annotation := desc.Annotations[annotationsID] + if b64Annotation != "" { + keywrapper := GetKeyWrapper(scheme) + + if keywrapper.NoPossibleKeys(dc.Parameters) { + continue + } + + if len(keywrapper.GetPrivateKeys(dc.Parameters)) > 0 { + privKeyGiven = true + } + optsData, err := preUnwrapKey(keywrapper, dc, b64Annotation) + if err != nil { + // try next keywrap.KeyWrapper + errs += fmt.Sprintf("%s\n", err) + continue + } + if optsData == nil { + // try next keywrap.KeyWrapper + continue + } + return optsData, nil + } + } + if !privKeyGiven { + return nil, errors.New("missing private key needed for decryption") + } + return nil, errors.Errorf("no suitable key unwrapper found or none of the private keys could be used for decryption:\n%s", errs) +} + +func getLayerPubOpts(desc ocispec.Descriptor) ([]byte, error) { + pubOptsString := desc.Annotations["org.opencontainers.image.enc.pubopts"] + if pubOptsString == "" { + return json.Marshal(blockcipher.PublicLayerBlockCipherOptions{}) + } + return base64.StdEncoding.DecodeString(pubOptsString) +} + +// preUnwrapKey decodes the comma separated base64 strings and calls the Unwrap function +// of the given keywrapper with it and returns the result in case the Unwrap functions +// does not return an error. If all attempts fail, an error is returned. +func preUnwrapKey(keywrapper keywrap.KeyWrapper, dc *config.DecryptConfig, b64Annotations string) ([]byte, error) { + if b64Annotations == "" { + return nil, nil + } + errs := "" + for _, b64Annotation := range strings.Split(b64Annotations, ",") { + annotation, err := base64.StdEncoding.DecodeString(b64Annotation) + if err != nil { + return nil, errors.New("could not base64 decode the annotation") + } + optsData, err := keywrapper.UnwrapKey(dc, annotation) + if err != nil { + errs += fmt.Sprintf("- %s\n", err) + continue + } + return optsData, nil + } + return nil, errors.Errorf("no suitable key found for decrypting layer key:\n%s", errs) +} + +// commonEncryptLayer is a function to encrypt the plain layer using a new random +// symmetric key and return the LayerBlockCipherHandler's JSON in string form for +// later use during decryption +func commonEncryptLayer(plainLayerReader io.Reader, d digest.Digest, typ blockcipher.LayerCipherType) (io.Reader, blockcipher.Finalizer, error) { + lbch, err := blockcipher.NewLayerBlockCipherHandler() + if err != nil { + return nil, nil, err + } + + encLayerReader, bcFin, err := lbch.Encrypt(plainLayerReader, typ) + if err != nil { + return nil, nil, err + } + + newBcFin := func() (blockcipher.LayerBlockCipherOptions, error) { + lbco, err := bcFin() + if err != nil { + return blockcipher.LayerBlockCipherOptions{}, err + } + lbco.Private.Digest = d + return lbco, nil + } + + return encLayerReader, newBcFin, err +} + +// commonDecryptLayer decrypts an encrypted layer previously encrypted with commonEncryptLayer +// by passing along the optsData +func commonDecryptLayer(encLayerReader io.Reader, privOptsData []byte, pubOptsData []byte) (io.Reader, digest.Digest, error) { + privOpts := blockcipher.PrivateLayerBlockCipherOptions{} + err := json.Unmarshal(privOptsData, &privOpts) + if err != nil { + return nil, "", errors.Wrapf(err, "could not JSON unmarshal privOptsData") + } + + lbch, err := blockcipher.NewLayerBlockCipherHandler() + if err != nil { + return nil, "", err + } + + pubOpts := blockcipher.PublicLayerBlockCipherOptions{} + if len(pubOptsData) > 0 { + err := json.Unmarshal(pubOptsData, &pubOpts) + if err != nil { + return nil, "", errors.Wrapf(err, "could not JSON unmarshal pubOptsData") + } + } + + opts := blockcipher.LayerBlockCipherOptions{ + Private: privOpts, + Public: pubOpts, + } + + plainLayerReader, opts, err := lbch.Decrypt(encLayerReader, opts) + if err != nil { + return nil, "", err + } + + return plainLayerReader, opts.Private.Digest, nil +} + +// FilterOutAnnotations filters out the annotations belonging to the image encryption 'namespace' +// and returns a map with those taken out +func FilterOutAnnotations(annotations map[string]string) map[string]string { + a := make(map[string]string) + if len(annotations) > 0 { + for k, v := range annotations { + if strings.HasPrefix(k, "org.opencontainers.image.enc.") { + continue + } + a[k] = v + } + } + return a +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/go.mod containerd-1.5.9/vendor/github.com/containers/ocicrypt/go.mod --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +module github.com/containers/ocicrypt + +go 1.12 + +require ( + github.com/golang/protobuf v1.4.3 + github.com/google/go-cmp v0.5.2 // indirect + github.com/miekg/pkcs11 v1.0.3 + github.com/opencontainers/go-digest v1.0.0 + github.com/opencontainers/image-spec v1.0.1 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.7.0 + github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 + github.com/stretchr/testify v1.3.0 + go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 + google.golang.org/grpc v1.33.2 + gopkg.in/square/go-jose.v2 v2.5.1 + gopkg.in/yaml.v2 v2.4.0 +) diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/go.sum containerd-1.5.9/vendor/github.com/containers/ocicrypt/go.sum --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,117 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 h1:lIOOHPEbXzO3vnmx2gok1Tfs31Q8GQqKLc8vVqyQq/I= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/gpg.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/gpg.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/gpg.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/gpg.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,425 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ocicrypt + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "golang.org/x/term" +) + +// GPGVersion enum representing the GPG client version to use. +type GPGVersion int + +const ( + // GPGv2 signifies gpgv2+ + GPGv2 GPGVersion = iota + // GPGv1 signifies gpgv1+ + GPGv1 + // GPGVersionUndetermined signifies gpg client version undetermined + GPGVersionUndetermined +) + +// GPGClient defines an interface for wrapping the gpg command line tools +type GPGClient interface { + // ReadGPGPubRingFile gets the byte sequence of the gpg public keyring + ReadGPGPubRingFile() ([]byte, error) + // GetGPGPrivateKey gets the private key bytes of a keyid given a passphrase + GetGPGPrivateKey(keyid uint64, passphrase string) ([]byte, error) + // GetSecretKeyDetails gets the details of a secret key + GetSecretKeyDetails(keyid uint64) ([]byte, bool, error) + // GetKeyDetails gets the details of a public key + GetKeyDetails(keyid uint64) ([]byte, bool, error) + // ResolveRecipients resolves PGP key ids to user names + ResolveRecipients([]string) []string +} + +// gpgClient contains generic gpg client information +type gpgClient struct { + gpgHomeDir string +} + +// gpgv2Client is a gpg2 client +type gpgv2Client struct { + gpgClient +} + +// gpgv1Client is a gpg client +type gpgv1Client struct { + gpgClient +} + +// GuessGPGVersion guesses the version of gpg. Defaults to gpg2 if exists, if +// not defaults to regular gpg. +func GuessGPGVersion() GPGVersion { + if err := exec.Command("gpg2", "--version").Run(); err == nil { + return GPGv2 + } else if err := exec.Command("gpg", "--version").Run(); err == nil { + return GPGv1 + } else { + return GPGVersionUndetermined + } +} + +// NewGPGClient creates a new GPGClient object representing the given version +// and using the given home directory +func NewGPGClient(gpgVersion, gpgHomeDir string) (GPGClient, error) { + v := new(GPGVersion) + switch gpgVersion { + case "v1": + *v = GPGv1 + case "v2": + *v = GPGv2 + default: + v = nil + } + return newGPGClient(v, gpgHomeDir) +} + +func newGPGClient(version *GPGVersion, homedir string) (GPGClient, error) { + var gpgVersion GPGVersion + if version != nil { + gpgVersion = *version + } else { + gpgVersion = GuessGPGVersion() + } + + switch gpgVersion { + case GPGv1: + return &gpgv1Client{ + gpgClient: gpgClient{gpgHomeDir: homedir}, + }, nil + case GPGv2: + return &gpgv2Client{ + gpgClient: gpgClient{gpgHomeDir: homedir}, + }, nil + case GPGVersionUndetermined: + return nil, fmt.Errorf("unable to determine GPG version") + default: + return nil, fmt.Errorf("unhandled case: NewGPGClient") + } +} + +// GetGPGPrivateKey gets the bytes of a specified keyid, supplying a passphrase +func (gc *gpgv2Client) GetGPGPrivateKey(keyid uint64, passphrase string) ([]byte, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = append(args, []string{"--homedir", gc.gpgHomeDir}...) + } + + rfile, wfile, err := os.Pipe() + if err != nil { + return nil, errors.Wrapf(err, "could not create pipe") + } + defer func() { + rfile.Close() + wfile.Close() + }() + // fill pipe in background + go func(passphrase string) { + _, _ = wfile.Write([]byte(passphrase)) + wfile.Close() + }(passphrase) + + args = append(args, []string{"--pinentry-mode", "loopback", "--batch", "--passphrase-fd", fmt.Sprintf("%d", 3), "--export-secret-key", fmt.Sprintf("0x%x", keyid)}...) + + cmd := exec.Command("gpg2", args...) + cmd.ExtraFiles = []*os.File{rfile} + + return runGPGGetOutput(cmd) +} + +// ReadGPGPubRingFile reads the GPG public key ring file +func (gc *gpgv2Client) ReadGPGPubRingFile() ([]byte, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = append(args, []string{"--homedir", gc.gpgHomeDir}...) + } + args = append(args, []string{"--batch", "--export"}...) + + cmd := exec.Command("gpg2", args...) + + return runGPGGetOutput(cmd) +} + +func (gc *gpgv2Client) getKeyDetails(option string, keyid uint64) ([]byte, bool, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = []string{"--homedir", gc.gpgHomeDir} + } + args = append(args, option, fmt.Sprintf("0x%x", keyid)) + + cmd := exec.Command("gpg2", args...) + + keydata, err := runGPGGetOutput(cmd) + return keydata, err == nil, err +} + +// GetSecretKeyDetails retrieves the secret key details of key with keyid. +// returns a byte array of the details and a bool if the key exists +func (gc *gpgv2Client) GetSecretKeyDetails(keyid uint64) ([]byte, bool, error) { + return gc.getKeyDetails("-K", keyid) +} + +// GetKeyDetails retrieves the public key details of key with keyid. +// returns a byte array of the details and a bool if the key exists +func (gc *gpgv2Client) GetKeyDetails(keyid uint64) ([]byte, bool, error) { + return gc.getKeyDetails("-k", keyid) +} + +// ResolveRecipients converts PGP keyids to email addresses, if possible +func (gc *gpgv2Client) ResolveRecipients(recipients []string) []string { + return resolveRecipients(gc, recipients) +} + +// GetGPGPrivateKey gets the bytes of a specified keyid, supplying a passphrase +func (gc *gpgv1Client) GetGPGPrivateKey(keyid uint64, _ string) ([]byte, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = append(args, []string{"--homedir", gc.gpgHomeDir}...) + } + args = append(args, []string{"--batch", "--export-secret-key", fmt.Sprintf("0x%x", keyid)}...) + + cmd := exec.Command("gpg", args...) + + return runGPGGetOutput(cmd) +} + +// ReadGPGPubRingFile reads the GPG public key ring file +func (gc *gpgv1Client) ReadGPGPubRingFile() ([]byte, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = append(args, []string{"--homedir", gc.gpgHomeDir}...) + } + args = append(args, []string{"--batch", "--export"}...) + + cmd := exec.Command("gpg", args...) + + return runGPGGetOutput(cmd) +} + +func (gc *gpgv1Client) getKeyDetails(option string, keyid uint64) ([]byte, bool, error) { + var args []string + + if gc.gpgHomeDir != "" { + args = []string{"--homedir", gc.gpgHomeDir} + } + args = append(args, option, fmt.Sprintf("0x%x", keyid)) + + cmd := exec.Command("gpg", args...) + + keydata, err := runGPGGetOutput(cmd) + + return keydata, err == nil, err +} + +// GetSecretKeyDetails retrieves the secret key details of key with keyid. +// returns a byte array of the details and a bool if the key exists +func (gc *gpgv1Client) GetSecretKeyDetails(keyid uint64) ([]byte, bool, error) { + return gc.getKeyDetails("-K", keyid) +} + +// GetKeyDetails retrieves the public key details of key with keyid. +// returns a byte array of the details and a bool if the key exists +func (gc *gpgv1Client) GetKeyDetails(keyid uint64) ([]byte, bool, error) { + return gc.getKeyDetails("-k", keyid) +} + +// ResolveRecipients converts PGP keyids to email addresses, if possible +func (gc *gpgv1Client) ResolveRecipients(recipients []string) []string { + return resolveRecipients(gc, recipients) +} + +// runGPGGetOutput runs the GPG commandline and returns stdout as byte array +// and any stderr in the error +func runGPGGetOutput(cmd *exec.Cmd) ([]byte, error) { + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + if err := cmd.Start(); err != nil { + return nil, err + } + + stdoutstr, err2 := ioutil.ReadAll(stdout) + stderrstr, _ := ioutil.ReadAll(stderr) + + if err := cmd.Wait(); err != nil { + return nil, fmt.Errorf("error from %s: %s", cmd.Path, string(stderrstr)) + } + + return stdoutstr, err2 +} + +// resolveRecipients walks the list of recipients and attempts to convert +// all keyIds to email addresses; if something goes wrong during the +// conversion of a recipient, the original string is returned for that +// recpient +func resolveRecipients(gc GPGClient, recipients []string) []string { + var result []string + + for _, recipient := range recipients { + keyID, err := strconv.ParseUint(recipient, 0, 64) + if err != nil { + result = append(result, recipient) + } else { + details, found, _ := gc.GetKeyDetails(keyID) + if !found { + result = append(result, recipient) + } else { + email := extractEmailFromDetails(details) + if email == "" { + result = append(result, recipient) + } else { + result = append(result, email) + } + } + } + } + return result +} + +var emailPattern = regexp.MustCompile(`uid\s+\[.*\]\s.*\s<(?P.+)>`) + +func extractEmailFromDetails(details []byte) string { + loc := emailPattern.FindSubmatchIndex(details) + if len(loc) == 0 { + return "" + } + return string(emailPattern.Expand(nil, []byte("$email"), details, loc)) +} + +// uint64ToStringArray converts an array of uint64's to an array of strings +// by applying a format string to each uint64 +func uint64ToStringArray(format string, in []uint64) []string { + var ret []string + + for _, v := range in { + ret = append(ret, fmt.Sprintf(format, v)) + } + return ret +} + +// GPGGetPrivateKey walks the list of layerInfos and tries to decrypt the +// wrapped symmetric keys. For this it determines whether a private key is +// in the GPGVault or on this system and prompts for the passwords for those +// that are available. If we do not find a private key on the system for +// getting to the symmetric key of a layer then an error is generated. +func GPGGetPrivateKey(descs []ocispec.Descriptor, gpgClient GPGClient, gpgVault GPGVault, mustFindKey bool) (gpgPrivKeys [][]byte, gpgPrivKeysPwds [][]byte, err error) { + // PrivateKeyData describes a private key + type PrivateKeyData struct { + KeyData []byte + KeyDataPassword []byte + } + var pkd PrivateKeyData + keyIDPasswordMap := make(map[uint64]PrivateKeyData) + + for _, desc := range descs { + for scheme, b64pgpPackets := range GetWrappedKeysMap(desc) { + if scheme != "pgp" { + continue + } + keywrapper := GetKeyWrapper(scheme) + if keywrapper == nil { + return nil, nil, errors.Errorf("could not get KeyWrapper for %s\n", scheme) + } + keyIds, err := keywrapper.GetKeyIdsFromPacket(b64pgpPackets) + if err != nil { + return nil, nil, err + } + + found := false + for _, keyid := range keyIds { + // do we have this key? -- first check the vault + if gpgVault != nil { + _, keydata := gpgVault.GetGPGPrivateKey(keyid) + if len(keydata) > 0 { + pkd = PrivateKeyData{ + KeyData: keydata, + KeyDataPassword: nil, // password not supported in this case + } + keyIDPasswordMap[keyid] = pkd + found = true + break + } + } else if gpgClient != nil { + // check the local system's gpg installation + keyinfo, haveKey, _ := gpgClient.GetSecretKeyDetails(keyid) + // this may fail if the key is not here; we ignore the error + if !haveKey { + // key not on this system + continue + } + + _, found = keyIDPasswordMap[keyid] + if !found { + fmt.Printf("Passphrase required for Key id 0x%x: \n%v", keyid, string(keyinfo)) + fmt.Printf("Enter passphrase for key with Id 0x%x: ", keyid) + + password, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Printf("\n") + if err != nil { + return nil, nil, err + } + keydata, err := gpgClient.GetGPGPrivateKey(keyid, string(password)) + if err != nil { + return nil, nil, err + } + pkd = PrivateKeyData{ + KeyData: keydata, + KeyDataPassword: password, + } + keyIDPasswordMap[keyid] = pkd + found = true + } + break + } else { + return nil, nil, errors.New("no GPGVault or GPGClient passed") + } + } + if !found && len(b64pgpPackets) > 0 && mustFindKey { + ids := uint64ToStringArray("0x%x", keyIds) + + return nil, nil, errors.Errorf("missing key for decryption of layer %x of %s. Need one of the following keys: %s", desc.Digest, desc.Platform, strings.Join(ids, ", ")) + } + } + } + + for _, pkd := range keyIDPasswordMap { + gpgPrivKeys = append(gpgPrivKeys, pkd.KeyData) + gpgPrivKeysPwds = append(gpgPrivKeysPwds, pkd.KeyDataPassword) + } + + return gpgPrivKeys, gpgPrivKeysPwds, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/gpgvault.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/gpgvault.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/gpgvault.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/gpgvault.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,100 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ocicrypt + +import ( + "bytes" + "io/ioutil" + + "github.com/pkg/errors" + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/packet" +) + +// GPGVault defines an interface for wrapping multiple secret key rings +type GPGVault interface { + // AddSecretKeyRingData adds a secret keyring via its raw byte array + AddSecretKeyRingData(gpgSecretKeyRingData []byte) error + // AddSecretKeyRingDataArray adds secret keyring via its raw byte arrays + AddSecretKeyRingDataArray(gpgSecretKeyRingDataArray [][]byte) error + // AddSecretKeyRingFiles adds secret keyrings given their filenames + AddSecretKeyRingFiles(filenames []string) error + // GetGPGPrivateKey gets the private key bytes of a keyid given a passphrase + GetGPGPrivateKey(keyid uint64) ([]openpgp.Key, []byte) +} + +// gpgVault wraps an array of gpgSecretKeyRing +type gpgVault struct { + entityLists []openpgp.EntityList + keyDataList [][]byte // the raw data original passed in +} + +// NewGPGVault creates an empty GPGVault +func NewGPGVault() GPGVault { + return &gpgVault{} +} + +// AddSecretKeyRingData adds a secret keyring's to the gpgVault; the raw byte +// array read from the file must be passed and will be parsed by this function +func (g *gpgVault) AddSecretKeyRingData(gpgSecretKeyRingData []byte) error { + // read the private keys + r := bytes.NewReader(gpgSecretKeyRingData) + entityList, err := openpgp.ReadKeyRing(r) + if err != nil { + return errors.Wrapf(err, "could not read keyring") + } + g.entityLists = append(g.entityLists, entityList) + g.keyDataList = append(g.keyDataList, gpgSecretKeyRingData) + return nil +} + +// AddSecretKeyRingDataArray adds secret keyrings to the gpgVault; the raw byte +// arrays read from files must be passed +func (g *gpgVault) AddSecretKeyRingDataArray(gpgSecretKeyRingDataArray [][]byte) error { + for _, gpgSecretKeyRingData := range gpgSecretKeyRingDataArray { + if err := g.AddSecretKeyRingData(gpgSecretKeyRingData); err != nil { + return err + } + } + return nil +} + +// AddSecretKeyRingFiles adds the secret key rings given their filenames +func (g *gpgVault) AddSecretKeyRingFiles(filenames []string) error { + for _, filename := range filenames { + gpgSecretKeyRingData, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + err = g.AddSecretKeyRingData(gpgSecretKeyRingData) + if err != nil { + return err + } + } + return nil +} + +// GetGPGPrivateKey gets the bytes of a specified keyid, supplying a passphrase +func (g *gpgVault) GetGPGPrivateKey(keyid uint64) ([]openpgp.Key, []byte) { + for i, el := range g.entityLists { + decKeys := el.KeysByIdUsage(keyid, packet.KeyFlagEncryptCommunications) + if len(decKeys) > 0 { + return decKeys, g.keyDataList[i] + } + } + return nil, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,136 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package jwe + +import ( + "crypto/ecdsa" + + "github.com/containers/ocicrypt/config" + "github.com/containers/ocicrypt/keywrap" + "github.com/containers/ocicrypt/utils" + "github.com/pkg/errors" + jose "gopkg.in/square/go-jose.v2" +) + +type jweKeyWrapper struct { +} + +func (kw *jweKeyWrapper) GetAnnotationID() string { + return "org.opencontainers.image.enc.keys.jwe" +} + +// NewKeyWrapper returns a new key wrapping interface using jwe +func NewKeyWrapper() keywrap.KeyWrapper { + return &jweKeyWrapper{} +} + +// WrapKeys wraps the session key for recpients and encrypts the optsData, which +// describe the symmetric key used for encrypting the layer +func (kw *jweKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) { + var joseRecipients []jose.Recipient + + err := addPubKeys(&joseRecipients, ec.Parameters["pubkeys"]) + if err != nil { + return nil, err + } + // no recipients is not an error... + if len(joseRecipients) == 0 { + return nil, nil + } + + encrypter, err := jose.NewMultiEncrypter(jose.A256GCM, joseRecipients, nil) + if err != nil { + return nil, errors.Wrapf(err, "jose.NewMultiEncrypter failed") + } + jwe, err := encrypter.Encrypt(optsData) + if err != nil { + return nil, errors.Wrapf(err, "JWE Encrypt failed") + } + return []byte(jwe.FullSerialize()), nil +} + +func (kw *jweKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jweString []byte) ([]byte, error) { + jwe, err := jose.ParseEncrypted(string(jweString)) + if err != nil { + return nil, errors.New("jose.ParseEncrypted failed") + } + + privKeys := kw.GetPrivateKeys(dc.Parameters) + if len(privKeys) == 0 { + return nil, errors.New("No private keys found for JWE decryption") + } + privKeysPasswords := kw.getPrivateKeysPasswords(dc.Parameters) + if len(privKeysPasswords) != len(privKeys) { + return nil, errors.New("Private key password array length must be same as that of private keys") + } + + for idx, privKey := range privKeys { + key, err := utils.ParsePrivateKey(privKey, privKeysPasswords[idx], "JWE") + if err != nil { + return nil, err + } + _, _, plain, err := jwe.DecryptMulti(key) + if err == nil { + return plain, nil + } + } + return nil, errors.New("JWE: No suitable private key found for decryption") +} + +func (kw *jweKeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool { + return len(kw.GetPrivateKeys(dcparameters)) == 0 +} + +func (kw *jweKeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte { + return dcparameters["privkeys"] +} + +func (kw *jweKeyWrapper) getPrivateKeysPasswords(dcparameters map[string][][]byte) [][]byte { + return dcparameters["privkeys-passwords"] +} + +func (kw *jweKeyWrapper) GetKeyIdsFromPacket(b64jwes string) ([]uint64, error) { + return nil, nil +} + +func (kw *jweKeyWrapper) GetRecipients(b64jwes string) ([]string, error) { + return []string{"[jwe]"}, nil +} + +func addPubKeys(joseRecipients *[]jose.Recipient, pubKeys [][]byte) error { + if len(pubKeys) == 0 { + return nil + } + for _, pubKey := range pubKeys { + key, err := utils.ParsePublicKey(pubKey, "JWE") + if err != nil { + return err + } + + alg := jose.RSA_OAEP + switch key.(type) { + case *ecdsa.PublicKey: + alg = jose.ECDH_ES_A256KW + } + + *joseRecipients = append(*joseRecipients, jose.Recipient{ + Algorithm: alg, + Key: key, + }) + } + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,242 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package keyprovider + +import ( + "context" + "encoding/json" + "github.com/containers/ocicrypt/config" + keyproviderconfig "github.com/containers/ocicrypt/config/keyprovider-config" + "github.com/containers/ocicrypt/keywrap" + "github.com/containers/ocicrypt/utils" + keyproviderpb "github.com/containers/ocicrypt/utils/keyprovider" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "google.golang.org/grpc" +) + +type keyProviderKeyWrapper struct { + provider string + attrs keyproviderconfig.KeyProviderAttrs +} + +func (kw *keyProviderKeyWrapper) GetAnnotationID() string { + return "org.opencontainers.image.enc.keys.provider." + kw.provider +} + +// NewKeyWrapper returns a new key wrapping interface using keyprovider +func NewKeyWrapper(p string, a keyproviderconfig.KeyProviderAttrs) keywrap.KeyWrapper { + return &keyProviderKeyWrapper{provider: p, attrs: a} +} + +type KeyProviderKeyWrapProtocolOperation string + +var ( + OpKeyWrap KeyProviderKeyWrapProtocolOperation = "keywrap" + OpKeyUnwrap KeyProviderKeyWrapProtocolOperation = "keyunwrap" +) + +// KeyProviderKeyWrapProtocolInput defines the input to the key provider binary or grpc method. +type KeyProviderKeyWrapProtocolInput struct { + // Operation is either "keywrap" or "keyunwrap" + Operation KeyProviderKeyWrapProtocolOperation `json:"op"` + // KeyWrapParams encodes the arguments to key wrap if operation is set to wrap + KeyWrapParams KeyWrapParams `json:"keywrapparams,omitempty"` + // KeyUnwrapParams encodes the arguments to key unwrap if operation is set to unwrap + KeyUnwrapParams KeyUnwrapParams `json:"keyunwrapparams,omitempty"` +} + +// KeyProviderKeyWrapProtocolOutput defines the output of the key provider binary or grpc method. +type KeyProviderKeyWrapProtocolOutput struct { + // KeyWrapResult encodes the results to key wrap if operation is to wrap + KeyWrapResults KeyWrapResults `json:"keywrapresults,omitempty"` + // KeyUnwrapResult encodes the result to key unwrap if operation is to unwrap + KeyUnwrapResults KeyUnwrapResults `json:"keyunwrapresults,omitempty"` +} + +type KeyWrapParams struct { + Ec *config.EncryptConfig `json:"ec"` + OptsData []byte `json:"optsdata"` +} + +type KeyUnwrapParams struct { + Dc *config.DecryptConfig `json:"dc"` + Annotation []byte `json:"annotation"` +} + +type KeyUnwrapResults struct { + OptsData []byte `json:"optsdata"` +} + +type KeyWrapResults struct { + Annotation []byte `json:"annotation"` +} + +var runner utils.CommandExecuter + +func init() { + runner = utils.Runner{} +} + +// WrapKeys calls appropriate binary executable/grpc server for wrapping the session key for recipients and gets encrypted optsData, which +// describe the symmetric key used for encrypting the layer +func (kw *keyProviderKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) { + + input, err := json.Marshal(KeyProviderKeyWrapProtocolInput{ + Operation: OpKeyWrap, + KeyWrapParams: KeyWrapParams{ + Ec: ec, + OptsData: optsData, + }, + }) + + if err != nil { + return nil, err + } + + if _, ok := ec.Parameters[kw.provider]; ok { + if kw.attrs.Command != nil { + protocolOuput, err := getProviderCommandOutput(input, kw.attrs.Command) + if err != nil { + return nil, errors.Wrap(err, "error while retrieving keyprovider protocol command output") + } + return protocolOuput.KeyWrapResults.Annotation, nil + } else if kw.attrs.Grpc != "" { + protocolOuput, err := getProviderGRPCOutput(input, kw.attrs.Grpc, OpKeyWrap) + if err != nil { + return nil, errors.Wrap(err, "error while retrieving keyprovider protocol grpc output") + } + + return protocolOuput.KeyWrapResults.Annotation, nil + } else { + return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd") + } + } + + return nil, nil +} + +// UnwrapKey calls appropriate binary executable/grpc server for unwrapping the session key based on the protocol given in annotation for recipients and gets decrypted optsData, +// which describe the symmetric key used for decrypting the layer +func (kw *keyProviderKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jsonString []byte) ([]byte, error) { + input, err := json.Marshal(KeyProviderKeyWrapProtocolInput{ + Operation: OpKeyUnwrap, + KeyUnwrapParams: KeyUnwrapParams{ + Dc: dc, + Annotation: jsonString, + }, + }) + if err != nil { + return nil, err + } + + if kw.attrs.Command != nil { + protocolOuput, err := getProviderCommandOutput(input, kw.attrs.Command) + if err != nil { + // If err is not nil, then ignore it and continue with rest of the given keyproviders + return nil, err + } + + return protocolOuput.KeyUnwrapResults.OptsData, nil + } else if kw.attrs.Grpc != "" { + protocolOuput, err := getProviderGRPCOutput(input, kw.attrs.Grpc, OpKeyUnwrap) + if err != nil { + // If err is not nil, then ignore it and continue with rest of the given keyproviders + return nil, err + } + + return protocolOuput.KeyUnwrapResults.OptsData, nil + } else { + return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd") + } +} + +func getProviderGRPCOutput(input []byte, connString string, operation KeyProviderKeyWrapProtocolOperation) (*KeyProviderKeyWrapProtocolOutput, error) { + var protocolOuput KeyProviderKeyWrapProtocolOutput + var grpcOutput *keyproviderpb.KeyProviderKeyWrapProtocolOutput + cc, err := grpc.Dial(connString, grpc.WithInsecure()) + if err != nil { + return nil, errors.Wrap(err, "error while dialing rpc server") + } + defer func() { + derr := cc.Close() + if derr != nil { + log.WithError(derr).Error("Error closing grpc socket") + } + }() + + client := keyproviderpb.NewKeyProviderServiceClient(cc) + req := &keyproviderpb.KeyProviderKeyWrapProtocolInput{ + KeyProviderKeyWrapProtocolInput: input, + } + + if operation == OpKeyWrap { + grpcOutput, err = client.WrapKey(context.Background(), req) + if err != nil { + return nil, errors.Wrap(err, "Error from grpc method") + } + } else if operation == OpKeyUnwrap { + grpcOutput, err = client.UnWrapKey(context.Background(), req) + if err != nil { + return nil, errors.Wrap(err, "Error from grpc method") + } + } else { + return nil, errors.New("Unsupported operation") + } + + respBytes := grpcOutput.GetKeyProviderKeyWrapProtocolOutput() + err = json.Unmarshal(respBytes, &protocolOuput) + if err != nil { + return nil, errors.Wrap(err, "Error while unmarshalling grpc method output") + } + + return &protocolOuput, nil +} + +func getProviderCommandOutput(input []byte, command *keyproviderconfig.Command) (*KeyProviderKeyWrapProtocolOutput, error) { + var protocolOuput KeyProviderKeyWrapProtocolOutput + // Convert interface to command structure + respBytes, err := runner.Exec(command.Path, command.Args, input) + if err != nil { + return nil, err + } + err = json.Unmarshal(respBytes, &protocolOuput) + if err != nil { + return nil, errors.Wrap(err, "Error while unmarshalling binary executable command output") + } + return &protocolOuput, nil +} + +// Return false as it is not applicable to keyprovider protocol +func (kw *keyProviderKeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool { + return false +} + +// Return nil as it is not applicable to keyprovider protocol +func (kw *keyProviderKeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte { + return nil +} + +// Return nil as it is not applicable to keyprovider protocol +func (kw *keyProviderKeyWrapper) GetKeyIdsFromPacket(_ string) ([]uint64, error) { + return nil, nil +} + +// Return nil as it is not applicable to keyprovider protocol +func (kw *keyProviderKeyWrapper) GetRecipients(_ string) ([]string, error) { + return nil, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/keywrap.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/keywrap.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/keywrap.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/keywrap.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,48 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package keywrap + +import ( + "github.com/containers/ocicrypt/config" +) + +// KeyWrapper is the interface used for wrapping keys using +// a specific encryption technology (pgp, jwe) +type KeyWrapper interface { + WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) + UnwrapKey(dc *config.DecryptConfig, annotation []byte) ([]byte, error) + GetAnnotationID() string + + // NoPossibleKeys returns true if there is no possibility of performing + // decryption for parameters provided. + NoPossibleKeys(dcparameters map[string][][]byte) bool + + // GetPrivateKeys (optional) gets the array of private keys. It is an optional implementation + // as in some key services, a private key may not be exportable (i.e. HSM) + // If not implemented, return nil + GetPrivateKeys(dcparameters map[string][][]byte) [][]byte + + // GetKeyIdsFromPacket (optional) gets a list of key IDs. This is optional as some encryption + // schemes may not have a notion of key IDs + // If not implemented, return the nil slice + GetKeyIdsFromPacket(packet string) ([]uint64, error) + + // GetRecipients (optional) gets a list of recipients. It is optional due to the validity of + // recipients in a particular encryptiong scheme + // If not implemented, return the nil slice + GetRecipients(packet string) ([]string, error) +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pgp/keywrapper_gpg.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pgp/keywrapper_gpg.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pgp/keywrapper_gpg.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pgp/keywrapper_gpg.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,273 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pgp + +import ( + "bytes" + "crypto" + "crypto/rand" + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "net/mail" + "strconv" + "strings" + + "github.com/containers/ocicrypt/config" + "github.com/containers/ocicrypt/keywrap" + "github.com/pkg/errors" + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/packet" +) + +type gpgKeyWrapper struct { +} + +// NewKeyWrapper returns a new key wrapping interface for pgp +func NewKeyWrapper() keywrap.KeyWrapper { + return &gpgKeyWrapper{} +} + +var ( + // GPGDefaultEncryptConfig is the default configuration for layer encryption/decryption + GPGDefaultEncryptConfig = &packet.Config{ + Rand: rand.Reader, + DefaultHash: crypto.SHA256, + DefaultCipher: packet.CipherAES256, + CompressionConfig: &packet.CompressionConfig{Level: 0}, // No compression + RSABits: 2048, + } +) + +func (kw *gpgKeyWrapper) GetAnnotationID() string { + return "org.opencontainers.image.enc.keys.pgp" +} + +// WrapKeys wraps the session key for recpients and encrypts the optsData, which +// describe the symmetric key used for encrypting the layer +func (kw *gpgKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) { + ciphertext := new(bytes.Buffer) + el, err := kw.createEntityList(ec) + if err != nil { + return nil, errors.Wrap(err, "unable to create entity list") + } + if len(el) == 0 { + // nothing to do -- not an error + return nil, nil + } + + plaintextWriter, err := openpgp.Encrypt(ciphertext, + el, /*EntityList*/ + nil, /* Sign*/ + nil, /* FileHint */ + GPGDefaultEncryptConfig) + if err != nil { + return nil, err + } + + if _, err = plaintextWriter.Write(optsData); err != nil { + return nil, err + } else if err = plaintextWriter.Close(); err != nil { + return nil, err + } + return ciphertext.Bytes(), err +} + +// UnwrapKey unwraps the symmetric key with which the layer is encrypted +// This symmetric key is encrypted in the PGP payload. +func (kw *gpgKeyWrapper) UnwrapKey(dc *config.DecryptConfig, pgpPacket []byte) ([]byte, error) { + pgpPrivateKeys, pgpPrivateKeysPwd, err := kw.getKeyParameters(dc.Parameters) + if err != nil { + return nil, err + } + + for idx, pgpPrivateKey := range pgpPrivateKeys { + r := bytes.NewBuffer(pgpPrivateKey) + entityList, err := openpgp.ReadKeyRing(r) + if err != nil { + return nil, errors.Wrap(err, "unable to parse private keys") + } + + var prompt openpgp.PromptFunction + if len(pgpPrivateKeysPwd) > idx { + responded := false + prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) { + if responded { + return nil, fmt.Errorf("don't seem to have the right password") + } + responded = true + for _, key := range keys { + if key.PrivateKey != nil { + _ = key.PrivateKey.Decrypt(pgpPrivateKeysPwd[idx]) + } + } + return pgpPrivateKeysPwd[idx], nil + } + } + + r = bytes.NewBuffer(pgpPacket) + md, err := openpgp.ReadMessage(r, entityList, prompt, GPGDefaultEncryptConfig) + if err != nil { + continue + } + // we get the plain key options back + optsData, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + continue + } + return optsData, nil + } + return nil, errors.New("PGP: No suitable key found to unwrap key") +} + +// GetKeyIdsFromWrappedKeys converts the base64 encoded PGPPacket to uint64 keyIds +func (kw *gpgKeyWrapper) GetKeyIdsFromPacket(b64pgpPackets string) ([]uint64, error) { + + var keyids []uint64 + for _, b64pgpPacket := range strings.Split(b64pgpPackets, ",") { + pgpPacket, err := base64.StdEncoding.DecodeString(b64pgpPacket) + if err != nil { + return nil, errors.Wrapf(err, "could not decode base64 encoded PGP packet") + } + newids, err := kw.getKeyIDs(pgpPacket) + if err != nil { + return nil, err + } + keyids = append(keyids, newids...) + } + return keyids, nil +} + +// getKeyIDs parses a PGPPacket and gets the list of recipients' key IDs +func (kw *gpgKeyWrapper) getKeyIDs(pgpPacket []byte) ([]uint64, error) { + var keyids []uint64 + + kbuf := bytes.NewBuffer(pgpPacket) + packets := packet.NewReader(kbuf) +ParsePackets: + for { + p, err := packets.Next() + if err == io.EOF { + break ParsePackets + } + if err != nil { + return []uint64{}, errors.Wrapf(err, "packets.Next() failed") + } + switch p := p.(type) { + case *packet.EncryptedKey: + keyids = append(keyids, p.KeyId) + case *packet.SymmetricallyEncrypted: + break ParsePackets + } + } + return keyids, nil +} + +// GetRecipients converts the wrappedKeys to an array of recipients +func (kw *gpgKeyWrapper) GetRecipients(b64pgpPackets string) ([]string, error) { + keyIds, err := kw.GetKeyIdsFromPacket(b64pgpPackets) + if err != nil { + return nil, err + } + var array []string + for _, keyid := range keyIds { + array = append(array, "0x"+strconv.FormatUint(keyid, 16)) + } + return array, nil +} + +func (kw *gpgKeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool { + return len(kw.GetPrivateKeys(dcparameters)) == 0 +} + +func (kw *gpgKeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte { + return dcparameters["gpg-privatekeys"] +} + +func (kw *gpgKeyWrapper) getKeyParameters(dcparameters map[string][][]byte) ([][]byte, [][]byte, error) { + + privKeys := kw.GetPrivateKeys(dcparameters) + if len(privKeys) == 0 { + return nil, nil, errors.New("GPG: Missing private key parameter") + } + + return privKeys, dcparameters["gpg-privatekeys-passwords"], nil +} + +// createEntityList creates the opengpg EntityList by reading the KeyRing +// first and then filtering out recipients' keys +func (kw *gpgKeyWrapper) createEntityList(ec *config.EncryptConfig) (openpgp.EntityList, error) { + pgpPubringFile := ec.Parameters["gpg-pubkeyringfile"] + if len(pgpPubringFile) == 0 { + return nil, nil + } + r := bytes.NewReader(pgpPubringFile[0]) + + entityList, err := openpgp.ReadKeyRing(r) + if err != nil { + return nil, err + } + + gpgRecipients := ec.Parameters["gpg-recipients"] + if len(gpgRecipients) == 0 { + return nil, nil + } + + rSet := make(map[string]int) + for _, r := range gpgRecipients { + rSet[string(r)] = 0 + } + + var filteredList openpgp.EntityList + for _, entity := range entityList { + for k := range entity.Identities { + addr, err := mail.ParseAddress(k) + if err != nil { + return nil, err + } + for _, r := range gpgRecipients { + recp := string(r) + if strings.Compare(addr.Name, recp) == 0 || strings.Compare(addr.Address, recp) == 0 { + filteredList = append(filteredList, entity) + rSet[recp] = rSet[recp] + 1 + } + } + } + } + + // make sure we found keys for all the Recipients... + var buffer bytes.Buffer + notFound := false + buffer.WriteString("PGP: No key found for the following recipients: ") + + for k, v := range rSet { + if v == 0 { + if notFound { + buffer.WriteString(", ") + } + buffer.WriteString(k) + notFound = true + } + } + + if notFound { + return nil, errors.New(buffer.String()) + } + + return filteredList, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pkcs11/keywrapper_pkcs11.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pkcs11/keywrapper_pkcs11.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pkcs11/keywrapper_pkcs11.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pkcs11/keywrapper_pkcs11.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,147 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs11 + +import ( + "github.com/containers/ocicrypt/config" + "github.com/containers/ocicrypt/crypto/pkcs11" + "github.com/containers/ocicrypt/keywrap" + "github.com/containers/ocicrypt/utils" + + "github.com/pkg/errors" +) + +type pkcs11KeyWrapper struct { +} + +func (kw *pkcs11KeyWrapper) GetAnnotationID() string { + return "org.opencontainers.image.enc.keys.pkcs11" +} + +// NewKeyWrapper returns a new key wrapping interface using pkcs11 +func NewKeyWrapper() keywrap.KeyWrapper { + return &pkcs11KeyWrapper{} +} + +// WrapKeys wraps the session key for recpients and encrypts the optsData, which +// describe the symmetric key used for encrypting the layer +func (kw *pkcs11KeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) { + pkcs11Recipients, err := addPubKeys(&ec.DecryptConfig, append(ec.Parameters["pkcs11-pubkeys"], ec.Parameters["pkcs11-yamls"]...)) + if err != nil { + return nil, err + } + // no recipients is not an error... + if len(pkcs11Recipients) == 0 { + return nil, nil + } + + jsonString, err := pkcs11.EncryptMultiple(pkcs11Recipients, optsData) + if err != nil { + return nil, errors.Wrapf(err, "PKCS11 EncryptMulitple failed") + } + return jsonString, nil +} + +func (kw *pkcs11KeyWrapper) UnwrapKey(dc *config.DecryptConfig, jsonString []byte) ([]byte, error) { + var pkcs11PrivKeys []*pkcs11.Pkcs11KeyFileObject + + privKeys := kw.GetPrivateKeys(dc.Parameters) + if len(privKeys) == 0 { + return nil, errors.New("No private keys found for PKCS11 decryption") + } + + p11conf, err := p11confFromParameters(dc.Parameters) + if err != nil { + return nil, err + } + + for _, privKey := range privKeys { + key, err := utils.ParsePrivateKey(privKey, nil, "PKCS11") + if err != nil { + return nil, err + } + switch pkcs11PrivKey := key.(type) { + case *pkcs11.Pkcs11KeyFileObject: + if p11conf != nil { + pkcs11PrivKey.Uri.SetModuleDirectories(p11conf.ModuleDirectories) + pkcs11PrivKey.Uri.SetAllowedModulePaths(p11conf.AllowedModulePaths) + } + pkcs11PrivKeys = append(pkcs11PrivKeys, pkcs11PrivKey) + default: + continue + } + } + + plaintext, err := pkcs11.Decrypt(pkcs11PrivKeys, jsonString) + if err == nil { + return plaintext, nil + } + + return nil, errors.Wrapf(err, "PKCS11: No suitable private key found for decryption") +} + +func (kw *pkcs11KeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool { + return len(kw.GetPrivateKeys(dcparameters)) == 0 +} + +func (kw *pkcs11KeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte { + return dcparameters["pkcs11-yamls"] +} + +func (kw *pkcs11KeyWrapper) GetKeyIdsFromPacket(_ string) ([]uint64, error) { + return nil, nil +} + +func (kw *pkcs11KeyWrapper) GetRecipients(_ string) ([]string, error) { + return []string{"[pkcs11]"}, nil +} + +func addPubKeys(dc *config.DecryptConfig, pubKeys [][]byte) ([]interface{}, error) { + var pkcs11Keys []interface{} + + if len(pubKeys) == 0 { + return pkcs11Keys, nil + } + + p11conf, err := p11confFromParameters(dc.Parameters) + if err != nil { + return nil, err + } + + for _, pubKey := range pubKeys { + key, err := utils.ParsePublicKey(pubKey, "PKCS11") + if err != nil { + return nil, err + } + switch pkcs11PubKey := key.(type) { + case *pkcs11.Pkcs11KeyFileObject: + if p11conf != nil { + pkcs11PubKey.Uri.SetModuleDirectories(p11conf.ModuleDirectories) + pkcs11PubKey.Uri.SetAllowedModulePaths(p11conf.AllowedModulePaths) + } + } + pkcs11Keys = append(pkcs11Keys, key) + } + return pkcs11Keys, nil +} + +func p11confFromParameters(dcparameters map[string][][]byte) (*pkcs11.Pkcs11Config, error){ + if _, ok := dcparameters["pkcs11-config"]; ok { + return pkcs11.ParsePkcs11ConfigFile(dcparameters["pkcs11-config"][0]) + } + return nil, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,136 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pkcs7 + +import ( + "crypto" + "crypto/x509" + + "github.com/containers/ocicrypt/config" + "github.com/containers/ocicrypt/keywrap" + "github.com/containers/ocicrypt/utils" + "github.com/pkg/errors" + "go.mozilla.org/pkcs7" +) + +type pkcs7KeyWrapper struct { +} + +// NewKeyWrapper returns a new key wrapping interface using jwe +func NewKeyWrapper() keywrap.KeyWrapper { + return &pkcs7KeyWrapper{} +} + +func (kw *pkcs7KeyWrapper) GetAnnotationID() string { + return "org.opencontainers.image.enc.keys.pkcs7" +} + +// WrapKeys wraps the session key for recpients and encrypts the optsData, which +// describe the symmetric key used for encrypting the layer +func (kw *pkcs7KeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]byte, error) { + x509Certs, err := collectX509s(ec.Parameters["x509s"]) + if err != nil { + return nil, err + } + // no recipients is not an error... + if len(x509Certs) == 0 { + return nil, nil + } + + pkcs7.ContentEncryptionAlgorithm = pkcs7.EncryptionAlgorithmAES128GCM + return pkcs7.Encrypt(optsData, x509Certs) +} + +func collectX509s(x509s [][]byte) ([]*x509.Certificate, error) { + if len(x509s) == 0 { + return nil, nil + } + var x509Certs []*x509.Certificate + for _, x509 := range x509s { + x509Cert, err := utils.ParseCertificate(x509, "PKCS7") + if err != nil { + return nil, err + } + x509Certs = append(x509Certs, x509Cert) + } + return x509Certs, nil +} + +func (kw *pkcs7KeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool { + return len(kw.GetPrivateKeys(dcparameters)) == 0 +} + +func (kw *pkcs7KeyWrapper) GetPrivateKeys(dcparameters map[string][][]byte) [][]byte { + return dcparameters["privkeys"] +} + +func (kw *pkcs7KeyWrapper) getPrivateKeysPasswords(dcparameters map[string][][]byte) [][]byte { + return dcparameters["privkeys-passwords"] +} + +// UnwrapKey unwraps the symmetric key with which the layer is encrypted +// This symmetric key is encrypted in the PKCS7 payload. +func (kw *pkcs7KeyWrapper) UnwrapKey(dc *config.DecryptConfig, pkcs7Packet []byte) ([]byte, error) { + privKeys := kw.GetPrivateKeys(dc.Parameters) + if len(privKeys) == 0 { + return nil, errors.New("no private keys found for PKCS7 decryption") + } + privKeysPasswords := kw.getPrivateKeysPasswords(dc.Parameters) + if len(privKeysPasswords) != len(privKeys) { + return nil, errors.New("private key password array length must be same as that of private keys") + } + + x509Certs, err := collectX509s(dc.Parameters["x509s"]) + if err != nil { + return nil, err + } + if len(x509Certs) == 0 { + return nil, errors.New("no x509 certificates found needed for PKCS7 decryption") + } + + p7, err := pkcs7.Parse(pkcs7Packet) + if err != nil { + return nil, errors.Wrapf(err, "could not parse PKCS7 packet") + } + + for idx, privKey := range privKeys { + key, err := utils.ParsePrivateKey(privKey, privKeysPasswords[idx], "PKCS7") + if err != nil { + return nil, err + } + for _, x509Cert := range x509Certs { + optsData, err := p7.Decrypt(x509Cert, crypto.PrivateKey(key)) + if err != nil { + continue + } + return optsData, nil + } + } + return nil, errors.New("PKCS7: No suitable private key found for decryption") +} + +// GetKeyIdsFromWrappedKeys converts the base64 encoded Packet to uint64 keyIds; +// We cannot do this with pkcs7 +func (kw *pkcs7KeyWrapper) GetKeyIdsFromPacket(b64pkcs7Packets string) ([]uint64, error) { + return nil, nil +} + +// GetRecipients converts the wrappedKeys to an array of recipients +// We cannot do this with pkcs7 +func (kw *pkcs7KeyWrapper) GetRecipients(b64pkcs7Packets string) ([]string, error) { + return []string{"[pkcs7]"}, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/LICENSE containerd-1.5.9/vendor/github.com/containers/ocicrypt/LICENSE --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,189 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + 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. diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/MAINTAINERS containerd-1.5.9/vendor/github.com/containers/ocicrypt/MAINTAINERS --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/MAINTAINERS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/MAINTAINERS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +# ocicrypt maintainers +# +# Github ID, Name, Email Address +lumjjb, Brandon Lum, lumjjb@gmail.com +stefanberger, Stefan Berger, stefanb@linux.ibm.com diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/Makefile containerd-1.5.9/vendor/github.com/containers/ocicrypt/Makefile --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.PHONY: check build decoder generate-protobuf + +all: build + +FORCE: + +check: + golangci-lint run + +build: vendor + go build ./... + +vendor: + go mod tidy + +test: + go test ./... -test.v + +generate-protobuf: + protoc -I utils/keyprovider/ utils/keyprovider/keyprovider.proto --go_out=plugins=grpc:utils/keyprovider diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/reader.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/reader.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/reader.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/reader.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,40 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package ocicrypt + +import ( + "io" +) + +type readerAtReader struct { + r io.ReaderAt + off int64 +} + +// ReaderFromReaderAt takes an io.ReaderAt and returns an io.Reader +func ReaderFromReaderAt(r io.ReaderAt) io.Reader { + return &readerAtReader{ + r: r, + off: 0, + } +} + +func (rar *readerAtReader) Read(p []byte) (n int, err error) { + n, err = rar.r.ReadAt(p, rar.off) + rar.off += int64(n) + return n, err +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/README.md containerd-1.5.9/vendor/github.com/containers/ocicrypt/README.md --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,44 @@ +# OCIcrypt Library + +The `ocicrypt` library is the OCI image spec implementation of container image encryption. More details of the spec can be seen in the [OCI repository](https://github.com/opencontainers/image-spec/pull/775). The purpose of this library is to encode spec structures and consts in code, as well as provide a consistent implementation of image encryption across container runtimes and build tools. + +Consumers of OCIcrypt: + +- [containerd/imgcrypt](https://github.com/containerd/imgcrypt) +- [cri-o](https://github.com/cri-o/cri-o) +- [skopeo](https://github.com/containers/skopeo) + + +## Usage + +There are various levels of usage for this library. The main consumers of these would be runtime/build tools, and a more specific use would be in the ability to extend cryptographic function. + +### Runtime/Build tool usage + +The general exposed interface a runtime/build tool would use, would be to perform encryption or decryption of layers: + +``` +package "github.com/containers/ocicrypt" +func EncryptLayer(ec *config.EncryptConfig, encOrPlainLayerReader io.Reader, desc ocispec.Descriptor) (io.Reader, EncryptLayerFinalizer, error) +func DecryptLayer(dc *config.DecryptConfig, encLayerReader io.Reader, desc ocispec.Descriptor, unwrapOnly bool) (io.Reader, digest.Digest, error) +``` + +The settings/parameters to these functions can be specified via creation of an encryption config with the `github.com/containers/ocicrypt/config` package. We note that because setting of annotations and other fields of the layer descriptor is done through various means in different runtimes/build tools, it is the responsibility of the caller to still ensure that the layer descriptor follows the OCI specification (i.e. encoding, setting annotations, etc.). + + +### Crypto Agility and Extensibility + +The implementation for both symmetric and asymmetric encryption used in this library are behind 2 main interfaces, which users can extend if need be. These are in the following packages: +- github.com/containers/ocicrypt/blockcipher - LayerBlockCipher interface for block ciphers +- github.com/containers/ocicrypt/keywrap - KeyWrapper interface for key wrapping + +We note that adding interfaces here is risky outside the OCI spec is not recommended, unless for very specialized and confined usecases. Please open an issue or PR if there is a general usecase that could be added to the OCI spec. + +## Security Issues + +We consider security issues related to this library critical. Please report and security related issues by emailing maintainers in the [MAINTAINERS](MAINTAINERS) file. + + +## Ocicrypt Pkcs11 Support + +Ocicrypt Pkcs11 support is currently experiemental. For more details, please refer to the [this document](docs/pkcs11.md). diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/SECURITY.md containerd-1.5.9/vendor/github.com/containers/ocicrypt/SECURITY.md --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/SECURITY.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/SECURITY.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,3 @@ +## Security and Disclosure Information Policy for the OCIcrypt Library Project + +The OCIcrypt Library Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects. diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/spec/spec.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/spec/spec.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/spec/spec.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/spec/spec.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +package spec + +const ( + // MediaTypeLayerEnc is MIME type used for encrypted layers. + MediaTypeLayerEnc = "application/vnd.oci.image.layer.v1.tar+encrypted" + // MediaTypeLayerGzipEnc is MIME type used for encrypted compressed layers. + MediaTypeLayerGzipEnc = "application/vnd.oci.image.layer.v1.tar+gzip+encrypted" + // MediaTypeLayerNonDistributableEnc is MIME type used for non distributable encrypted layers. + MediaTypeLayerNonDistributableEnc = "application/vnd.oci.image.layer.nondistributable.v1.tar+encrypted" + // MediaTypeLayerGzipEnc is MIME type used for non distributable encrypted compressed layers. + MediaTypeLayerNonDistributableGzipEnc = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip+encrypted" +) diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/.travis.yml containerd-1.5.9/vendor/github.com/containers/ocicrypt/.travis.yml --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,29 @@ +dist: bionic +language: go + +os: +- linux + +go: + - "1.13.x" + - "1.16.x" + +matrix: + include: + - os: linux + +addons: + apt: + packages: + - gnutls-bin + - softhsm2 + +go_import_path: github.com/containers/ocicrypt + +install: + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0 + +script: + - make + - make check + - make test diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/delayedreader.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/delayedreader.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/delayedreader.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/delayedreader.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,109 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +import ( + "io" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// DelayedReader wraps a io.Reader and allows a client to use the Reader +// interface. The DelayedReader holds back some buffer to the client +// so that it can report any error that occurred on the Reader it wraps +// early to the client while it may still have held some data back. +type DelayedReader struct { + reader io.Reader // Reader to Read() bytes from and delay them + err error // error that occurred on the reader + buffer []byte // delay buffer + bufbytes int // number of bytes in the delay buffer to give to Read(); on '0' we return 'EOF' to caller + bufoff int // offset in the delay buffer to give to Read() +} + +// NewDelayedReader wraps a io.Reader and allocates a delay buffer of bufsize bytes +func NewDelayedReader(reader io.Reader, bufsize uint) io.Reader { + return &DelayedReader{ + reader: reader, + buffer: make([]byte, bufsize), + } +} + +// Read implements the io.Reader interface +func (dr *DelayedReader) Read(p []byte) (int, error) { + if dr.err != nil && dr.err != io.EOF { + return 0, dr.err + } + + // if we are completely drained, return io.EOF + if dr.err == io.EOF && dr.bufbytes == 0 { + return 0, io.EOF + } + + // only at the beginning we fill our delay buffer in an extra step + if dr.bufbytes < len(dr.buffer) && dr.err == nil { + dr.bufbytes, dr.err = FillBuffer(dr.reader, dr.buffer) + if dr.err != nil && dr.err != io.EOF { + return 0, dr.err + } + } + // dr.err != nil means we have EOF and can drain the delay buffer + // otherwise we need to still read from the reader + + var tmpbuf []byte + tmpbufbytes := 0 + if dr.err == nil { + tmpbuf = make([]byte, len(p)) + tmpbufbytes, dr.err = FillBuffer(dr.reader, tmpbuf) + if dr.err != nil && dr.err != io.EOF { + return 0, dr.err + } + } + + // copy out of the delay buffer into 'p' + tocopy1 := min(len(p), dr.bufbytes) + c1 := copy(p[:tocopy1], dr.buffer[dr.bufoff:]) + dr.bufoff += c1 + dr.bufbytes -= c1 + + c2 := 0 + // can p still hold more data? + if c1 < len(p) { + // copy out of the tmpbuf into 'p' + c2 = copy(p[tocopy1:], tmpbuf[:tmpbufbytes]) + } + + // if tmpbuf holds data we need to hold onto, copy them + // into the delay buffer + if tmpbufbytes-c2 > 0 { + // left-shift the delay buffer and append the tmpbuf's remaining data + dr.buffer = dr.buffer[dr.bufoff : dr.bufoff+dr.bufbytes] + dr.buffer = append(dr.buffer, tmpbuf[c2:tmpbufbytes]...) + dr.bufoff = 0 + dr.bufbytes = len(dr.buffer) + } + + var err error + if dr.bufbytes == 0 { + err = io.EOF + } + return c1 + c2, err +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/ioutils.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/ioutils.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/ioutils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/ioutils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,56 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +import ( + "bytes" + "io" + "os/exec" + "github.com/pkg/errors" +) + +// FillBuffer fills the given buffer with as many bytes from the reader as possible. It returns +// EOF if an EOF was encountered or any other error. +func FillBuffer(reader io.Reader, buffer []byte) (int, error) { + n, err := io.ReadFull(reader, buffer) + if err == io.ErrUnexpectedEOF { + return n, io.EOF + } + return n, err +} + +// first argument is the command, like cat or echo, +// the second is the list of args to pass to it +type CommandExecuter interface { + Exec(string, []string, []byte) ([]byte, error) +} + +type Runner struct{} + +// ExecuteCommand is used to execute a linux command line command and return the output of the command with an error if it exists. +func (r Runner) Exec(cmdName string, args []string, input []byte) ([]byte, error) { + var out bytes.Buffer + stdInputBuffer := bytes.NewBuffer(input) + cmd := exec.Command(cmdName, args...) + cmd.Stdin = stdInputBuffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return nil, errors.Wrapf(err, "Error while running command: %s", cmdName) + } + return out.Bytes(), nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.pb.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.pb.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.pb.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.pb.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,243 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: keyprovider.proto + +package keyprovider + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// 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.ProtoPackageIsVersion3 // please upgrade the proto package + +type KeyProviderKeyWrapProtocolInput struct { + KeyProviderKeyWrapProtocolInput []byte `protobuf:"bytes,1,opt,name=KeyProviderKeyWrapProtocolInput,proto3" json:"KeyProviderKeyWrapProtocolInput,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KeyProviderKeyWrapProtocolInput) Reset() { *m = KeyProviderKeyWrapProtocolInput{} } +func (m *KeyProviderKeyWrapProtocolInput) String() string { return proto.CompactTextString(m) } +func (*KeyProviderKeyWrapProtocolInput) ProtoMessage() {} +func (*KeyProviderKeyWrapProtocolInput) Descriptor() ([]byte, []int) { + return fileDescriptor_da74c8e785ad390c, []int{0} +} + +func (m *KeyProviderKeyWrapProtocolInput) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KeyProviderKeyWrapProtocolInput.Unmarshal(m, b) +} +func (m *KeyProviderKeyWrapProtocolInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KeyProviderKeyWrapProtocolInput.Marshal(b, m, deterministic) +} +func (m *KeyProviderKeyWrapProtocolInput) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyProviderKeyWrapProtocolInput.Merge(m, src) +} +func (m *KeyProviderKeyWrapProtocolInput) XXX_Size() int { + return xxx_messageInfo_KeyProviderKeyWrapProtocolInput.Size(m) +} +func (m *KeyProviderKeyWrapProtocolInput) XXX_DiscardUnknown() { + xxx_messageInfo_KeyProviderKeyWrapProtocolInput.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyProviderKeyWrapProtocolInput proto.InternalMessageInfo + +func (m *KeyProviderKeyWrapProtocolInput) GetKeyProviderKeyWrapProtocolInput() []byte { + if m != nil { + return m.KeyProviderKeyWrapProtocolInput + } + return nil +} + +type KeyProviderKeyWrapProtocolOutput struct { + KeyProviderKeyWrapProtocolOutput []byte `protobuf:"bytes,1,opt,name=KeyProviderKeyWrapProtocolOutput,proto3" json:"KeyProviderKeyWrapProtocolOutput,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KeyProviderKeyWrapProtocolOutput) Reset() { *m = KeyProviderKeyWrapProtocolOutput{} } +func (m *KeyProviderKeyWrapProtocolOutput) String() string { return proto.CompactTextString(m) } +func (*KeyProviderKeyWrapProtocolOutput) ProtoMessage() {} +func (*KeyProviderKeyWrapProtocolOutput) Descriptor() ([]byte, []int) { + return fileDescriptor_da74c8e785ad390c, []int{1} +} + +func (m *KeyProviderKeyWrapProtocolOutput) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KeyProviderKeyWrapProtocolOutput.Unmarshal(m, b) +} +func (m *KeyProviderKeyWrapProtocolOutput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KeyProviderKeyWrapProtocolOutput.Marshal(b, m, deterministic) +} +func (m *KeyProviderKeyWrapProtocolOutput) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyProviderKeyWrapProtocolOutput.Merge(m, src) +} +func (m *KeyProviderKeyWrapProtocolOutput) XXX_Size() int { + return xxx_messageInfo_KeyProviderKeyWrapProtocolOutput.Size(m) +} +func (m *KeyProviderKeyWrapProtocolOutput) XXX_DiscardUnknown() { + xxx_messageInfo_KeyProviderKeyWrapProtocolOutput.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyProviderKeyWrapProtocolOutput proto.InternalMessageInfo + +func (m *KeyProviderKeyWrapProtocolOutput) GetKeyProviderKeyWrapProtocolOutput() []byte { + if m != nil { + return m.KeyProviderKeyWrapProtocolOutput + } + return nil +} + +func init() { + proto.RegisterType((*KeyProviderKeyWrapProtocolInput)(nil), "keyprovider.keyProviderKeyWrapProtocolInput") + proto.RegisterType((*KeyProviderKeyWrapProtocolOutput)(nil), "keyprovider.keyProviderKeyWrapProtocolOutput") +} + +func init() { + proto.RegisterFile("keyprovider.proto", fileDescriptor_da74c8e785ad390c) +} + +var fileDescriptor_da74c8e785ad390c = []byte{ + // 169 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xcc, 0x4e, 0xad, 0x2c, + 0x28, 0xca, 0x2f, 0xcb, 0x4c, 0x49, 0x2d, 0xd2, 0x03, 0x32, 0x4a, 0xf2, 0x85, 0xb8, 0x91, 0x84, + 0x94, 0xb2, 0xb9, 0xe4, 0x81, 0xdc, 0x00, 0x28, 0xd7, 0x3b, 0xb5, 0x32, 0xbc, 0x28, 0xb1, 0x20, + 0x00, 0xa4, 0x2e, 0x39, 0x3f, 0xc7, 0x33, 0xaf, 0xa0, 0xb4, 0x44, 0xc8, 0x83, 0x4b, 0xde, 0x1b, + 0xbf, 0x12, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x42, 0xca, 0x94, 0xf2, 0xb8, 0x14, 0x70, + 0x5b, 0xe6, 0x5f, 0x5a, 0x02, 0xb2, 0xcd, 0x8b, 0x4b, 0xc1, 0x9b, 0x80, 0x1a, 0xa8, 0x75, 0x04, + 0xd5, 0x19, 0xbd, 0x62, 0xe4, 0x12, 0x42, 0x52, 0x14, 0x9c, 0x5a, 0x54, 0x96, 0x99, 0x9c, 0x2a, + 0x94, 0xc1, 0xc5, 0x0e, 0x52, 0x0c, 0x94, 0x11, 0xd2, 0xd1, 0x43, 0x0e, 0x1f, 0x02, 0x21, 0x21, + 0xa5, 0x4b, 0xa4, 0x6a, 0x88, 0xf5, 0x4a, 0x0c, 0x42, 0x59, 0x5c, 0x9c, 0xa1, 0x79, 0xf4, 0xb1, + 0xcb, 0x89, 0x37, 0x0a, 0x39, 0x62, 0x93, 0xd8, 0xc0, 0x91, 0x6d, 0x0c, 0x08, 0x00, 0x00, 0xff, + 0xff, 0x9a, 0x10, 0xcb, 0xf9, 0x01, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// KeyProviderServiceClient is the client API for KeyProviderService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type KeyProviderServiceClient interface { + WrapKey(ctx context.Context, in *KeyProviderKeyWrapProtocolInput, opts ...grpc.CallOption) (*KeyProviderKeyWrapProtocolOutput, error) + UnWrapKey(ctx context.Context, in *KeyProviderKeyWrapProtocolInput, opts ...grpc.CallOption) (*KeyProviderKeyWrapProtocolOutput, error) +} + +type keyProviderServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewKeyProviderServiceClient(cc grpc.ClientConnInterface) KeyProviderServiceClient { + return &keyProviderServiceClient{cc} +} + +func (c *keyProviderServiceClient) WrapKey(ctx context.Context, in *KeyProviderKeyWrapProtocolInput, opts ...grpc.CallOption) (*KeyProviderKeyWrapProtocolOutput, error) { + out := new(KeyProviderKeyWrapProtocolOutput) + err := c.cc.Invoke(ctx, "/keyprovider.KeyProviderService/WrapKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyProviderServiceClient) UnWrapKey(ctx context.Context, in *KeyProviderKeyWrapProtocolInput, opts ...grpc.CallOption) (*KeyProviderKeyWrapProtocolOutput, error) { + out := new(KeyProviderKeyWrapProtocolOutput) + err := c.cc.Invoke(ctx, "/keyprovider.KeyProviderService/UnWrapKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// KeyProviderServiceServer is the server API for KeyProviderService service. +type KeyProviderServiceServer interface { + WrapKey(context.Context, *KeyProviderKeyWrapProtocolInput) (*KeyProviderKeyWrapProtocolOutput, error) + UnWrapKey(context.Context, *KeyProviderKeyWrapProtocolInput) (*KeyProviderKeyWrapProtocolOutput, error) +} + +// UnimplementedKeyProviderServiceServer can be embedded to have forward compatible implementations. +type UnimplementedKeyProviderServiceServer struct { +} + +func (*UnimplementedKeyProviderServiceServer) WrapKey(ctx context.Context, req *KeyProviderKeyWrapProtocolInput) (*KeyProviderKeyWrapProtocolOutput, error) { + return nil, status.Errorf(codes.Unimplemented, "method WrapKey not implemented") +} +func (*UnimplementedKeyProviderServiceServer) UnWrapKey(ctx context.Context, req *KeyProviderKeyWrapProtocolInput) (*KeyProviderKeyWrapProtocolOutput, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnWrapKey not implemented") +} + +func RegisterKeyProviderServiceServer(s *grpc.Server, srv KeyProviderServiceServer) { + s.RegisterService(&_KeyProviderService_serviceDesc, srv) +} + +func _KeyProviderService_WrapKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(KeyProviderKeyWrapProtocolInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyProviderServiceServer).WrapKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/keyprovider.KeyProviderService/WrapKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyProviderServiceServer).WrapKey(ctx, req.(*KeyProviderKeyWrapProtocolInput)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyProviderService_UnWrapKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(KeyProviderKeyWrapProtocolInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyProviderServiceServer).UnWrapKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/keyprovider.KeyProviderService/UnWrapKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyProviderServiceServer).UnWrapKey(ctx, req.(*KeyProviderKeyWrapProtocolInput)) + } + return interceptor(ctx, in, info, handler) +} + +var _KeyProviderService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "keyprovider.KeyProviderService", + HandlerType: (*KeyProviderServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "WrapKey", + Handler: _KeyProviderService_WrapKey_Handler, + }, + { + MethodName: "UnWrapKey", + Handler: _KeyProviderService_UnWrapKey_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "keyprovider.proto", +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.proto containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.proto --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.proto 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/keyprovider/keyprovider.proto 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package keyprovider; +option go_package = "keyprovider"; + +message keyProviderKeyWrapProtocolInput { + bytes KeyProviderKeyWrapProtocolInput = 1; +} + +message keyProviderKeyWrapProtocolOutput { + bytes KeyProviderKeyWrapProtocolOutput = 1; +} + +service KeyProviderService { + rpc WrapKey(keyProviderKeyWrapProtocolInput) returns (keyProviderKeyWrapProtocolOutput) {}; + rpc UnWrapKey(keyProviderKeyWrapProtocolInput) returns (keyProviderKeyWrapProtocolOutput) {}; +} \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/testing.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/testing.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/testing.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/testing.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,166 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "time" + + "github.com/pkg/errors" +) + +// CreateRSAKey creates an RSA key +func CreateRSAKey(bits int) (*rsa.PrivateKey, error) { + key, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, errors.Wrap(err, "rsa.GenerateKey failed") + } + return key, nil +} + +// CreateRSATestKey creates an RSA key of the given size and returns +// the public and private key in PEM or DER format +func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte, error) { + key, err := CreateRSAKey(bits) + if err != nil { + return nil, nil, err + } + + pubData, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + return nil, nil, errors.Wrap(err, "x509.MarshalPKIXPublicKey failed") + } + privData := x509.MarshalPKCS1PrivateKey(key) + + // no more encoding needed for DER + if !pemencode { + return pubData, privData, nil + } + + publicKey := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: pubData, + }) + + var block *pem.Block + + typ := "RSA PRIVATE KEY" + if len(password) > 0 { + block, err = x509.EncryptPEMBlock(rand.Reader, typ, privData, password, x509.PEMCipherAES256) //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility + if err != nil { + return nil, nil, errors.Wrap(err, "x509.EncryptPEMBlock failed") + } + } else { + block = &pem.Block{ + Type: typ, + Bytes: privData, + } + } + + privateKey := pem.EncodeToMemory(block) + + return publicKey, privateKey, nil +} + +// CreateECDSATestKey creates and elliptic curve key for the given curve and returns +// the public and private key in DER format +func CreateECDSATestKey(curve elliptic.Curve) ([]byte, []byte, error) { + key, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, nil, errors.Wrapf(err, "ecdsa.GenerateKey failed") + } + + pubData, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + return nil, nil, errors.Wrapf(err, "x509.MarshalPKIXPublicKey failed") + } + + privData, err := x509.MarshalECPrivateKey(key) + if err != nil { + return nil, nil, errors.Wrapf(err, "x509.MarshalECPrivateKey failed") + } + + return pubData, privData, nil +} + +// CreateTestCA creates a root CA for testing +func CreateTestCA() (*rsa.PrivateKey, *x509.Certificate, error) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, errors.Wrap(err, "rsa.GenerateKey failed") + } + + ca := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "test-ca", + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + IsCA: true, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + caCert, err := certifyKey(&key.PublicKey, ca, key, ca) + + return key, caCert, err +} + +// CertifyKey certifies a public key using the given CA's private key and cert; +// The certificate template for the public key is optional +func CertifyKey(pubbytes []byte, template *x509.Certificate, caKey *rsa.PrivateKey, caCert *x509.Certificate) (*x509.Certificate, error) { + pubKey, err := ParsePublicKey(pubbytes, "CertifyKey") + if err != nil { + return nil, err + } + return certifyKey(pubKey, template, caKey, caCert) +} + +func certifyKey(pub interface{}, template *x509.Certificate, caKey *rsa.PrivateKey, caCert *x509.Certificate) (*x509.Certificate, error) { + if template == nil { + template = &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "testkey", + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour), + IsCA: false, + KeyUsage: x509.KeyUsageDigitalSignature, + BasicConstraintsValid: true, + } + } + + certDER, err := x509.CreateCertificate(rand.Reader, template, caCert, pub, caKey) + if err != nil { + return nil, errors.Wrap(err, "x509.CreateCertificate failed") + } + + cert, err := x509.ParseCertificate(certDER) + if err != nil { + return nil, errors.Wrap(err, "x509.ParseCertificate failed") + } + + return cert, nil +} diff -Nru containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/utils.go containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/utils.go --- containerd-1.2.6/vendor/github.com/containers/ocicrypt/utils/utils.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/containers/ocicrypt/utils/utils.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,250 @@ +/* + Copyright The ocicrypt Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package utils + +import ( + "bytes" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "strings" + + "github.com/containers/ocicrypt/crypto/pkcs11" + + "github.com/pkg/errors" + "golang.org/x/crypto/openpgp" + json "gopkg.in/square/go-jose.v2" +) + +// parseJWKPrivateKey parses the input byte array as a JWK and makes sure it's a private key +func parseJWKPrivateKey(privKey []byte, prefix string) (interface{}, error) { + jwk := json.JSONWebKey{} + err := jwk.UnmarshalJSON(privKey) + if err != nil { + return nil, errors.Wrapf(err, "%s: Could not parse input as JWK", prefix) + } + if jwk.IsPublic() { + return nil, fmt.Errorf("%s: JWK is not a private key", prefix) + } + return &jwk, nil +} + +// parseJWKPublicKey parses the input byte array as a JWK +func parseJWKPublicKey(privKey []byte, prefix string) (interface{}, error) { + jwk := json.JSONWebKey{} + err := jwk.UnmarshalJSON(privKey) + if err != nil { + return nil, errors.Wrapf(err, "%s: Could not parse input as JWK", prefix) + } + if !jwk.IsPublic() { + return nil, fmt.Errorf("%s: JWK is not a public key", prefix) + } + return &jwk, nil +} + +// parsePkcs11PrivateKeyYaml parses the input byte array as pkcs11 key file yaml format) +func parsePkcs11PrivateKeyYaml(yaml []byte, prefix string) (*pkcs11.Pkcs11KeyFileObject, error) { + // if the URI does not have enough attributes, we will throw an error when decrypting + return pkcs11.ParsePkcs11KeyFile(yaml) +} + +// parsePkcs11URIPublicKey parses the input byte array as a pkcs11 key file yaml +func parsePkcs11PublicKeyYaml(yaml []byte, prefix string) (*pkcs11.Pkcs11KeyFileObject, error) { + // if the URI does not have enough attributes, we will throw an error when decrypting + return pkcs11.ParsePkcs11KeyFile(yaml) +} + +// IsPasswordError checks whether an error is related to a missing or wrong +// password +func IsPasswordError(err error) bool { + if err == nil { + return false + } + msg := strings.ToLower(err.Error()) + + return strings.Contains(msg, "password") && + (strings.Contains(msg, "missing") || strings.Contains(msg, "wrong")) +} + +// ParsePrivateKey tries to parse a private key in DER format first and +// PEM format after, returning an error if the parsing failed +func ParsePrivateKey(privKey, privKeyPassword []byte, prefix string) (interface{}, error) { + key, err := x509.ParsePKCS8PrivateKey(privKey) + if err != nil { + key, err = x509.ParsePKCS1PrivateKey(privKey) + if err != nil { + key, err = x509.ParseECPrivateKey(privKey) + } + } + if err != nil { + block, _ := pem.Decode(privKey) + if block != nil { + var der []byte + if x509.IsEncryptedPEMBlock(block) { //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility + if privKeyPassword == nil { + return nil, errors.Errorf("%s: Missing password for encrypted private key", prefix) + } + der, err = x509.DecryptPEMBlock(block, privKeyPassword) //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility + if err != nil { + return nil, errors.Errorf("%s: Wrong password: could not decrypt private key", prefix) + } + } else { + der = block.Bytes + } + + key, err = x509.ParsePKCS8PrivateKey(der) + if err != nil { + key, err = x509.ParsePKCS1PrivateKey(der) + if err != nil { + return nil, errors.Wrapf(err, "%s: Could not parse private key", prefix) + } + } + } else { + key, err = parseJWKPrivateKey(privKey, prefix) + if err != nil { + key, err = parsePkcs11PrivateKeyYaml(privKey, prefix) + } + } + } + return key, err +} + +// IsPrivateKey returns true in case the given byte array represents a private key +// It returns an error if for example the password is wrong +func IsPrivateKey(data []byte, password []byte) (bool, error) { + _, err := ParsePrivateKey(data, password, "") + return err == nil, err +} + +// IsPkcs11PrivateKey returns true in case the given byte array represents a pkcs11 private key +func IsPkcs11PrivateKey(data []byte) bool { + return pkcs11.IsPkcs11PrivateKey(data) +} + +// ParsePublicKey tries to parse a public key in DER format first and +// PEM format after, returning an error if the parsing failed +func ParsePublicKey(pubKey []byte, prefix string) (interface{}, error) { + key, err := x509.ParsePKIXPublicKey(pubKey) + if err != nil { + block, _ := pem.Decode(pubKey) + if block != nil { + key, err = x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, errors.Wrapf(err, "%s: Could not parse public key", prefix) + } + } else { + key, err = parseJWKPublicKey(pubKey, prefix) + if err != nil { + key, err = parsePkcs11PublicKeyYaml(pubKey, prefix) + } + } + } + return key, err +} + +// IsPublicKey returns true in case the given byte array represents a public key +func IsPublicKey(data []byte) bool { + _, err := ParsePublicKey(data, "") + return err == nil +} + +// IsPkcs11PublicKey returns true in case the given byte array represents a pkcs11 public key +func IsPkcs11PublicKey(data []byte) bool { + return pkcs11.IsPkcs11PublicKey(data) +} + +// ParseCertificate tries to parse a public key in DER format first and +// PEM format after, returning an error if the parsing failed +func ParseCertificate(certBytes []byte, prefix string) (*x509.Certificate, error) { + x509Cert, err := x509.ParseCertificate(certBytes) + if err != nil { + block, _ := pem.Decode(certBytes) + if block == nil { + return nil, fmt.Errorf("%s: Could not PEM decode x509 certificate", prefix) + } + x509Cert, err = x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, errors.Wrapf(err, "%s: Could not parse x509 certificate", prefix) + } + } + return x509Cert, err +} + +// IsCertificate returns true in case the given byte array represents an x.509 certificate +func IsCertificate(data []byte) bool { + _, err := ParseCertificate(data, "") + return err == nil +} + +// IsGPGPrivateKeyRing returns true in case the given byte array represents a GPG private key ring file +func IsGPGPrivateKeyRing(data []byte) bool { + r := bytes.NewBuffer(data) + _, err := openpgp.ReadKeyRing(r) + return err == nil +} + +// SortDecryptionKeys parses a list of comma separated base64 entries and sorts the data into +// a map. Each entry in the list may be either a GPG private key ring, private key, or x.509 +// certificate +func SortDecryptionKeys(b64ItemList string) (map[string][][]byte, error) { + dcparameters := make(map[string][][]byte) + + for _, b64Item := range strings.Split(b64ItemList, ",") { + var password []byte + b64Data := strings.Split(b64Item, ":") + keyData, err := base64.StdEncoding.DecodeString(b64Data[0]) + if err != nil { + return nil, errors.New("Could not base64 decode a passed decryption key") + } + if len(b64Data) == 2 { + password, err = base64.StdEncoding.DecodeString(b64Data[1]) + if err != nil { + return nil, errors.New("Could not base64 decode a passed decryption key password") + } + } + var key string + isPrivKey, err := IsPrivateKey(keyData, password) + if IsPasswordError(err) { + return nil, err + } + if isPrivKey { + key = "privkeys" + if _, ok := dcparameters["privkeys-passwords"]; !ok { + dcparameters["privkeys-passwords"] = [][]byte{password} + } else { + dcparameters["privkeys-passwords"] = append(dcparameters["privkeys-passwords"], password) + } + } else if IsCertificate(keyData) { + key = "x509s" + } else if IsGPGPrivateKeyRing(keyData) { + key = "gpg-privatekeys" + } + if key != "" { + values := dcparameters[key] + if values == nil { + dcparameters[key] = [][]byte{keyData} + } else { + dcparameters[key] = append(dcparameters[key], keyData) + } + } else { + return nil, errors.New("Unknown decryption key type") + } + } + + return dcparameters, nil +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/dbus.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/dbus.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/dbus.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/dbus.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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. - -// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ -package dbus - -import ( - "fmt" - "os" - "strconv" - "strings" - "sync" - - "github.com/godbus/dbus" -) - -const ( - alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` - num = `0123456789` - alphanum = alpha + num - signalBuffer = 100 -) - -// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped -func needsEscape(i int, b byte) bool { - // Escape everything that is not a-z-A-Z-0-9 - // Also escape 0-9 if it's the first character - return strings.IndexByte(alphanum, b) == -1 || - (i == 0 && strings.IndexByte(num, b) != -1) -} - -// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the -// rules that systemd uses for serializing special characters. -func PathBusEscape(path string) string { - // Special case the empty string - if len(path) == 0 { - return "_" - } - n := []byte{} - for i := 0; i < len(path); i++ { - c := path[i] - if needsEscape(i, c) { - e := fmt.Sprintf("_%x", c) - n = append(n, []byte(e)...) - } else { - n = append(n, c) - } - } - return string(n) -} - -// Conn is a connection to systemd's dbus endpoint. -type Conn struct { - // sysconn/sysobj are only used to call dbus methods - sysconn *dbus.Conn - sysobj dbus.BusObject - - // sigconn/sigobj are only used to receive dbus signals - sigconn *dbus.Conn - sigobj dbus.BusObject - - jobListener struct { - jobs map[dbus.ObjectPath]chan<- string - sync.Mutex - } - subscriber struct { - updateCh chan<- *SubStateUpdate - errCh chan<- error - sync.Mutex - ignore map[dbus.ObjectPath]int64 - cleanIgnore int64 - } -} - -// New establishes a connection to any available bus and authenticates. -// Callers should call Close() when done with the connection. -func New() (*Conn, error) { - conn, err := NewSystemConnection() - if err != nil && os.Geteuid() == 0 { - return NewSystemdConnection() - } - return conn, err -} - -// NewSystemConnection establishes a connection to the system bus and authenticates. -// Callers should call Close() when done with the connection -func NewSystemConnection() (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SystemBusPrivate) - }) -} - -// NewUserConnection establishes a connection to the session bus and -// authenticates. This can be used to connect to systemd user instances. -// Callers should call Close() when done with the connection. -func NewUserConnection() (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SessionBusPrivate) - }) -} - -// NewSystemdConnection establishes a private, direct connection to systemd. -// This can be used for communicating with systemd without a dbus daemon. -// Callers should call Close() when done with the connection. -func NewSystemdConnection() (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - // We skip Hello when talking directly to systemd. - return dbusAuthConnection(func() (*dbus.Conn, error) { - return dbus.Dial("unix:path=/run/systemd/private") - }) - }) -} - -// Close closes an established connection -func (c *Conn) Close() { - c.sysconn.Close() - c.sigconn.Close() -} - -// NewConnection establishes a connection to a bus using a caller-supplied function. -// This allows connecting to remote buses through a user-supplied mechanism. -// The supplied function may be called multiple times, and should return independent connections. -// The returned connection must be fully initialised: the org.freedesktop.DBus.Hello call must have succeeded, -// and any authentication should be handled by the function. -func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := dialBus() - if err != nil { - return nil, err - } - - sigconn, err := dialBus() - if err != nil { - sysconn.Close() - return nil, err - } - - c := &Conn{ - sysconn: sysconn, - sysobj: systemdObject(sysconn), - sigconn: sigconn, - sigobj: systemdObject(sigconn), - } - - c.subscriber.ignore = make(map[dbus.ObjectPath]int64) - c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) - - // Setup the listeners on jobs so that we can get completions - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") - - c.dispatch() - return c, nil -} - -// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager -// interface. The value is returned in its string representation, as defined at -// https://developer.gnome.org/glib/unstable/gvariant-text.html -func (c *Conn) GetManagerProperty(prop string) (string, error) { - variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop) - if err != nil { - return "", err - } - return variant.String(), nil -} - -func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := createBus() - if err != nil { - return nil, err - } - - // Only use EXTERNAL method, and hardcode the uid (not username) - // to avoid a username lookup (which requires a dynamically linked - // libc) - methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))} - - err = conn.Auth(methods) - if err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := dbusAuthConnection(createBus) - if err != nil { - return nil, err - } - - if err = conn.Hello(); err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func systemdObject(conn *dbus.Conn) dbus.BusObject { - return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/methods.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/methods.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/methods.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/methods.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,565 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "errors" - "path" - "strconv" - - "github.com/godbus/dbus" -) - -func (c *Conn) jobComplete(signal *dbus.Signal) { - var id uint32 - var job dbus.ObjectPath - var unit string - var result string - dbus.Store(signal.Body, &id, &job, &unit, &result) - c.jobListener.Lock() - out, ok := c.jobListener.jobs[job] - if ok { - out <- result - delete(c.jobListener.jobs, job) - } - c.jobListener.Unlock() -} - -func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { - if ch != nil { - c.jobListener.Lock() - defer c.jobListener.Unlock() - } - - var p dbus.ObjectPath - err := c.sysobj.Call(job, 0, args...).Store(&p) - if err != nil { - return 0, err - } - - if ch != nil { - c.jobListener.jobs[p] = ch - } - - // ignore error since 0 is fine if conversion fails - jobID, _ := strconv.Atoi(path.Base(string(p))) - - return jobID, nil -} - -// StartUnit enqueues a start job and depending jobs, if any (unless otherwise -// specified by the mode string). -// -// Takes the unit to activate, plus a mode string. The mode needs to be one of -// replace, fail, isolate, ignore-dependencies, ignore-requirements. If -// "replace" the call will start the unit and its dependencies, possibly -// replacing already queued jobs that conflict with this. If "fail" the call -// will start the unit and its dependencies, but will fail if this would change -// an already queued job. If "isolate" the call will start the unit in question -// and terminate all units that aren't dependencies of it. If -// "ignore-dependencies" it will start a unit but ignore all its dependencies. -// If "ignore-requirements" it will start a unit but only ignore the -// requirement dependencies. It is not recommended to make use of the latter -// two options. -// -// If the provided channel is non-nil, a result string will be sent to it upon -// job completion: one of done, canceled, timeout, failed, dependency, skipped. -// done indicates successful execution of a job. canceled indicates that a job -// has been canceled before it finished execution. timeout indicates that the -// job timeout was reached. failed indicates that the job failed. dependency -// indicates that a job this job has been depending on failed and the job hence -// has been removed too. skipped indicates that a job was skipped because it -// didn't apply to the units current state. -// -// If no error occurs, the ID of the underlying systemd job will be returned. There -// does exist the possibility for no error to be returned, but for the returned job -// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint -// should not be considered authoritative. -// -// If an error does occur, it will be returned to the user alongside a job ID of 0. -func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) -} - -// StopUnit is similar to StartUnit but stops the specified unit rather -// than starting it. -func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) -} - -// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. -func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) -} - -// RestartUnit restarts a service. If a service is restarted that isn't -// running it will be started. -func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) -} - -// TryRestartUnit is like RestartUnit, except that a service that isn't running -// is not affected by the restart. -func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) -} - -// ReloadOrRestart attempts a reload if the unit supports it and use a restart -// otherwise. -func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) -} - -// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" -// flavored restart otherwise. -func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) -} - -// StartTransientUnit() may be used to create and start a transient unit, which -// will be released as soon as it is not running or referenced anymore or the -// system is rebooted. name is the unit name including suffix, and must be -// unique. mode is the same as in StartUnit(), properties contains properties -// of the unit. -func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) -} - -// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's -// processes are killed. -func (c *Conn) KillUnit(name string, signal int32) { - c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() -} - -// ResetFailedUnit resets the "failed" state of a specific unit. -func (c *Conn) ResetFailedUnit(name string) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() -} - -// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface -func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) { - var err error - var props map[string]dbus.Variant - - path := unitPath(unit) - if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) - if err != nil { - return nil, err - } - - out := make(map[string]interface{}, len(props)) - for k, v := range props { - out[k] = v.Value() - } - - return out, nil -} - -// GetUnitProperties takes the unit name and returns all of its dbus object properties. -func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1.Unit") -} - -func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { - var err error - var prop dbus.Variant - - path := unitPath(unit) - if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) - if err != nil { - return nil, err - } - - return &Property{Name: propertyName, Value: prop}, nil -} - -func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) -} - -// GetServiceProperty returns property for given service name and property name -func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { - return c.getProperty(service, "org.freedesktop.systemd1.Service", propertyName) -} - -// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. -// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope -// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit -func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1."+unitType) -} - -// SetUnitProperties() may be used to modify certain unit properties at runtime. -// Not all properties may be changed at runtime, but many resource management -// settings (primarily those in systemd.cgroup(5)) may. The changes are applied -// instantly, and stored on disk for future boots, unless runtime is true, in which -// case the settings only apply until the next reboot. name is the name of the unit -// to modify. properties are the settings to set, encoded as an array of property -// name and value pairs. -func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() -} - -func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) -} - -type UnitStatus struct { - Name string // The primary unit name as string - Description string // The human readable description string - LoadState string // The load state (i.e. whether the unit file has been loaded successfully) - ActiveState string // The active state (i.e. whether the unit is currently started or not) - SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not) - Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string. - Path dbus.ObjectPath // The unit object path - JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise - JobType string // The job type as string - JobPath dbus.ObjectPath // The job object path -} - -type storeFunc func(retvalues ...interface{}) error - -func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - status := make([]UnitStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } - - err = dbus.Store(resultInterface, statusInterface...) - if err != nil { - return nil, err - } - - return status, nil -} - -// ListUnits returns an array with all currently loaded units. Note that -// units may be known by multiple names at the same time, and hence there might -// be more unit names loaded than actual units behind them. -func (c *Conn) ListUnits() ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) -} - -// ListUnitsFiltered returns an array with units filtered by state. -// It takes a list of units' statuses to filter. -func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) -} - -// ListUnitsByPatterns returns an array with units. -// It takes a list of units' statuses and names to filter. -// Note that units may be known by multiple names at the same time, -// and hence there might be more unit names loaded than actual units behind them. -func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) -} - -// ListUnitsByNames returns an array with units. It takes a list of units' -// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns -// method, this method returns statuses even for inactive or non-existing -// units. Input array should contain exact unit names, but not patterns. -func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) -} - -type UnitFile struct { - Path string - Type string -} - -func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - files := make([]UnitFile, len(result)) - fileInterface := make([]interface{}, len(files)) - for i := range files { - fileInterface[i] = &files[i] - } - - err = dbus.Store(resultInterface, fileInterface...) - if err != nil { - return nil, err - } - - return files, nil -} - -// ListUnitFiles returns an array of all available units on disk. -func (c *Conn) ListUnitFiles() ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) -} - -// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. -func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) -} - -type LinkUnitFileChange EnableUnitFileChange - -// LinkUnitFiles() links unit files (that are located outside of the -// usual unit search paths) into the unit search path. -// -// It takes a list of absolute paths to unit files to link and two -// booleans. The first boolean controls whether the unit shall be -// enabled for runtime only (true, /run), or persistently (false, -// /etc). -// The second controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns a list of the changes made. The list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]LinkUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -// EnableUnitFiles() may be used to enable one or more units in the system (by -// creating symlinks to them in /etc or /run). -// -// It takes a list of unit files to enable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and two booleans: the first controls whether the unit shall -// be enabled for runtime only (true, /run), or persistently (false, /etc). -// The second one controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns one boolean and an array with the changes made. The -// boolean signals whether the unit files contained any enablement -// information (i.e. an [Install]) section. The changes list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { - var carries_install_info bool - - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) - if err != nil { - return false, nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]EnableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return false, nil, err - } - - return carries_install_info, changes, nil -} - -type EnableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// DisableUnitFiles() may be used to disable one or more units in the system (by -// removing symlinks to them from /etc or /run). -// -// It takes a list of unit files to disable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and one boolean: whether the unit was enabled for runtime -// only (true, /run), or persistently (false, /etc). -// -// This call returns an array with the changes made. The changes list -// consists of structures with three strings: the type of the change (one of -// symlink or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]DisableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type DisableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// MaskUnitFiles masks one or more units in the system -// -// It takes three arguments: -// * list of units to mask (either just file names or full -// absolute paths if the unit files are residing outside -// the usual unit search paths) -// * runtime to specify whether the unit was enabled for runtime -// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) -// * force flag -func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]MaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type MaskUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// UnmaskUnitFiles unmasks one or more units in the system -// -// It takes two arguments: -// * list of unit files to mask (either just file names or full -// absolute paths if the unit files are residing outside -// the usual unit search paths) -// * runtime to specify whether the unit was enabled for runtime -// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) -func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]UnmaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type UnmaskUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Reload instructs systemd to scan for and reload unit files. This is -// equivalent to a 'systemctl daemon-reload'. -func (c *Conn) Reload() error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() -} - -func unitPath(name string) dbus.ObjectPath { - return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/properties.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/properties.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/properties.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/properties.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "github.com/godbus/dbus" -) - -// From the systemd docs: -// -// The properties array of StartTransientUnit() may take many of the settings -// that may also be configured in unit files. Not all parameters are currently -// accepted though, but we plan to cover more properties with future release. -// Currently you may set the Description, Slice and all dependency types of -// units, as well as RemainAfterExit, ExecStart for service units, -// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares, -// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth, -// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit, -// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map -// directly to their counterparts in unit files and as normal D-Bus object -// properties. The exception here is the PIDs field of scope units which is -// used for construction of the scope only and specifies the initial PIDs to -// add to the scope object. - -type Property struct { - Name string - Value dbus.Variant -} - -type PropertyCollection struct { - Name string - Properties []Property -} - -type execStart struct { - Path string // the binary path to execute - Args []string // an array with all arguments to pass to the executed command, starting with argument 0 - UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly -} - -// PropExecStart sets the ExecStart service property. The first argument is a -// slice with the binary path to execute followed by the arguments to pass to -// the executed command. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= -func PropExecStart(command []string, uncleanIsFailure bool) Property { - execStarts := []execStart{ - execStart{ - Path: command[0], - Args: command, - UncleanIsFailure: uncleanIsFailure, - }, - } - - return Property{ - Name: "ExecStart", - Value: dbus.MakeVariant(execStarts), - } -} - -// PropRemainAfterExit sets the RemainAfterExit service property. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit= -func PropRemainAfterExit(b bool) Property { - return Property{ - Name: "RemainAfterExit", - Value: dbus.MakeVariant(b), - } -} - -// PropType sets the Type service property. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#Type= -func PropType(t string) Property { - return Property{ - Name: "Type", - Value: dbus.MakeVariant(t), - } -} - -// PropDescription sets the Description unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description= -func PropDescription(desc string) Property { - return Property{ - Name: "Description", - Value: dbus.MakeVariant(desc), - } -} - -func propDependency(name string, units []string) Property { - return Property{ - Name: name, - Value: dbus.MakeVariant(units), - } -} - -// PropRequires sets the Requires unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires= -func PropRequires(units ...string) Property { - return propDependency("Requires", units) -} - -// PropRequiresOverridable sets the RequiresOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable= -func PropRequiresOverridable(units ...string) Property { - return propDependency("RequiresOverridable", units) -} - -// PropRequisite sets the Requisite unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite= -func PropRequisite(units ...string) Property { - return propDependency("Requisite", units) -} - -// PropRequisiteOverridable sets the RequisiteOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable= -func PropRequisiteOverridable(units ...string) Property { - return propDependency("RequisiteOverridable", units) -} - -// PropWants sets the Wants unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants= -func PropWants(units ...string) Property { - return propDependency("Wants", units) -} - -// PropBindsTo sets the BindsTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo= -func PropBindsTo(units ...string) Property { - return propDependency("BindsTo", units) -} - -// PropRequiredBy sets the RequiredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy= -func PropRequiredBy(units ...string) Property { - return propDependency("RequiredBy", units) -} - -// PropRequiredByOverridable sets the RequiredByOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable= -func PropRequiredByOverridable(units ...string) Property { - return propDependency("RequiredByOverridable", units) -} - -// PropWantedBy sets the WantedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy= -func PropWantedBy(units ...string) Property { - return propDependency("WantedBy", units) -} - -// PropBoundBy sets the BoundBy unit property. See -// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy= -func PropBoundBy(units ...string) Property { - return propDependency("BoundBy", units) -} - -// PropConflicts sets the Conflicts unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts= -func PropConflicts(units ...string) Property { - return propDependency("Conflicts", units) -} - -// PropConflictedBy sets the ConflictedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy= -func PropConflictedBy(units ...string) Property { - return propDependency("ConflictedBy", units) -} - -// PropBefore sets the Before unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before= -func PropBefore(units ...string) Property { - return propDependency("Before", units) -} - -// PropAfter sets the After unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After= -func PropAfter(units ...string) Property { - return propDependency("After", units) -} - -// PropOnFailure sets the OnFailure unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure= -func PropOnFailure(units ...string) Property { - return propDependency("OnFailure", units) -} - -// PropTriggers sets the Triggers unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers= -func PropTriggers(units ...string) Property { - return propDependency("Triggers", units) -} - -// PropTriggeredBy sets the TriggeredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy= -func PropTriggeredBy(units ...string) Property { - return propDependency("TriggeredBy", units) -} - -// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo= -func PropPropagatesReloadTo(units ...string) Property { - return propDependency("PropagatesReloadTo", units) -} - -// PropRequiresMountsFor sets the RequiresMountsFor unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor= -func PropRequiresMountsFor(units ...string) Property { - return propDependency("RequiresMountsFor", units) -} - -// PropSlice sets the Slice unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice= -func PropSlice(slice string) Property { - return Property{ - Name: "Slice", - Value: dbus.MakeVariant(slice), - } -} - -// PropPids sets the PIDs field of scope units used in the initial construction -// of the scope only and specifies the initial PIDs to add to the scope object. -// See https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#properties -func PropPids(pids ...uint32) Property { - return Property{ - Name: "PIDs", - Value: dbus.MakeVariant(pids), - } -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/set.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/set.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/set.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/set.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -type set struct { - data map[string]bool -} - -func (s *set) Add(value string) { - s.data[value] = true -} - -func (s *set) Remove(value string) { - delete(s.data, value) -} - -func (s *set) Contains(value string) (exists bool) { - _, exists = s.data[value] - return -} - -func (s *set) Length() int { - return len(s.data) -} - -func (s *set) Values() (values []string) { - for val, _ := range s.data { - values = append(values, val) - } - return -} - -func newSet() *set { - return &set{make(map[string]bool)} -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/subscription.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/subscription.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/subscription.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/subscription.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,250 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "errors" - "time" - - "github.com/godbus/dbus" -) - -const ( - cleanIgnoreInterval = int64(10 * time.Second) - ignoreInterval = int64(30 * time.Millisecond) -) - -// Subscribe sets up this connection to subscribe to all systemd dbus events. -// This is required before calling SubscribeUnits. When the connection closes -// systemd will automatically stop sending signals so there is no need to -// explicitly call Unsubscribe(). -func (c *Conn) Subscribe() error { - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") - - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() - if err != nil { - return err - } - - return nil -} - -// Unsubscribe this connection from systemd dbus events. -func (c *Conn) Unsubscribe() error { - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() - if err != nil { - return err - } - - return nil -} - -func (c *Conn) dispatch() { - ch := make(chan *dbus.Signal, signalBuffer) - - c.sigconn.Signal(ch) - - go func() { - for { - signal, ok := <-ch - if !ok { - return - } - - if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" { - c.jobComplete(signal) - } - - if c.subscriber.updateCh == nil { - continue - } - - var unitPath dbus.ObjectPath - switch signal.Name { - case "org.freedesktop.systemd1.Manager.JobRemoved": - unitName := signal.Body[2].(string) - c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) - case "org.freedesktop.systemd1.Manager.UnitNew": - unitPath = signal.Body[1].(dbus.ObjectPath) - case "org.freedesktop.DBus.Properties.PropertiesChanged": - if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { - unitPath = signal.Path - } - } - - if unitPath == dbus.ObjectPath("") { - continue - } - - c.sendSubStateUpdate(unitPath) - } - }() -} - -// Returns two unbuffered channels which will receive all changed units every -// interval. Deleted units are sent as nil. -func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { - return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) -} - -// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer -// size of the channels, the comparison function for detecting changes and a filter -// function for cutting down on the noise that your channel receives. -func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { - old := make(map[string]*UnitStatus) - statusChan := make(chan map[string]*UnitStatus, buffer) - errChan := make(chan error, buffer) - - go func() { - for { - timerChan := time.After(interval) - - units, err := c.ListUnits() - if err == nil { - cur := make(map[string]*UnitStatus) - for i := range units { - if filterUnit != nil && filterUnit(units[i].Name) { - continue - } - cur[units[i].Name] = &units[i] - } - - // add all new or changed units - changed := make(map[string]*UnitStatus) - for n, u := range cur { - if oldU, ok := old[n]; !ok || isChanged(oldU, u) { - changed[n] = u - } - delete(old, n) - } - - // add all deleted units - for oldN := range old { - changed[oldN] = nil - } - - old = cur - - if len(changed) != 0 { - statusChan <- changed - } - } else { - errChan <- err - } - - <-timerChan - } - }() - - return statusChan, errChan -} - -type SubStateUpdate struct { - UnitName string - SubState string -} - -// SetSubStateSubscriber writes to updateCh when any unit's substate changes. -// Although this writes to updateCh on every state change, the reported state -// may be more recent than the change that generated it (due to an unavoidable -// race in the systemd dbus interface). That is, this method provides a good -// way to keep a current view of all units' states, but is not guaranteed to -// show every state transition they go through. Furthermore, state changes -// will only be written to the channel with non-blocking writes. If updateCh -// is full, it attempts to write an error to errCh; if errCh is full, the error -// passes silently. -func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { - c.subscriber.Lock() - defer c.subscriber.Unlock() - c.subscriber.updateCh = updateCh - c.subscriber.errCh = errCh -} - -func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { - c.subscriber.Lock() - defer c.subscriber.Unlock() - - if c.shouldIgnore(path) { - return - } - - info, err := c.GetUnitProperties(string(path)) - if err != nil { - select { - case c.subscriber.errCh <- err: - default: - } - } - - name := info["Id"].(string) - substate := info["SubState"].(string) - - update := &SubStateUpdate{name, substate} - select { - case c.subscriber.updateCh <- update: - default: - select { - case c.subscriber.errCh <- errors.New("update channel full!"): - default: - } - } - - c.updateIgnore(path, info) -} - -// The ignore functions work around a wart in the systemd dbus interface. -// Requesting the properties of an unloaded unit will cause systemd to send a -// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's -// properties on UnitNew (as that's the only indication of a new unit coming up -// for the first time), we would enter an infinite loop if we did not attempt -// to detect and ignore these spurious signals. The signal themselves are -// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an -// unloaded unit's signals for a short time after requesting its properties. -// This means that we will miss e.g. a transient unit being restarted -// *immediately* upon failure and also a transient unit being started -// immediately after requesting its status (with systemctl status, for example, -// because this causes a UnitNew signal to be sent which then causes us to fetch -// the properties). - -func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { - t, ok := c.subscriber.ignore[path] - return ok && t >= time.Now().UnixNano() -} - -func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { - c.cleanIgnore() - - // unit is unloaded - it will trigger bad systemd dbus behavior - if info["LoadState"].(string) == "not-found" { - c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval - } -} - -// without this, ignore would grow unboundedly over time -func (c *Conn) cleanIgnore() { - now := time.Now().UnixNano() - if c.subscriber.cleanIgnore < now { - c.subscriber.cleanIgnore = now + cleanIgnoreInterval - - for p, t := range c.subscriber.ignore { - if t < now { - delete(c.subscriber.ignore, p) - } - } - } -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/subscription_set.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/subscription_set.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/dbus/subscription_set.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/dbus/subscription_set.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dbus - -import ( - "time" -) - -// SubscriptionSet returns a subscription set which is like conn.Subscribe but -// can filter to only return events for a set of units. -type SubscriptionSet struct { - *set - conn *Conn -} - -func (s *SubscriptionSet) filter(unit string) bool { - return !s.Contains(unit) -} - -// Subscribe starts listening for dbus events for all of the units in the set. -// Returns channels identical to conn.SubscribeUnits. -func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { - // TODO: Make fully evented by using systemd 209 with properties changed values - return s.conn.SubscribeUnitsCustom(time.Second, 0, - mismatchUnitStatus, - func(unit string) bool { return s.filter(unit) }, - ) -} - -// NewSubscriptionSet returns a new subscription set. -func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { - return &SubscriptionSet{newSet(), conn} -} - -// mismatchUnitStatus returns true if the provided UnitStatus objects -// are not equivalent. false is returned if the objects are equivalent. -// Only the Name, Description and state-related fields are used in -// the comparison. -func mismatchUnitStatus(u1, u2 *UnitStatus) bool { - return u1.Name != u2.Name || - u1.Description != u2.Description || - u1.LoadState != u2.LoadState || - u1.ActiveState != u2.ActiveState || - u1.SubState != u2.SubState -} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/LICENSE containerd-1.5.9/vendor/github.com/coreos/go-systemd/LICENSE --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/README.md containerd-1.5.9/vendor/github.com/coreos/go-systemd/README.md --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -# go-systemd - -[![Build Status](https://travis-ci.org/coreos/go-systemd.png?branch=master)](https://travis-ci.org/coreos/go-systemd) -[![godoc](https://godoc.org/github.com/coreos/go-systemd?status.svg)](http://godoc.org/github.com/coreos/go-systemd) - -Go bindings to systemd. The project has several packages: - -- `activation` - for writing and using socket activation from Go -- `dbus` - for starting/stopping/inspecting running services and units -- `journal` - for writing to systemd's logging service, journald -- `sdjournal` - for reading from journald by wrapping its C API -- `machine1` - for registering machines/containers with systemd -- `unit` - for (de)serialization and comparison of unit files - -## Socket Activation - -An example HTTP server using socket activation can be quickly set up by following this README on a Linux machine running systemd: - -https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver - -## Journal - -Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry. -The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available. - -## D-Bus - -The `dbus` package connects to the [systemd D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/dbus/) and lets you start, stop and introspect systemd units. The API docs are here: - -http://godoc.org/github.com/coreos/go-systemd/dbus - -### Debugging - -Create `/etc/dbus-1/system-local.conf` that looks like this: - -``` - - - - - - - -``` - -## machined - -The `machine1` package allows interaction with the [systemd machined D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/machined/). - -## Units - -The `unit` package provides various functions for working with [systemd unit files](http://www.freedesktop.org/software/systemd/man/systemd.unit.html). diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,84 @@ +// Copyright 2014 Docker, Inc. +// Copyright 2015-2018 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package daemon provides a Go implementation of the sd_notify protocol. +// It can be used to inform systemd of service start-up completion, watchdog +// events, and other status changes. +// +// https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description +package daemon + +import ( + "net" + "os" +) + +const ( + // SdNotifyReady tells the service manager that service startup is finished + // or the service finished loading its configuration. + SdNotifyReady = "READY=1" + + // SdNotifyStopping tells the service manager that the service is beginning + // its shutdown. + SdNotifyStopping = "STOPPING=1" + + // SdNotifyReloading tells the service manager that this service is + // reloading its configuration. Note that you must call SdNotifyReady when + // it completed reloading. + SdNotifyReloading = "RELOADING=1" + + // SdNotifyWatchdog tells the service manager to update the watchdog + // timestamp for the service. + SdNotifyWatchdog = "WATCHDOG=1" +) + +// SdNotify sends a message to the init daemon. It is common to ignore the error. +// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET` +// will be unconditionally unset. +// +// It returns one of the following: +// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset) +// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data) +// (true, nil) - notification supported, data has been sent +func SdNotify(unsetEnvironment bool, state string) (bool, error) { + socketAddr := &net.UnixAddr{ + Name: os.Getenv("NOTIFY_SOCKET"), + Net: "unixgram", + } + + // NOTIFY_SOCKET not set + if socketAddr.Name == "" { + return false, nil + } + + if unsetEnvironment { + if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { + return false, err + } + } + + conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + // Error connecting to NOTIFY_SOCKET + if err != nil { + return false, err + } + defer conn.Close() + + if _, err = conn.Write([]byte(state)); err != nil { + return false, err + } + return true, nil +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,73 @@ +// Copyright 2016 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package daemon + +import ( + "fmt" + "os" + "strconv" + "time" +) + +// SdWatchdogEnabled returns watchdog information for a service. +// Processes should call daemon.SdNotify(false, daemon.SdNotifyWatchdog) every +// time / 2. +// If `unsetEnvironment` is true, the environment variables `WATCHDOG_USEC` and +// `WATCHDOG_PID` will be unconditionally unset. +// +// It returns one of the following: +// (0, nil) - watchdog isn't enabled or we aren't the watched PID. +// (0, err) - an error happened (e.g. error converting time). +// (time, nil) - watchdog is enabled and we can send ping. +// time is delay before inactive service will be killed. +func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) { + wusec := os.Getenv("WATCHDOG_USEC") + wpid := os.Getenv("WATCHDOG_PID") + if unsetEnvironment { + wusecErr := os.Unsetenv("WATCHDOG_USEC") + wpidErr := os.Unsetenv("WATCHDOG_PID") + if wusecErr != nil { + return 0, wusecErr + } + if wpidErr != nil { + return 0, wpidErr + } + } + + if wusec == "" { + return 0, nil + } + s, err := strconv.Atoi(wusec) + if err != nil { + return 0, fmt.Errorf("error converting WATCHDOG_USEC: %s", err) + } + if s <= 0 { + return 0, fmt.Errorf("error WATCHDOG_USEC must be a positive number") + } + interval := time.Duration(s) * time.Microsecond + + if wpid == "" { + return interval, nil + } + p, err := strconv.Atoi(wpid) + if err != nil { + return 0, fmt.Errorf("error converting WATCHDOG_PID: %s", err) + } + if os.Getpid() != p { + return 0, nil + } + + return interval, nil +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,261 @@ +// Copyright 2015 CoreOS, Inc. +// +// 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. + +// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ +package dbus + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "strconv" + "strings" + "sync" + + "github.com/godbus/dbus/v5" +) + +const ( + alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` + num = `0123456789` + alphanum = alpha + num + signalBuffer = 100 +) + +// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped +func needsEscape(i int, b byte) bool { + // Escape everything that is not a-z-A-Z-0-9 + // Also escape 0-9 if it's the first character + return strings.IndexByte(alphanum, b) == -1 || + (i == 0 && strings.IndexByte(num, b) != -1) +} + +// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the +// rules that systemd uses for serializing special characters. +func PathBusEscape(path string) string { + // Special case the empty string + if len(path) == 0 { + return "_" + } + n := []byte{} + for i := 0; i < len(path); i++ { + c := path[i] + if needsEscape(i, c) { + e := fmt.Sprintf("_%x", c) + n = append(n, []byte(e)...) + } else { + n = append(n, c) + } + } + return string(n) +} + +// pathBusUnescape is the inverse of PathBusEscape. +func pathBusUnescape(path string) string { + if path == "_" { + return "" + } + n := []byte{} + for i := 0; i < len(path); i++ { + c := path[i] + if c == '_' && i+2 < len(path) { + res, err := hex.DecodeString(path[i+1 : i+3]) + if err == nil { + n = append(n, res...) + } + i += 2 + } else { + n = append(n, c) + } + } + return string(n) +} + +// Conn is a connection to systemd's dbus endpoint. +type Conn struct { + // sysconn/sysobj are only used to call dbus methods + sysconn *dbus.Conn + sysobj dbus.BusObject + + // sigconn/sigobj are only used to receive dbus signals + sigconn *dbus.Conn + sigobj dbus.BusObject + + jobListener struct { + jobs map[dbus.ObjectPath]chan<- string + sync.Mutex + } + subStateSubscriber struct { + updateCh chan<- *SubStateUpdate + errCh chan<- error + sync.Mutex + ignore map[dbus.ObjectPath]int64 + cleanIgnore int64 + } + propertiesSubscriber struct { + updateCh chan<- *PropertiesUpdate + errCh chan<- error + sync.Mutex + } +} + +// Deprecated: use NewWithContext instead. +func New() (*Conn, error) { + return NewWithContext(context.Background()) +} + +// NewWithContext establishes a connection to any available bus and authenticates. +// Callers should call Close() when done with the connection. +func NewWithContext(ctx context.Context) (*Conn, error) { + conn, err := NewSystemConnectionContext(ctx) + if err != nil && os.Geteuid() == 0 { + return NewSystemdConnectionContext(ctx) + } + return conn, err +} + +// Deprecated: use NewSystemConnectionContext instead. +func NewSystemConnection() (*Conn, error) { + return NewSystemConnectionContext(context.Background()) +} + +// NewSystemConnectionContext establishes a connection to the system bus and authenticates. +// Callers should call Close() when done with the connection. +func NewSystemConnectionContext(ctx context.Context) (*Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate) + }) +} + +// Deprecated: use NewUserConnectionContext instead. +func NewUserConnection() (*Conn, error) { + return NewUserConnectionContext(context.Background()) +} + +// NewUserConnectionContext establishes a connection to the session bus and +// authenticates. This can be used to connect to systemd user instances. +// Callers should call Close() when done with the connection. +func NewUserConnectionContext(ctx context.Context) (*Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate) + }) +} + +// Deprecated: use NewSystemdConnectionContext instead. +func NewSystemdConnection() (*Conn, error) { + return NewSystemdConnectionContext(context.Background()) +} + +// NewSystemdConnectionContext establishes a private, direct connection to systemd. +// This can be used for communicating with systemd without a dbus daemon. +// Callers should call Close() when done with the connection. +func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { + // We skip Hello when talking directly to systemd. + return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) { + return dbus.Dial("unix:path=/run/systemd/private", opts...) + }) + }) +} + +// Close closes an established connection. +func (c *Conn) Close() { + c.sysconn.Close() + c.sigconn.Close() +} + +// NewConnection establishes a connection to a bus using a caller-supplied function. +// This allows connecting to remote buses through a user-supplied mechanism. +// The supplied function may be called multiple times, and should return independent connections. +// The returned connection must be fully initialised: the org.freedesktop.DBus.Hello call must have succeeded, +// and any authentication should be handled by the function. +func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { + sysconn, err := dialBus() + if err != nil { + return nil, err + } + + sigconn, err := dialBus() + if err != nil { + sysconn.Close() + return nil, err + } + + c := &Conn{ + sysconn: sysconn, + sysobj: systemdObject(sysconn), + sigconn: sigconn, + sigobj: systemdObject(sigconn), + } + + c.subStateSubscriber.ignore = make(map[dbus.ObjectPath]int64) + c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) + + // Setup the listeners on jobs so that we can get completions + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") + + c.dispatch() + return c, nil +} + +// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager +// interface. The value is returned in its string representation, as defined at +// https://developer.gnome.org/glib/unstable/gvariant-text.html. +func (c *Conn) GetManagerProperty(prop string) (string, error) { + variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop) + if err != nil { + return "", err + } + return variant.String(), nil +} + +func dbusAuthConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus(dbus.WithContext(ctx)) + if err != nil { + return nil, err + } + + // Only use EXTERNAL method, and hardcode the uid (not username) + // to avoid a username lookup (which requires a dynamically linked + // libc) + methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))} + + err = conn.Auth(methods) + if err != nil { + conn.Close() + return nil, err + } + + return conn, nil +} + +func dbusAuthHelloConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := dbusAuthConnection(ctx, createBus) + if err != nil { + return nil, err + } + + if err = conn.Hello(); err != nil { + conn.Close() + return nil, err + } + + return conn, nil +} + +func systemdObject(conn *dbus.Conn) dbus.BusObject { + return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,830 @@ +// Copyright 2015, 2018 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbus + +import ( + "context" + "errors" + "fmt" + "path" + "strconv" + + "github.com/godbus/dbus/v5" +) + +// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API +type Who string + +const ( + // All sends the signal to all processes in the unit + All Who = "all" + // Main sends the signal to the main process of the unit + Main Who = "main" + // Control sends the signal to the control process of the unit + Control Who = "control" +) + +func (c *Conn) jobComplete(signal *dbus.Signal) { + var id uint32 + var job dbus.ObjectPath + var unit string + var result string + dbus.Store(signal.Body, &id, &job, &unit, &result) + c.jobListener.Lock() + out, ok := c.jobListener.jobs[job] + if ok { + out <- result + delete(c.jobListener.jobs, job) + } + c.jobListener.Unlock() +} + +func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) { + if ch != nil { + c.jobListener.Lock() + defer c.jobListener.Unlock() + } + + var p dbus.ObjectPath + err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p) + if err != nil { + return 0, err + } + + if ch != nil { + c.jobListener.jobs[p] = ch + } + + // ignore error since 0 is fine if conversion fails + jobID, _ := strconv.Atoi(path.Base(string(p))) + + return jobID, nil +} + +// Deprecated: use StartUnitContext instead. +func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.StartUnitContext(context.Background(), name, mode, ch) +} + +// StartUnitContext enqueues a start job and depending jobs, if any (unless otherwise +// specified by the mode string). +// +// Takes the unit to activate, plus a mode string. The mode needs to be one of +// replace, fail, isolate, ignore-dependencies, ignore-requirements. If +// "replace" the call will start the unit and its dependencies, possibly +// replacing already queued jobs that conflict with this. If "fail" the call +// will start the unit and its dependencies, but will fail if this would change +// an already queued job. If "isolate" the call will start the unit in question +// and terminate all units that aren't dependencies of it. If +// "ignore-dependencies" it will start a unit but ignore all its dependencies. +// If "ignore-requirements" it will start a unit but only ignore the +// requirement dependencies. It is not recommended to make use of the latter +// two options. +// +// If the provided channel is non-nil, a result string will be sent to it upon +// job completion: one of done, canceled, timeout, failed, dependency, skipped. +// done indicates successful execution of a job. canceled indicates that a job +// has been canceled before it finished execution. timeout indicates that the +// job timeout was reached. failed indicates that the job failed. dependency +// indicates that a job this job has been depending on failed and the job hence +// has been removed too. skipped indicates that a job was skipped because it +// didn't apply to the units current state. +// +// If no error occurs, the ID of the underlying systemd job will be returned. There +// does exist the possibility for no error to be returned, but for the returned job +// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint +// should not be considered authoritative. +// +// If an error does occur, it will be returned to the user alongside a job ID of 0. +func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) +} + +// Deprecated: use StopUnitContext instead. +func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { + return c.StopUnitContext(context.Background(), name, mode, ch) +} + +// StopUnitContext is similar to StartUnitContext, but stops the specified unit +// rather than starting it. +func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) +} + +// Deprecated: use ReloadUnitContext instead. +func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { + return c.ReloadUnitContext(context.Background(), name, mode, ch) +} + +// ReloadUnitContext reloads a unit. Reloading is done only if the unit +// is already running, and fails otherwise. +func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) +} + +// Deprecated: use RestartUnitContext instead. +func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.RestartUnitContext(context.Background(), name, mode, ch) +} + +// RestartUnitContext restarts a service. If a service is restarted that isn't +// running it will be started. +func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) +} + +// Deprecated: use TryRestartUnitContext instead. +func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.TryRestartUnitContext(context.Background(), name, mode, ch) +} + +// TryRestartUnitContext is like RestartUnitContext, except that a service that +// isn't running is not affected by the restart. +func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) +} + +// Deprecated: use ReloadOrRestartUnitContext instead. +func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch) +} + +// ReloadOrRestartUnitContext attempts a reload if the unit supports it and use +// a restart otherwise. +func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) +} + +// Deprecated: use ReloadOrTryRestartUnitContext instead. +func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch) +} + +// ReloadOrTryRestartUnitContext attempts a reload if the unit supports it, +// and use a "Try" flavored restart otherwise. +func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) +} + +// Deprecated: use StartTransientUnitContext instead. +func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { + return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch) +} + +// StartTransientUnitContext may be used to create and start a transient unit, which +// will be released as soon as it is not running or referenced anymore or the +// system is rebooted. name is the unit name including suffix, and must be +// unique. mode is the same as in StartUnitContext, properties contains properties +// of the unit. +func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) { + return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) +} + +// Deprecated: use KillUnitContext instead. +func (c *Conn) KillUnit(name string, signal int32) { + c.KillUnitContext(context.Background(), name, signal) +} + +// KillUnitContext takes the unit name and a UNIX signal number to send. +// All of the unit's processes are killed. +func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) { + c.KillUnitWithTarget(ctx, name, All, signal) +} + +// KillUnitWithTarget is like KillUnitContext, but allows you to specify which +// process in the unit to send the signal to. +func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store() +} + +// Deprecated: use ResetFailedUnitContext instead. +func (c *Conn) ResetFailedUnit(name string) error { + return c.ResetFailedUnitContext(context.Background(), name) +} + +// ResetFailedUnitContext resets the "failed" state of a specific unit. +func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() +} + +// Deprecated: use SystemStateContext instead. +func (c *Conn) SystemState() (*Property, error) { + return c.SystemStateContext(context.Background()) +} + +// SystemStateContext returns the systemd state. Equivalent to +// systemctl is-system-running. +func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { + var err error + var prop dbus.Variant + + obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) + if err != nil { + return nil, err + } + + return &Property{Name: "SystemState", Value: prop}, nil +} + +// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface. +func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { + var err error + var props map[string]dbus.Variant + + if !path.IsValid() { + return nil, fmt.Errorf("invalid unit name: %v", path) + } + + obj := c.sysconn.Object("org.freedesktop.systemd1", path) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) + if err != nil { + return nil, err + } + + out := make(map[string]interface{}, len(props)) + for k, v := range props { + out[k] = v.Value() + } + + return out, nil +} + +// Deprecated: use GetUnitPropertiesContext instead. +func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { + return c.GetUnitPropertiesContext(context.Background(), unit) +} + +// GetUnitPropertiesContext takes the (unescaped) unit name and returns all of +// its dbus object properties. +func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { + path := unitPath(unit) + return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") +} + +// Deprecated: use GetUnitPathPropertiesContext instead. +func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { + return c.GetUnitPathPropertiesContext(context.Background(), path) +} + +// GetUnitPathPropertiesContext takes the (escaped) unit path and returns all +// of its dbus object properties. +func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) { + return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") +} + +// Deprecated: use GetAllPropertiesContext instead. +func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { + return c.GetAllPropertiesContext(context.Background(), unit) +} + +// GetAllPropertiesContext takes the (unescaped) unit name and returns all of +// its dbus object properties. +func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { + path := unitPath(unit) + return c.getProperties(ctx, path, "") +} + +func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) { + var err error + var prop dbus.Variant + + path := unitPath(unit) + if !path.IsValid() { + return nil, errors.New("invalid unit name: " + unit) + } + + obj := c.sysconn.Object("org.freedesktop.systemd1", path) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) + if err != nil { + return nil, err + } + + return &Property{Name: propertyName, Value: prop}, nil +} + +// Deprecated: use GetUnitPropertyContext instead. +func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { + return c.GetUnitPropertyContext(context.Background(), unit, propertyName) +} + +// GetUnitPropertyContext takes an (unescaped) unit name, and a property name, +// and returns the property value. +func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) { + return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName) +} + +// Deprecated: use GetServicePropertyContext instead. +func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { + return c.GetServicePropertyContext(context.Background(), service, propertyName) +} + +// GetServiceProperty returns property for given service name and property name. +func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) { + return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName) +} + +// Deprecated: use GetUnitTypePropertiesContext instead. +func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { + return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType) +} + +// GetUnitTypePropertiesContext returns the extra properties for a unit, specific to the unit type. +// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope. +// Returns "dbus.Error: Unknown interface" error if the unitType is not the correct type of the unit. +func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) { + path := unitPath(unit) + return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType) +} + +// Deprecated: use SetUnitPropertiesContext instead. +func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { + return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...) +} + +// SetUnitPropertiesContext may be used to modify certain unit properties at runtime. +// Not all properties may be changed at runtime, but many resource management +// settings (primarily those in systemd.cgroup(5)) may. The changes are applied +// instantly, and stored on disk for future boots, unless runtime is true, in which +// case the settings only apply until the next reboot. name is the name of the unit +// to modify. properties are the settings to set, encoded as an array of property +// name and value pairs. +func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() +} + +// Deprecated: use GetUnitTypePropertyContext instead. +func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { + return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName) +} + +// GetUnitTypePropertyContext takes a property name, a unit name, and a unit type, +// and returns a property value. For valid values of unitType, see GetUnitTypePropertiesContext. +func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) { + return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName) +} + +type UnitStatus struct { + Name string // The primary unit name as string + Description string // The human readable description string + LoadState string // The load state (i.e. whether the unit file has been loaded successfully) + ActiveState string // The active state (i.e. whether the unit is currently started or not) + SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not) + Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string. + Path dbus.ObjectPath // The unit object path + JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise + JobType string // The job type as string + JobPath dbus.ObjectPath // The job object path +} + +type storeFunc func(retvalues ...interface{}) error + +func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { + result := make([][]interface{}, 0) + err := f(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + status := make([]UnitStatus, len(result)) + statusInterface := make([]interface{}, len(status)) + for i := range status { + statusInterface[i] = &status[i] + } + + err = dbus.Store(resultInterface, statusInterface...) + if err != nil { + return nil, err + } + + return status, nil +} + +// Deprecated: use ListUnitsContext instead. +func (c *Conn) ListUnits() ([]UnitStatus, error) { + return c.ListUnitsContext(context.Background()) +} + +// ListUnitsContext returns an array with all currently loaded units. Note that +// units may be known by multiple names at the same time, and hence there might +// be more unit names loaded than actual units behind them. +// Also note that a unit is only loaded if it is active and/or enabled. +// Units that are both disabled and inactive will thus not be returned. +func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) +} + +// Deprecated: use ListUnitsFilteredContext instead. +func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { + return c.ListUnitsFilteredContext(context.Background(), states) +} + +// ListUnitsFilteredContext returns an array with units filtered by state. +// It takes a list of units' statuses to filter. +func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) +} + +// Deprecated: use ListUnitsByPatternsContext instead. +func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { + return c.ListUnitsByPatternsContext(context.Background(), states, patterns) +} + +// ListUnitsByPatternsContext returns an array with units. +// It takes a list of units' statuses and names to filter. +// Note that units may be known by multiple names at the same time, +// and hence there might be more unit names loaded than actual units behind them. +func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) +} + +// Deprecated: use ListUnitsByNamesContext instead. +func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { + return c.ListUnitsByNamesContext(context.Background(), units) +} + +// ListUnitsByNamesContext returns an array with units. It takes a list of units' +// names and returns an UnitStatus array. Comparing to ListUnitsByPatternsContext +// method, this method returns statuses even for inactive or non-existing +// units. Input array should contain exact unit names, but not patterns. +// +// Requires systemd v230 or higher. +func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) +} + +type UnitFile struct { + Path string + Type string +} + +func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { + result := make([][]interface{}, 0) + err := f(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + files := make([]UnitFile, len(result)) + fileInterface := make([]interface{}, len(files)) + for i := range files { + fileInterface[i] = &files[i] + } + + err = dbus.Store(resultInterface, fileInterface...) + if err != nil { + return nil, err + } + + return files, nil +} + +// Deprecated: use ListUnitFilesContext instead. +func (c *Conn) ListUnitFiles() ([]UnitFile, error) { + return c.ListUnitFilesContext(context.Background()) +} + +// ListUnitFiles returns an array of all available units on disk. +func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) +} + +// Deprecated: use ListUnitFilesByPatternsContext instead. +func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { + return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns) +} + +// ListUnitFilesByPatternsContext returns an array of all available units on disk matched the patterns. +func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) +} + +type LinkUnitFileChange EnableUnitFileChange + +// Deprecated: use LinkUnitFilesContext instead. +func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { + return c.LinkUnitFilesContext(context.Background(), files, runtime, force) +} + +// LinkUnitFilesContext links unit files (that are located outside of the +// usual unit search paths) into the unit search path. +// +// It takes a list of absolute paths to unit files to link and two +// booleans. +// +// The first boolean controls whether the unit shall be +// enabled for runtime only (true, /run), or persistently (false, +// /etc). +// +// The second controls whether symlinks pointing to other units shall +// be replaced if necessary. +// +// This call returns a list of the changes made. The list consists of +// structures with three strings: the type of the change (one of symlink +// or unlink), the file name of the symlink and the destination of the +// symlink. +func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]LinkUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +// Deprecated: use EnableUnitFilesContext instead. +func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { + return c.EnableUnitFilesContext(context.Background(), files, runtime, force) +} + +// EnableUnitFilesContext may be used to enable one or more units in the system +// (by creating symlinks to them in /etc or /run). +// +// It takes a list of unit files to enable (either just file names or full +// absolute paths if the unit files are residing outside the usual unit +// search paths), and two booleans: the first controls whether the unit shall +// be enabled for runtime only (true, /run), or persistently (false, /etc). +// The second one controls whether symlinks pointing to other units shall +// be replaced if necessary. +// +// This call returns one boolean and an array with the changes made. The +// boolean signals whether the unit files contained any enablement +// information (i.e. an [Install]) section. The changes list consists of +// structures with three strings: the type of the change (one of symlink +// or unlink), the file name of the symlink and the destination of the +// symlink. +func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { + var carries_install_info bool + + result := make([][]interface{}, 0) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) + if err != nil { + return false, nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]EnableUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return false, nil, err + } + + return carries_install_info, changes, nil +} + +type EnableUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + +// Deprecated: use DisableUnitFilesContext instead. +func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { + return c.DisableUnitFilesContext(context.Background(), files, runtime) +} + +// DisableUnitFilesContext may be used to disable one or more units in the +// system (by removing symlinks to them from /etc or /run). +// +// It takes a list of unit files to disable (either just file names or full +// absolute paths if the unit files are residing outside the usual unit +// search paths), and one boolean: whether the unit was enabled for runtime +// only (true, /run), or persistently (false, /etc). +// +// This call returns an array with the changes made. The changes list +// consists of structures with three strings: the type of the change (one of +// symlink or unlink), the file name of the symlink and the destination of the +// symlink. +func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]DisableUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +type DisableUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + +// Deprecated: use MaskUnitFilesContext instead. +func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { + return c.MaskUnitFilesContext(context.Background(), files, runtime, force) +} + +// MaskUnitFilesContext masks one or more units in the system. +// +// The files argument contains a list of units to mask (either just file names +// or full absolute paths if the unit files are residing outside the usual unit +// search paths). +// +// The runtime argument is used to specify whether the unit was enabled for +// runtime only (true, /run/systemd/..), or persistently (false, +// /etc/systemd/..). +func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]MaskUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +type MaskUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + +// Deprecated: use UnmaskUnitFilesContext instead. +func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { + return c.UnmaskUnitFilesContext(context.Background(), files, runtime) +} + +// UnmaskUnitFilesContext unmasks one or more units in the system. +// +// It takes the list of unit files to mask (either just file names or full +// absolute paths if the unit files are residing outside the usual unit search +// paths), and a boolean runtime flag to specify whether the unit was enabled +// for runtime only (true, /run/systemd/..), or persistently (false, +// /etc/systemd/..). +func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]UnmaskUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +type UnmaskUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + +// Deprecated: use ReloadContext instead. +func (c *Conn) Reload() error { + return c.ReloadContext(context.Background()) +} + +// ReloadContext instructs systemd to scan for and reload unit files. This is +// an equivalent to systemctl daemon-reload. +func (c *Conn) ReloadContext(ctx context.Context) error { + return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store() +} + +func unitPath(name string) dbus.ObjectPath { + return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) +} + +// unitName returns the unescaped base element of the supplied escaped path. +func unitName(dpath dbus.ObjectPath) string { + return pathBusUnescape(path.Base(string(dpath))) +} + +// JobStatus holds a currently queued job definition. +type JobStatus struct { + Id uint32 // The numeric job id + Unit string // The primary unit name for this job + JobType string // The job type as string + Status string // The job state as string + JobPath dbus.ObjectPath // The job object path + UnitPath dbus.ObjectPath // The unit object path +} + +// Deprecated: use ListJobsContext instead. +func (c *Conn) ListJobs() ([]JobStatus, error) { + return c.ListJobsContext(context.Background()) +} + +// ListJobsContext returns an array with all currently queued jobs. +func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) { + return c.listJobsInternal(ctx) +} + +func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) { + result := make([][]interface{}, 0) + if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + status := make([]JobStatus, len(result)) + statusInterface := make([]interface{}, len(status)) + for i := range status { + statusInterface[i] = &status[i] + } + + if err := dbus.Store(resultInterface, statusInterface...); err != nil { + return nil, err + } + + return status, nil +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,237 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbus + +import ( + "github.com/godbus/dbus/v5" +) + +// From the systemd docs: +// +// The properties array of StartTransientUnit() may take many of the settings +// that may also be configured in unit files. Not all parameters are currently +// accepted though, but we plan to cover more properties with future release. +// Currently you may set the Description, Slice and all dependency types of +// units, as well as RemainAfterExit, ExecStart for service units, +// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares, +// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth, +// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit, +// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map +// directly to their counterparts in unit files and as normal D-Bus object +// properties. The exception here is the PIDs field of scope units which is +// used for construction of the scope only and specifies the initial PIDs to +// add to the scope object. + +type Property struct { + Name string + Value dbus.Variant +} + +type PropertyCollection struct { + Name string + Properties []Property +} + +type execStart struct { + Path string // the binary path to execute + Args []string // an array with all arguments to pass to the executed command, starting with argument 0 + UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly +} + +// PropExecStart sets the ExecStart service property. The first argument is a +// slice with the binary path to execute followed by the arguments to pass to +// the executed command. See +// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= +func PropExecStart(command []string, uncleanIsFailure bool) Property { + execStarts := []execStart{ + { + Path: command[0], + Args: command, + UncleanIsFailure: uncleanIsFailure, + }, + } + + return Property{ + Name: "ExecStart", + Value: dbus.MakeVariant(execStarts), + } +} + +// PropRemainAfterExit sets the RemainAfterExit service property. See +// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit= +func PropRemainAfterExit(b bool) Property { + return Property{ + Name: "RemainAfterExit", + Value: dbus.MakeVariant(b), + } +} + +// PropType sets the Type service property. See +// http://www.freedesktop.org/software/systemd/man/systemd.service.html#Type= +func PropType(t string) Property { + return Property{ + Name: "Type", + Value: dbus.MakeVariant(t), + } +} + +// PropDescription sets the Description unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description= +func PropDescription(desc string) Property { + return Property{ + Name: "Description", + Value: dbus.MakeVariant(desc), + } +} + +func propDependency(name string, units []string) Property { + return Property{ + Name: name, + Value: dbus.MakeVariant(units), + } +} + +// PropRequires sets the Requires unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires= +func PropRequires(units ...string) Property { + return propDependency("Requires", units) +} + +// PropRequiresOverridable sets the RequiresOverridable unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable= +func PropRequiresOverridable(units ...string) Property { + return propDependency("RequiresOverridable", units) +} + +// PropRequisite sets the Requisite unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite= +func PropRequisite(units ...string) Property { + return propDependency("Requisite", units) +} + +// PropRequisiteOverridable sets the RequisiteOverridable unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable= +func PropRequisiteOverridable(units ...string) Property { + return propDependency("RequisiteOverridable", units) +} + +// PropWants sets the Wants unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants= +func PropWants(units ...string) Property { + return propDependency("Wants", units) +} + +// PropBindsTo sets the BindsTo unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo= +func PropBindsTo(units ...string) Property { + return propDependency("BindsTo", units) +} + +// PropRequiredBy sets the RequiredBy unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy= +func PropRequiredBy(units ...string) Property { + return propDependency("RequiredBy", units) +} + +// PropRequiredByOverridable sets the RequiredByOverridable unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable= +func PropRequiredByOverridable(units ...string) Property { + return propDependency("RequiredByOverridable", units) +} + +// PropWantedBy sets the WantedBy unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy= +func PropWantedBy(units ...string) Property { + return propDependency("WantedBy", units) +} + +// PropBoundBy sets the BoundBy unit property. See +// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy= +func PropBoundBy(units ...string) Property { + return propDependency("BoundBy", units) +} + +// PropConflicts sets the Conflicts unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts= +func PropConflicts(units ...string) Property { + return propDependency("Conflicts", units) +} + +// PropConflictedBy sets the ConflictedBy unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy= +func PropConflictedBy(units ...string) Property { + return propDependency("ConflictedBy", units) +} + +// PropBefore sets the Before unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before= +func PropBefore(units ...string) Property { + return propDependency("Before", units) +} + +// PropAfter sets the After unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After= +func PropAfter(units ...string) Property { + return propDependency("After", units) +} + +// PropOnFailure sets the OnFailure unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure= +func PropOnFailure(units ...string) Property { + return propDependency("OnFailure", units) +} + +// PropTriggers sets the Triggers unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers= +func PropTriggers(units ...string) Property { + return propDependency("Triggers", units) +} + +// PropTriggeredBy sets the TriggeredBy unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy= +func PropTriggeredBy(units ...string) Property { + return propDependency("TriggeredBy", units) +} + +// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo= +func PropPropagatesReloadTo(units ...string) Property { + return propDependency("PropagatesReloadTo", units) +} + +// PropRequiresMountsFor sets the RequiresMountsFor unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor= +func PropRequiresMountsFor(units ...string) Property { + return propDependency("RequiresMountsFor", units) +} + +// PropSlice sets the Slice unit property. See +// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice= +func PropSlice(slice string) Property { + return Property{ + Name: "Slice", + Value: dbus.MakeVariant(slice), + } +} + +// PropPids sets the PIDs field of scope units used in the initial construction +// of the scope only and specifies the initial PIDs to add to the scope object. +// See https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#properties +func PropPids(pids ...uint32) Property { + return Property{ + Name: "PIDs", + Value: dbus.MakeVariant(pids), + } +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/set.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/set.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/set.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/set.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,47 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbus + +type set struct { + data map[string]bool +} + +func (s *set) Add(value string) { + s.data[value] = true +} + +func (s *set) Remove(value string) { + delete(s.data, value) +} + +func (s *set) Contains(value string) (exists bool) { + _, exists = s.data[value] + return +} + +func (s *set) Length() int { + return len(s.data) +} + +func (s *set) Values() (values []string) { + for val := range s.data { + values = append(values, val) + } + return +} + +func newSet() *set { + return &set{make(map[string]bool)} +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,333 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbus + +import ( + "errors" + "log" + "time" + + "github.com/godbus/dbus/v5" +) + +const ( + cleanIgnoreInterval = int64(10 * time.Second) + ignoreInterval = int64(30 * time.Millisecond) +) + +// Subscribe sets up this connection to subscribe to all systemd dbus events. +// This is required before calling SubscribeUnits. When the connection closes +// systemd will automatically stop sending signals so there is no need to +// explicitly call Unsubscribe(). +func (c *Conn) Subscribe() error { + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") + + return c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() +} + +// Unsubscribe this connection from systemd dbus events. +func (c *Conn) Unsubscribe() error { + return c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() +} + +func (c *Conn) dispatch() { + ch := make(chan *dbus.Signal, signalBuffer) + + c.sigconn.Signal(ch) + + go func() { + for { + signal, ok := <-ch + if !ok { + return + } + + if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" { + c.jobComplete(signal) + } + + if c.subStateSubscriber.updateCh == nil && + c.propertiesSubscriber.updateCh == nil { + continue + } + + var unitPath dbus.ObjectPath + switch signal.Name { + case "org.freedesktop.systemd1.Manager.JobRemoved": + unitName := signal.Body[2].(string) + c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) + case "org.freedesktop.systemd1.Manager.UnitNew": + unitPath = signal.Body[1].(dbus.ObjectPath) + case "org.freedesktop.DBus.Properties.PropertiesChanged": + if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { + unitPath = signal.Path + + if len(signal.Body) >= 2 { + if changed, ok := signal.Body[1].(map[string]dbus.Variant); ok { + c.sendPropertiesUpdate(unitPath, changed) + } + } + } + } + + if unitPath == dbus.ObjectPath("") { + continue + } + + c.sendSubStateUpdate(unitPath) + } + }() +} + +// SubscribeUnits returns two unbuffered channels which will receive all changed units every +// interval. Deleted units are sent as nil. +func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { + return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) +} + +// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer +// size of the channels, the comparison function for detecting changes and a filter +// function for cutting down on the noise that your channel receives. +func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { + old := make(map[string]*UnitStatus) + statusChan := make(chan map[string]*UnitStatus, buffer) + errChan := make(chan error, buffer) + + go func() { + for { + timerChan := time.After(interval) + + units, err := c.ListUnits() + if err == nil { + cur := make(map[string]*UnitStatus) + for i := range units { + if filterUnit != nil && filterUnit(units[i].Name) { + continue + } + cur[units[i].Name] = &units[i] + } + + // add all new or changed units + changed := make(map[string]*UnitStatus) + for n, u := range cur { + if oldU, ok := old[n]; !ok || isChanged(oldU, u) { + changed[n] = u + } + delete(old, n) + } + + // add all deleted units + for oldN := range old { + changed[oldN] = nil + } + + old = cur + + if len(changed) != 0 { + statusChan <- changed + } + } else { + errChan <- err + } + + <-timerChan + } + }() + + return statusChan, errChan +} + +type SubStateUpdate struct { + UnitName string + SubState string +} + +// SetSubStateSubscriber writes to updateCh when any unit's substate changes. +// Although this writes to updateCh on every state change, the reported state +// may be more recent than the change that generated it (due to an unavoidable +// race in the systemd dbus interface). That is, this method provides a good +// way to keep a current view of all units' states, but is not guaranteed to +// show every state transition they go through. Furthermore, state changes +// will only be written to the channel with non-blocking writes. If updateCh +// is full, it attempts to write an error to errCh; if errCh is full, the error +// passes silently. +func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { + if c == nil { + msg := "nil receiver" + select { + case errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } + + c.subStateSubscriber.Lock() + defer c.subStateSubscriber.Unlock() + c.subStateSubscriber.updateCh = updateCh + c.subStateSubscriber.errCh = errCh +} + +func (c *Conn) sendSubStateUpdate(unitPath dbus.ObjectPath) { + c.subStateSubscriber.Lock() + defer c.subStateSubscriber.Unlock() + + if c.subStateSubscriber.updateCh == nil { + return + } + + isIgnored := c.shouldIgnore(unitPath) + defer c.cleanIgnore() + if isIgnored { + return + } + + info, err := c.GetUnitPathProperties(unitPath) + if err != nil { + select { + case c.subStateSubscriber.errCh <- err: + default: + log.Printf("full error channel while reporting: %s\n", err) + } + return + } + defer c.updateIgnore(unitPath, info) + + name, ok := info["Id"].(string) + if !ok { + msg := "failed to cast info.Id" + select { + case c.subStateSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", err) + } + return + } + substate, ok := info["SubState"].(string) + if !ok { + msg := "failed to cast info.SubState" + select { + case c.subStateSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } + + update := &SubStateUpdate{name, substate} + select { + case c.subStateSubscriber.updateCh <- update: + default: + msg := "update channel is full" + select { + case c.subStateSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } +} + +// The ignore functions work around a wart in the systemd dbus interface. +// Requesting the properties of an unloaded unit will cause systemd to send a +// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's +// properties on UnitNew (as that's the only indication of a new unit coming up +// for the first time), we would enter an infinite loop if we did not attempt +// to detect and ignore these spurious signals. The signal themselves are +// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an +// unloaded unit's signals for a short time after requesting its properties. +// This means that we will miss e.g. a transient unit being restarted +// *immediately* upon failure and also a transient unit being started +// immediately after requesting its status (with systemctl status, for example, +// because this causes a UnitNew signal to be sent which then causes us to fetch +// the properties). + +func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { + t, ok := c.subStateSubscriber.ignore[path] + return ok && t >= time.Now().UnixNano() +} + +func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { + loadState, ok := info["LoadState"].(string) + if !ok { + return + } + + // unit is unloaded - it will trigger bad systemd dbus behavior + if loadState == "not-found" { + c.subStateSubscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval + } +} + +// without this, ignore would grow unboundedly over time +func (c *Conn) cleanIgnore() { + now := time.Now().UnixNano() + if c.subStateSubscriber.cleanIgnore < now { + c.subStateSubscriber.cleanIgnore = now + cleanIgnoreInterval + + for p, t := range c.subStateSubscriber.ignore { + if t < now { + delete(c.subStateSubscriber.ignore, p) + } + } + } +} + +// PropertiesUpdate holds a map of a unit's changed properties +type PropertiesUpdate struct { + UnitName string + Changed map[string]dbus.Variant +} + +// SetPropertiesSubscriber writes to updateCh when any unit's properties +// change. Every property change reported by systemd will be sent; that is, no +// transitions will be "missed" (as they might be with SetSubStateSubscriber). +// However, state changes will only be written to the channel with non-blocking +// writes. If updateCh is full, it attempts to write an error to errCh; if +// errCh is full, the error passes silently. +func (c *Conn) SetPropertiesSubscriber(updateCh chan<- *PropertiesUpdate, errCh chan<- error) { + c.propertiesSubscriber.Lock() + defer c.propertiesSubscriber.Unlock() + c.propertiesSubscriber.updateCh = updateCh + c.propertiesSubscriber.errCh = errCh +} + +// we don't need to worry about shouldIgnore() here because +// sendPropertiesUpdate doesn't call GetProperties() +func (c *Conn) sendPropertiesUpdate(unitPath dbus.ObjectPath, changedProps map[string]dbus.Variant) { + c.propertiesSubscriber.Lock() + defer c.propertiesSubscriber.Unlock() + + if c.propertiesSubscriber.updateCh == nil { + return + } + + update := &PropertiesUpdate{unitName(unitPath), changedProps} + + select { + case c.propertiesSubscriber.updateCh <- update: + default: + msg := "update channel is full" + select { + case c.propertiesSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,57 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dbus + +import ( + "time" +) + +// SubscriptionSet returns a subscription set which is like conn.Subscribe but +// can filter to only return events for a set of units. +type SubscriptionSet struct { + *set + conn *Conn +} + +func (s *SubscriptionSet) filter(unit string) bool { + return !s.Contains(unit) +} + +// Subscribe starts listening for dbus events for all of the units in the set. +// Returns channels identical to conn.SubscribeUnits. +func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { + // TODO: Make fully evented by using systemd 209 with properties changed values + return s.conn.SubscribeUnitsCustom(time.Second, 0, + mismatchUnitStatus, + func(unit string) bool { return s.filter(unit) }, + ) +} + +// NewSubscriptionSet returns a new subscription set. +func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { + return &SubscriptionSet{newSet(), conn} +} + +// mismatchUnitStatus returns true if the provided UnitStatus objects +// are not equivalent. false is returned if the objects are equivalent. +// Only the Name, Description and state-related fields are used in +// the comparison. +func mismatchUnitStatus(u1, u2 *UnitStatus) bool { + return u1.Name != u2.Name || + u1.Description != u2.Description || + u1.LoadState != u2.LoadState || + u1.ActiveState != u2.ActiveState || + u1.SubState != u2.SubState +} diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/LICENSE containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/LICENSE --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff -Nru containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/NOTICE containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/NOTICE --- containerd-1.2.6/vendor/github.com/coreos/go-systemd/v22/NOTICE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/coreos/go-systemd/v22/NOTICE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +CoreOS Project +Copyright 2018 CoreOS, Inc + +This product includes software developed at CoreOS, Inc. +(http://www.coreos.com/). diff -Nru containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md --- containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Brian Goff + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff -Nru containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go --- containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,14 @@ +package md2man + +import ( + "github.com/russross/blackfriday/v2" +) + +// Render converts a markdown document into a roff formatted document. +func Render(doc []byte) []byte { + renderer := NewRoffRenderer() + + return blackfriday.Run(doc, + []blackfriday.Option{blackfriday.WithRenderer(renderer), + blackfriday.WithExtensions(renderer.GetExtensions())}...) +} diff -Nru containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go --- containerd-1.2.6/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,345 @@ +package md2man + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/russross/blackfriday/v2" +) + +// roffRenderer implements the blackfriday.Renderer interface for creating +// roff format (manpages) from markdown text +type roffRenderer struct { + extensions blackfriday.Extensions + listCounters []int + firstHeader bool + defineTerm bool + listDepth int +} + +const ( + titleHeader = ".TH " + topLevelHeader = "\n\n.SH " + secondLevelHdr = "\n.SH " + otherHeader = "\n.SS " + crTag = "\n" + emphTag = "\\fI" + emphCloseTag = "\\fP" + strongTag = "\\fB" + strongCloseTag = "\\fP" + breakTag = "\n.br\n" + paraTag = "\n.PP\n" + hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n" + linkTag = "\n\\[la]" + linkCloseTag = "\\[ra]" + codespanTag = "\\fB\\fC" + codespanCloseTag = "\\fR" + codeTag = "\n.PP\n.RS\n\n.nf\n" + codeCloseTag = "\n.fi\n.RE\n" + quoteTag = "\n.PP\n.RS\n" + quoteCloseTag = "\n.RE\n" + listTag = "\n.RS\n" + listCloseTag = "\n.RE\n" + arglistTag = "\n.TP\n" + tableStart = "\n.TS\nallbox;\n" + tableEnd = ".TE\n" + tableCellStart = "T{\n" + tableCellEnd = "\nT}\n" +) + +// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents +// from markdown +func NewRoffRenderer() *roffRenderer { // nolint: golint + var extensions blackfriday.Extensions + + extensions |= blackfriday.NoIntraEmphasis + extensions |= blackfriday.Tables + extensions |= blackfriday.FencedCode + extensions |= blackfriday.SpaceHeadings + extensions |= blackfriday.Footnotes + extensions |= blackfriday.Titleblock + extensions |= blackfriday.DefinitionLists + return &roffRenderer{ + extensions: extensions, + } +} + +// GetExtensions returns the list of extensions used by this renderer implementation +func (r *roffRenderer) GetExtensions() blackfriday.Extensions { + return r.extensions +} + +// RenderHeader handles outputting the header at document start +func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) { + // disable hyphenation + out(w, ".nh\n") +} + +// RenderFooter handles outputting the footer at the document end; the roff +// renderer has no footer information +func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) { +} + +// RenderNode is called for each node in a markdown document; based on the node +// type the equivalent roff output is sent to the writer +func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + + var walkAction = blackfriday.GoToNext + + switch node.Type { + case blackfriday.Text: + r.handleText(w, node, entering) + case blackfriday.Softbreak: + out(w, crTag) + case blackfriday.Hardbreak: + out(w, breakTag) + case blackfriday.Emph: + if entering { + out(w, emphTag) + } else { + out(w, emphCloseTag) + } + case blackfriday.Strong: + if entering { + out(w, strongTag) + } else { + out(w, strongCloseTag) + } + case blackfriday.Link: + if !entering { + out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag) + } + case blackfriday.Image: + // ignore images + walkAction = blackfriday.SkipChildren + case blackfriday.Code: + out(w, codespanTag) + escapeSpecialChars(w, node.Literal) + out(w, codespanCloseTag) + case blackfriday.Document: + break + case blackfriday.Paragraph: + // roff .PP markers break lists + if r.listDepth > 0 { + return blackfriday.GoToNext + } + if entering { + out(w, paraTag) + } else { + out(w, crTag) + } + case blackfriday.BlockQuote: + if entering { + out(w, quoteTag) + } else { + out(w, quoteCloseTag) + } + case blackfriday.Heading: + r.handleHeading(w, node, entering) + case blackfriday.HorizontalRule: + out(w, hruleTag) + case blackfriday.List: + r.handleList(w, node, entering) + case blackfriday.Item: + r.handleItem(w, node, entering) + case blackfriday.CodeBlock: + out(w, codeTag) + escapeSpecialChars(w, node.Literal) + out(w, codeCloseTag) + case blackfriday.Table: + r.handleTable(w, node, entering) + case blackfriday.TableCell: + r.handleTableCell(w, node, entering) + case blackfriday.TableHead: + case blackfriday.TableBody: + case blackfriday.TableRow: + // no action as cell entries do all the nroff formatting + return blackfriday.GoToNext + default: + fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String()) + } + return walkAction +} + +func (r *roffRenderer) handleText(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + // handle special roff table cell text encapsulation + if node.Parent.Type == blackfriday.TableCell { + if len(node.Literal) > 30 { + start = tableCellStart + end = tableCellEnd + } else { + // end rows that aren't terminated by "tableCellEnd" with a cr if end of row + if node.Parent.Next == nil && !node.Parent.IsHeader { + end = crTag + } + } + } + out(w, start) + escapeSpecialChars(w, node.Literal) + out(w, end) +} + +func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + switch node.Level { + case 1: + if !r.firstHeader { + out(w, titleHeader) + r.firstHeader = true + break + } + out(w, topLevelHeader) + case 2: + out(w, secondLevelHdr) + default: + out(w, otherHeader) + } + } +} + +func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) { + openTag := listTag + closeTag := listCloseTag + if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // tags for definition lists handled within Item node + openTag = "" + closeTag = "" + } + if entering { + r.listDepth++ + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = append(r.listCounters, 1) + } + out(w, openTag) + } else { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = r.listCounters[:len(r.listCounters)-1] + } + out(w, closeTag) + r.listDepth-- + } +} + +func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1])) + r.listCounters[len(r.listCounters)-1]++ + } else if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // state machine for handling terms and following definitions + // since blackfriday does not distinguish them properly, nor + // does it seperate them into separate lists as it should + if !r.defineTerm { + out(w, arglistTag) + r.defineTerm = true + } else { + r.defineTerm = false + } + } else { + out(w, ".IP \\(bu 2\n") + } + } else { + out(w, "\n") + } +} + +func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + out(w, tableStart) + //call walker to count cells (and rows?) so format section can be produced + columns := countColumns(node) + out(w, strings.Repeat("l ", columns)+"\n") + out(w, strings.Repeat("l ", columns)+".\n") + } else { + out(w, tableEnd) + } +} + +func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + if node.IsHeader { + start = codespanTag + end = codespanCloseTag + } + if entering { + if node.Prev != nil && node.Prev.Type == blackfriday.TableCell { + out(w, "\t"+start) + } else { + out(w, start) + } + } else { + // need to carriage return if we are at the end of the header row + if node.IsHeader && node.Next == nil { + end = end + crTag + } + out(w, end) + } +} + +// because roff format requires knowing the column count before outputting any table +// data we need to walk a table tree and count the columns +func countColumns(node *blackfriday.Node) int { + var columns int + + node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + switch node.Type { + case blackfriday.TableRow: + if !entering { + return blackfriday.Terminate + } + case blackfriday.TableCell: + if entering { + columns++ + } + default: + } + return blackfriday.GoToNext + }) + return columns +} + +func out(w io.Writer, output string) { + io.WriteString(w, output) // nolint: errcheck +} + +func needsBackslash(c byte) bool { + for _, r := range []byte("-_&\\~") { + if c == r { + return true + } + } + return false +} + +func escapeSpecialChars(w io.Writer, text []byte) { + for i := 0; i < len(text); i++ { + // escape initial apostrophe or period + if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { + out(w, "\\&") + } + + // directly copy normal characters + org := i + + for i < len(text) && !needsBackslash(text[i]) { + i++ + } + if i > org { + w.Write(text[org:i]) // nolint: errcheck + } + + // escape a character + if i >= len(text) { + break + } + + w.Write([]byte{'\\', text[i]}) // nolint: errcheck + } +} diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/LICENSE containerd-1.5.9/vendor/github.com/davecgh/go-spew/LICENSE --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -2,7 +2,7 @@ Copyright (c) 2012-2016 Dave Collins -Permission to use, copy, modify, and distribute this software for any +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/README.md containerd-1.5.9/vendor/github.com/davecgh/go-spew/README.md --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -go-spew -======= - -[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)] -(https://travis-ci.org/davecgh/go-spew) [![ISC License] -(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status] -(https://img.shields.io/coveralls/davecgh/go-spew.svg)] -(https://coveralls.io/r/davecgh/go-spew?branch=master) - - -Go-spew implements a deep pretty printer for Go data structures to aid in -debugging. A comprehensive suite of tests with 100% test coverage is provided -to ensure proper functionality. See `test_coverage.txt` for the gocov coverage -report. Go-spew is licensed under the liberal ISC license, so it may be used in -open source or commercial projects. - -If you're interested in reading about how this package came to life and some -of the challenges involved in providing a deep pretty printer, there is a blog -post about it -[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/). - -## Documentation - -[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] -(http://godoc.org/github.com/davecgh/go-spew/spew) - -Full `go doc` style documentation for the project can be viewed online without -installing this package by using the excellent GoDoc site here: -http://godoc.org/github.com/davecgh/go-spew/spew - -You can also view the documentation locally once the package is installed with -the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to -http://localhost:6060/pkg/github.com/davecgh/go-spew/spew - -## Installation - -```bash -$ go get -u github.com/davecgh/go-spew/spew -``` - -## Quick Start - -Add this import line to the file you're working in: - -```Go -import "github.com/davecgh/go-spew/spew" -``` - -To dump a variable with full newlines, indentation, type, and pointer -information use Dump, Fdump, or Sdump: - -```Go -spew.Dump(myVar1, myVar2, ...) -spew.Fdump(someWriter, myVar1, myVar2, ...) -str := spew.Sdump(myVar1, myVar2, ...) -``` - -Alternatively, if you would prefer to use format strings with a compacted inline -printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most -compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types -and pointer addresses): - -```Go -spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) -spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) -spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) -spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) -``` - -## Debugging a Web Application Example - -Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production. - -```Go -package main - -import ( - "fmt" - "html" - "net/http" - - "github.com/davecgh/go-spew/spew" -) - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html") - fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:]) - fmt.Fprintf(w, "") -} - -func main() { - http.HandleFunc("/", handler) - http.ListenAndServe(":8080", nil) -} -``` - -## Sample Dump Output - -``` -(main.Foo) { - unexportedField: (*main.Bar)(0xf84002e210)({ - flag: (main.Flag) flagTwo, - data: (uintptr) - }), - ExportedField: (map[interface {}]interface {}) { - (string) "one": (bool) true - } -} -([]uint8) { - 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - 00000020 31 32 |12| -} -``` - -## Sample Formatter Output - -Double pointer to a uint8: -``` - %v: <**>5 - %+v: <**>(0xf8400420d0->0xf8400420c8)5 - %#v: (**uint8)5 - %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 -``` - -Pointer to circular struct with a uint8 field and a pointer to itself: -``` - %v: <*>{1 <*>} - %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} - %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} - %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} -``` - -## Configuration Options - -Configuration of spew is handled by fields in the ConfigState type. For -convenience, all of the top-level functions use a global state available via the -spew.Config global. - -It is also possible to create a ConfigState instance that provides methods -equivalent to the top-level functions. This allows concurrent configuration -options. See the ConfigState documentation for more details. - -``` -* Indent - String to use for each indentation level for Dump functions. - It is a single space by default. A popular alternative is "\t". - -* MaxDepth - Maximum number of levels to descend into nested data structures. - There is no limit by default. - -* DisableMethods - Disables invocation of error and Stringer interface methods. - Method invocation is enabled by default. - -* DisablePointerMethods - Disables invocation of error and Stringer interface methods on types - which only accept pointer receivers from non-pointer variables. This option - relies on access to the unsafe package, so it will not have any effect when - running in environments without access to the unsafe package such as Google - App Engine or with the "safe" build tag specified. - Pointer method invocation is enabled by default. - -* DisablePointerAddresses - DisablePointerAddresses specifies whether to disable the printing of - pointer addresses. This is useful when diffing data structures in tests. - -* DisableCapacities - DisableCapacities specifies whether to disable the printing of capacities - for arrays, slices, maps and channels. This is useful when diffing data - structures in tests. - -* ContinueOnMethod - Enables recursion into types after invoking error and Stringer interface - methods. Recursion after method invocation is disabled by default. - -* SortKeys - Specifies map keys should be sorted before being printed. Use - this to have a more deterministic, diffable output. Note that - only native types (bool, int, uint, floats, uintptr and string) - and types which implement error or Stringer interfaces are supported, - with other types sorted according to the reflect.Value.String() output - which guarantees display stability. Natural map order is used by - default. - -* SpewKeys - SpewKeys specifies that, as a last resort attempt, map keys should be - spewed to strings and sorted by those strings. This is only considered - if SortKeys is true. - -``` - -## Unsafe Package Dependency - -This package relies on the unsafe package to perform some of the more advanced -features, however it also supports a "limited" mode which allows it to work in -environments where the unsafe package is not available. By default, it will -operate in this mode on Google App Engine and when compiled with GopherJS. The -"safe" build tag may also be specified to force the package to build without -using the unsafe package. - -## License - -Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/bypass.go containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/bypass.go --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/bypass.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/bypass.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,7 +16,9 @@ // when the code is not running on Google App Engine, compiled by GopherJS, and // "-tags safe" is not added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. -// +build !js,!appengine,!safe,!disableunsafe +// Go versions prior to 1.4 are disabled because they use a different layout +// for interfaces which make the implementation of unsafeReflectValue more complex. +// +build !js,!appengine,!safe,!disableunsafe,go1.4 package spew @@ -34,80 +36,49 @@ ptrSize = unsafe.Sizeof((*byte)(nil)) ) +type flag uintptr + var ( - // offsetPtr, offsetScalar, and offsetFlag are the offsets for the - // internal reflect.Value fields. These values are valid before golang - // commit ecccf07e7f9d which changed the format. The are also valid - // after commit 82f48826c6c7 which changed the format again to mirror - // the original format. Code in the init function updates these offsets - // as necessary. - offsetPtr = uintptr(ptrSize) - offsetScalar = uintptr(0) - offsetFlag = uintptr(ptrSize * 2) - - // flagKindWidth and flagKindShift indicate various bits that the - // reflect package uses internally to track kind information. - // - // flagRO indicates whether or not the value field of a reflect.Value is - // read-only. - // - // flagIndir indicates whether the value field of a reflect.Value is - // the actual data or a pointer to the data. - // - // These values are valid before golang commit 90a7c3c86944 which - // changed their positions. Code in the init function updates these - // flags as necessary. - flagKindWidth = uintptr(5) - flagKindShift = uintptr(flagKindWidth - 1) - flagRO = uintptr(1 << 0) - flagIndir = uintptr(1 << 1) + // flagRO indicates whether the value field of a reflect.Value + // is read-only. + flagRO flag + + // flagAddr indicates whether the address of the reflect.Value's + // value may be taken. + flagAddr flag ) -func init() { - // Older versions of reflect.Value stored small integers directly in the - // ptr field (which is named val in the older versions). Versions - // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named - // scalar for this purpose which unfortunately came before the flag - // field, so the offset of the flag field is different for those - // versions. - // - // This code constructs a new reflect.Value from a known small integer - // and checks if the size of the reflect.Value struct indicates it has - // the scalar field. When it does, the offsets are updated accordingly. - vv := reflect.ValueOf(0xf00) - if unsafe.Sizeof(vv) == (ptrSize * 4) { - offsetScalar = ptrSize * 2 - offsetFlag = ptrSize * 3 - } - - // Commit 90a7c3c86944 changed the flag positions such that the low - // order bits are the kind. This code extracts the kind from the flags - // field and ensures it's the correct type. When it's not, the flag - // order has been changed to the newer format, so the flags are updated - // accordingly. - upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) - upfv := *(*uintptr)(upf) - flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { - flagKindShift = 0 - flagRO = 1 << 5 - flagIndir = 1 << 6 - - // Commit adf9b30e5594 modified the flags to separate the - // flagRO flag into two bits which specifies whether or not the - // field is embedded. This causes flagIndir to move over a bit - // and means that flagRO is the combination of either of the - // original flagRO bit and the new bit. - // - // This code detects the change by extracting what used to be - // the indirect bit to ensure it's set. When it's not, the flag - // order has been changed to the newer format, so the flags are - // updated accordingly. - if upfv&flagIndir == 0 { - flagRO = 3 << 5 - flagIndir = 1 << 7 - } +// flagKindMask holds the bits that make up the kind +// part of the flags field. In all the supported versions, +// it is in the lower 5 bits. +const flagKindMask = flag(0x1f) + +// Different versions of Go have used different +// bit layouts for the flags type. This table +// records the known combinations. +var okFlags = []struct { + ro, addr flag +}{{ + // From Go 1.4 to 1.5 + ro: 1 << 5, + addr: 1 << 7, +}, { + // Up to Go tip. + ro: 1<<5 | 1<<6, + addr: 1 << 8, +}} + +var flagValOffset = func() uintptr { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") } + return field.Offset +}() + +// flagField returns a pointer to the flag field of a reflect.Value. +func flagField(v *reflect.Value) *flag { + return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) } // unsafeReflectValue converts the passed reflect.Value into a one that bypasses @@ -119,34 +90,56 @@ // This allows us to check for implementations of the Stringer and error // interfaces to be used for pretty printing ordinarily unaddressable and // inaccessible values such as unexported struct fields. -func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { - indirects := 1 - vt := v.Type() - upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) - rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) - if rvf&flagIndir != 0 { - vt = reflect.PtrTo(v.Type()) - indirects++ - } else if offsetScalar != 0 { - // The value is in the scalar field when it's not one of the - // reference types. - switch vt.Kind() { - case reflect.Uintptr: - case reflect.Chan: - case reflect.Func: - case reflect.Map: - case reflect.Ptr: - case reflect.UnsafePointer: - default: - upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + - offsetScalar) - } +func unsafeReflectValue(v reflect.Value) reflect.Value { + if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { + return v } + flagFieldPtr := flagField(&v) + *flagFieldPtr &^= flagRO + *flagFieldPtr |= flagAddr + return v +} - pv := reflect.NewAt(vt, upv) - rv = pv - for i := 0; i < indirects; i++ { - rv = rv.Elem() +// Sanity checks against future reflect package changes +// to the type or semantics of the Value.flag field. +func init() { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { + panic("reflect.Value flag field has changed kind") + } + type t0 int + var t struct { + A t0 + // t0 will have flagEmbedRO set. + t0 + // a will have flagStickyRO set + a t0 + } + vA := reflect.ValueOf(t).FieldByName("A") + va := reflect.ValueOf(t).FieldByName("a") + vt0 := reflect.ValueOf(t).FieldByName("t0") + + // Infer flagRO from the difference between the flags + // for the (otherwise identical) fields in t. + flagPublic := *flagField(&vA) + flagWithRO := *flagField(&va) | *flagField(&vt0) + flagRO = flagPublic ^ flagWithRO + + // Infer flagAddr from the difference between a value + // taken from a pointer and not. + vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") + flagNoPtr := *flagField(&vA) + flagPtr := *flagField(&vPtrA) + flagAddr = flagNoPtr ^ flagPtr + + // Check that the inferred flags tally with one of the known versions. + for _, f := range okFlags { + if flagRO == f.ro && flagAddr == f.addr { + return + } } - return rv + panic("reflect.Value read-only flag has changed semantics") } diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go 2022-01-05 17:30:58.000000000 +0000 @@ -16,7 +16,7 @@ // when the code is running on Google App Engine, compiled by GopherJS, or // "-tags safe" is added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. -// +build js appengine safe disableunsafe +// +build js appengine safe disableunsafe !go1.4 package spew diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/common.go containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/common.go --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/common.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/common.go 2022-01-05 17:30:58.000000000 +0000 @@ -180,7 +180,7 @@ w.Write(closeParenBytes) } -// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' +// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' // prefix to Writer w. func printHexPtr(w io.Writer, p uintptr) { // Null pointer. diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/dump.go containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/dump.go --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/dump.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/dump.go 2022-01-05 17:30:58.000000000 +0000 @@ -35,16 +35,16 @@ // cCharRE is a regular expression that matches a cgo char. // It is used to detect character arrays to hexdump them. - cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") + cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) // cUnsignedCharRE is a regular expression that matches a cgo unsigned // char. It is used to detect unsigned character arrays to hexdump // them. - cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") + cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) // cUint8tCharRE is a regular expression that matches a cgo uint8_t. // It is used to detect uint8_t arrays to hexdump them. - cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") + cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) ) // dumpState contains information about the state of a dump operation. @@ -143,10 +143,10 @@ // Display dereferenced value. d.w.Write(openParenBytes) switch { - case nilFound == true: + case nilFound: d.w.Write(nilAngleBytes) - case cycleFound == true: + case cycleFound: d.w.Write(circularBytes) default: diff -Nru containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/format.go containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/format.go --- containerd-1.2.6/vendor/github.com/davecgh/go-spew/spew/format.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/davecgh/go-spew/spew/format.go 2022-01-05 17:30:58.000000000 +0000 @@ -182,10 +182,10 @@ // Display dereferenced value. switch { - case nilFound == true: + case nilFound: f.fs.Write(nilAngleBytes) - case cycleFound == true: + case cycleFound: f.fs.Write(circularShortBytes) default: diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/digestset/set.go containerd-1.5.9/vendor/github.com/docker/distribution/digestset/set.go --- containerd-1.2.6/vendor/github.com/docker/distribution/digestset/set.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/digestset/set.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -package digestset - -import ( - "errors" - "sort" - "strings" - "sync" - - digest "github.com/opencontainers/go-digest" -) - -var ( - // ErrDigestNotFound is used when a matching digest - // could not be found in a set. - ErrDigestNotFound = errors.New("digest not found") - - // ErrDigestAmbiguous is used when multiple digests - // are found in a set. None of the matching digests - // should be considered valid matches. - ErrDigestAmbiguous = errors.New("ambiguous digest string") -) - -// Set is used to hold a unique set of digests which -// may be easily referenced by easily referenced by a string -// representation of the digest as well as short representation. -// The uniqueness of the short representation is based on other -// digests in the set. If digests are omitted from this set, -// collisions in a larger set may not be detected, therefore it -// is important to always do short representation lookups on -// the complete set of digests. To mitigate collisions, an -// appropriately long short code should be used. -type Set struct { - mutex sync.RWMutex - entries digestEntries -} - -// NewSet creates an empty set of digests -// which may have digests added. -func NewSet() *Set { - return &Set{ - entries: digestEntries{}, - } -} - -// checkShortMatch checks whether two digests match as either whole -// values or short values. This function does not test equality, -// rather whether the second value could match against the first -// value. -func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool { - if len(hex) == len(shortHex) { - if hex != shortHex { - return false - } - if len(shortAlg) > 0 && string(alg) != shortAlg { - return false - } - } else if !strings.HasPrefix(hex, shortHex) { - return false - } else if len(shortAlg) > 0 && string(alg) != shortAlg { - return false - } - return true -} - -// Lookup looks for a digest matching the given string representation. -// If no digests could be found ErrDigestNotFound will be returned -// with an empty digest value. If multiple matches are found -// ErrDigestAmbiguous will be returned with an empty digest value. -func (dst *Set) Lookup(d string) (digest.Digest, error) { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - if len(dst.entries) == 0 { - return "", ErrDigestNotFound - } - var ( - searchFunc func(int) bool - alg digest.Algorithm - hex string - ) - dgst, err := digest.Parse(d) - if err == digest.ErrDigestInvalidFormat { - hex = d - searchFunc = func(i int) bool { - return dst.entries[i].val >= d - } - } else { - hex = dgst.Hex() - alg = dgst.Algorithm() - searchFunc = func(i int) bool { - if dst.entries[i].val == hex { - return dst.entries[i].alg >= alg - } - return dst.entries[i].val >= hex - } - } - idx := sort.Search(len(dst.entries), searchFunc) - if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) { - return "", ErrDigestNotFound - } - if dst.entries[idx].alg == alg && dst.entries[idx].val == hex { - return dst.entries[idx].digest, nil - } - if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) { - return "", ErrDigestAmbiguous - } - - return dst.entries[idx].digest, nil -} - -// Add adds the given digest to the set. An error will be returned -// if the given digest is invalid. If the digest already exists in the -// set, this operation will be a no-op. -func (dst *Set) Add(d digest.Digest) error { - if err := d.Validate(); err != nil { - return err - } - dst.mutex.Lock() - defer dst.mutex.Unlock() - entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} - searchFunc := func(i int) bool { - if dst.entries[i].val == entry.val { - return dst.entries[i].alg >= entry.alg - } - return dst.entries[i].val >= entry.val - } - idx := sort.Search(len(dst.entries), searchFunc) - if idx == len(dst.entries) { - dst.entries = append(dst.entries, entry) - return nil - } else if dst.entries[idx].digest == d { - return nil - } - - entries := append(dst.entries, nil) - copy(entries[idx+1:], entries[idx:len(entries)-1]) - entries[idx] = entry - dst.entries = entries - return nil -} - -// Remove removes the given digest from the set. An err will be -// returned if the given digest is invalid. If the digest does -// not exist in the set, this operation will be a no-op. -func (dst *Set) Remove(d digest.Digest) error { - if err := d.Validate(); err != nil { - return err - } - dst.mutex.Lock() - defer dst.mutex.Unlock() - entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} - searchFunc := func(i int) bool { - if dst.entries[i].val == entry.val { - return dst.entries[i].alg >= entry.alg - } - return dst.entries[i].val >= entry.val - } - idx := sort.Search(len(dst.entries), searchFunc) - // Not found if idx is after or value at idx is not digest - if idx == len(dst.entries) || dst.entries[idx].digest != d { - return nil - } - - entries := dst.entries - copy(entries[idx:], entries[idx+1:]) - entries = entries[:len(entries)-1] - dst.entries = entries - - return nil -} - -// All returns all the digests in the set -func (dst *Set) All() []digest.Digest { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - retValues := make([]digest.Digest, len(dst.entries)) - for i := range dst.entries { - retValues[i] = dst.entries[i].digest - } - - return retValues -} - -// ShortCodeTable returns a map of Digest to unique short codes. The -// length represents the minimum value, the maximum length may be the -// entire value of digest if uniqueness cannot be achieved without the -// full value. This function will attempt to make short codes as short -// as possible to be unique. -func ShortCodeTable(dst *Set, length int) map[digest.Digest]string { - dst.mutex.RLock() - defer dst.mutex.RUnlock() - m := make(map[digest.Digest]string, len(dst.entries)) - l := length - resetIdx := 0 - for i := 0; i < len(dst.entries); i++ { - var short string - extended := true - for extended { - extended = false - if len(dst.entries[i].val) <= l { - short = dst.entries[i].digest.String() - } else { - short = dst.entries[i].val[:l] - for j := i + 1; j < len(dst.entries); j++ { - if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) { - if j > resetIdx { - resetIdx = j - } - extended = true - } else { - break - } - } - if extended { - l++ - } - } - } - m[dst.entries[i].digest] = short - if i >= resetIdx { - l = length - } - } - return m -} - -type digestEntry struct { - alg digest.Algorithm - val string - digest digest.Digest -} - -type digestEntries []*digestEntry - -func (d digestEntries) Len() int { - return len(d) -} - -func (d digestEntries) Less(i, j int) bool { - if d[i].val != d[j].val { - return d[i].val < d[j].val - } - return d[i].alg < d[j].alg -} - -func (d digestEntries) Swap(i, j int) { - d[i], d[j] = d[j], d[i] -} diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/LICENSE containerd-1.5.9/vendor/github.com/docker/distribution/LICENSE --- containerd-1.2.6/vendor/github.com/docker/distribution/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,202 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. - diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/README.md containerd-1.5.9/vendor/github.com/docker/distribution/README.md --- containerd-1.2.6/vendor/github.com/docker/distribution/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -# Distribution - -The Docker toolset to pack, ship, store, and deliver content. - -This repository's main product is the Docker Registry 2.0 implementation -for storing and distributing Docker images. It supersedes the -[docker/docker-registry](https://github.com/docker/docker-registry) -project with a new API design, focused around security and performance. - - - -[![Circle CI](https://circleci.com/gh/docker/distribution/tree/master.svg?style=svg)](https://circleci.com/gh/docker/distribution/tree/master) -[![GoDoc](https://godoc.org/github.com/docker/distribution?status.svg)](https://godoc.org/github.com/docker/distribution) - -This repository contains the following components: - -|**Component** |Description | -|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **registry** | An implementation of the [Docker Registry HTTP API V2](docs/spec/api.md) for use with docker 1.6+. | -| **libraries** | A rich set of libraries for interacting with distribution components. Please see [godoc](https://godoc.org/github.com/docker/distribution) for details. **Note**: These libraries are **unstable**. | -| **specifications** | _Distribution_ related specifications are available in [docs/spec](docs/spec) | -| **documentation** | Docker's full documentation set is available at [docs.docker.com](https://docs.docker.com). This repository [contains the subset](docs/) related just to the registry. | - -### How does this integrate with Docker engine? - -This project should provide an implementation to a V2 API for use in the [Docker -core project](https://github.com/docker/docker). The API should be embeddable -and simplify the process of securely pulling and pushing content from `docker` -daemons. - -### What are the long term goals of the Distribution project? - -The _Distribution_ project has the further long term goal of providing a -secure tool chain for distributing content. The specifications, APIs and tools -should be as useful with Docker as they are without. - -Our goal is to design a professional grade and extensible content distribution -system that allow users to: - -* Enjoy an efficient, secured and reliable way to store, manage, package and - exchange content -* Hack/roll their own on top of healthy open-source components -* Implement their own home made solution through good specs, and solid - extensions mechanism. - -## More about Registry 2.0 - -The new registry implementation provides the following benefits: - -- faster push and pull -- new, more efficient implementation -- simplified deployment -- pluggable storage backend -- webhook notifications - -For information on upcoming functionality, please see [ROADMAP.md](ROADMAP.md). - -### Who needs to deploy a registry? - -By default, Docker users pull images from Docker's public registry instance. -[Installing Docker](https://docs.docker.com/engine/installation/) gives users this -ability. Users can also push images to a repository on Docker's public registry, -if they have a [Docker Hub](https://hub.docker.com/) account. - -For some users and even companies, this default behavior is sufficient. For -others, it is not. - -For example, users with their own software products may want to maintain a -registry for private, company images. Also, you may wish to deploy your own -image repository for images used to test or in continuous integration. For these -use cases and others, [deploying your own registry instance](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md) -may be the better choice. - -### Migration to Registry 2.0 - -For those who have previously deployed their own registry based on the Registry -1.0 implementation and wish to deploy a Registry 2.0 while retaining images, -data migration is required. A tool to assist with migration efforts has been -created. For more information see [docker/migrator](https://github.com/docker/migrator). - -## Contribute - -Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute -issues, fixes, and patches to this project. If you are contributing code, see -the instructions for [building a development environment](BUILDING.md). - -## Support - -If any issues are encountered while using the _Distribution_ project, several -avenues are available for support: - - - - - - - - - - - - - - - - - - -
- IRC - - #docker-distribution on FreeNode -
- Issue Tracker - - github.com/docker/distribution/issues -
- Google Groups - - https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution -
- Mailing List - - docker@dockerproject.org -
- - -## License - -This project is distributed under [Apache License, Version 2.0](LICENSE). diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/reference/helpers.go containerd-1.5.9/vendor/github.com/docker/distribution/reference/helpers.go --- containerd-1.2.6/vendor/github.com/docker/distribution/reference/helpers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/reference/helpers.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -package reference - -import "path" - -// IsNameOnly returns true if reference only contains a repo name. -func IsNameOnly(ref Named) bool { - if _, ok := ref.(NamedTagged); ok { - return false - } - if _, ok := ref.(Canonical); ok { - return false - } - return true -} - -// FamiliarName returns the familiar name string -// for the given named, familiarizing if needed. -func FamiliarName(ref Named) string { - if nn, ok := ref.(normalizedNamed); ok { - return nn.Familiar().Name() - } - return ref.Name() -} - -// FamiliarString returns the familiar string representation -// for the given reference, familiarizing if needed. -func FamiliarString(ref Reference) string { - if nn, ok := ref.(normalizedNamed); ok { - return nn.Familiar().String() - } - return ref.String() -} - -// FamiliarMatch reports whether ref matches the specified pattern. -// See https://godoc.org/path#Match for supported patterns. -func FamiliarMatch(pattern string, ref Reference) (bool, error) { - matched, err := path.Match(pattern, FamiliarString(ref)) - if namedRef, isNamed := ref.(Named); isNamed && !matched { - matched, _ = path.Match(pattern, FamiliarName(namedRef)) - } - return matched, err -} diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/reference/normalize.go containerd-1.5.9/vendor/github.com/docker/distribution/reference/normalize.go --- containerd-1.2.6/vendor/github.com/docker/distribution/reference/normalize.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/reference/normalize.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -package reference - -import ( - "errors" - "fmt" - "strings" - - "github.com/docker/distribution/digestset" - "github.com/opencontainers/go-digest" -) - -var ( - legacyDefaultDomain = "index.docker.io" - defaultDomain = "docker.io" - officialRepoName = "library" - defaultTag = "latest" -) - -// normalizedNamed represents a name which has been -// normalized and has a familiar form. A familiar name -// is what is used in Docker UI. An example normalized -// name is "docker.io/library/ubuntu" and corresponding -// familiar name of "ubuntu". -type normalizedNamed interface { - Named - Familiar() Named -} - -// ParseNormalizedNamed parses a string into a named reference -// transforming a familiar name from Docker UI to a fully -// qualified reference. If the value may be an identifier -// use ParseAnyReference. -func ParseNormalizedNamed(s string) (Named, error) { - if ok := anchoredIdentifierRegexp.MatchString(s); ok { - return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) - } - domain, remainder := splitDockerDomain(s) - var remoteName string - if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { - remoteName = remainder[:tagSep] - } else { - remoteName = remainder - } - if strings.ToLower(remoteName) != remoteName { - return nil, errors.New("invalid reference format: repository name must be lowercase") - } - - ref, err := Parse(domain + "/" + remainder) - if err != nil { - return nil, err - } - named, isNamed := ref.(Named) - if !isNamed { - return nil, fmt.Errorf("reference %s has no name", ref.String()) - } - return named, nil -} - -// ParseDockerRef normalizes the image reference following the docker convention. This is added -// mainly for backward compatibility. -// The reference returned can only be either tagged or digested. For reference contains both tag -// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ -// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as -// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. -func ParseDockerRef(ref string) (Named, error) { - named, err := ParseNormalizedNamed(ref) - if err != nil { - return nil, err - } - if _, ok := named.(NamedTagged); ok { - if canonical, ok := named.(Canonical); ok { - // The reference is both tagged and digested, only - // return digested. - newNamed, err := WithName(canonical.Name()) - if err != nil { - return nil, err - } - newCanonical, err := WithDigest(newNamed, canonical.Digest()) - if err != nil { - return nil, err - } - return newCanonical, nil - } - } - return TagNameOnly(named), nil -} - -// splitDockerDomain splits a repository name to domain and remotename string. -// If no valid domain is found, the default domain is used. Repository name -// needs to be already validated before. -func splitDockerDomain(name string) (domain, remainder string) { - i := strings.IndexRune(name, '/') - if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { - domain, remainder = defaultDomain, name - } else { - domain, remainder = name[:i], name[i+1:] - } - if domain == legacyDefaultDomain { - domain = defaultDomain - } - if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { - remainder = officialRepoName + "/" + remainder - } - return -} - -// familiarizeName returns a shortened version of the name familiar -// to to the Docker UI. Familiar names have the default domain -// "docker.io" and "library/" repository prefix removed. -// For example, "docker.io/library/redis" will have the familiar -// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". -// Returns a familiarized named only reference. -func familiarizeName(named namedRepository) repository { - repo := repository{ - domain: named.Domain(), - path: named.Path(), - } - - if repo.domain == defaultDomain { - repo.domain = "" - // Handle official repositories which have the pattern "library/" - if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { - repo.path = split[1] - } - } - return repo -} - -func (r reference) Familiar() Named { - return reference{ - namedRepository: familiarizeName(r.namedRepository), - tag: r.tag, - digest: r.digest, - } -} - -func (r repository) Familiar() Named { - return familiarizeName(r) -} - -func (t taggedReference) Familiar() Named { - return taggedReference{ - namedRepository: familiarizeName(t.namedRepository), - tag: t.tag, - } -} - -func (c canonicalReference) Familiar() Named { - return canonicalReference{ - namedRepository: familiarizeName(c.namedRepository), - digest: c.digest, - } -} - -// TagNameOnly adds the default tag "latest" to a reference if it only has -// a repo name. -func TagNameOnly(ref Named) Named { - if IsNameOnly(ref) { - namedTagged, err := WithTag(ref, defaultTag) - if err != nil { - // Default tag must be valid, to create a NamedTagged - // type with non-validated input the WithTag function - // should be used instead - panic(err) - } - return namedTagged - } - return ref -} - -// ParseAnyReference parses a reference string as a possible identifier, -// full digest, or familiar name. -func ParseAnyReference(ref string) (Reference, error) { - if ok := anchoredIdentifierRegexp.MatchString(ref); ok { - return digestReference("sha256:" + ref), nil - } - if dgst, err := digest.Parse(ref); err == nil { - return digestReference(dgst), nil - } - - return ParseNormalizedNamed(ref) -} - -// ParseAnyReferenceWithSet parses a reference string as a possible short -// identifier to be matched in a digest set, a full digest, or familiar name. -func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { - if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { - dgst, err := ds.Lookup(ref) - if err == nil { - return digestReference(dgst), nil - } - } else { - if dgst, err := digest.Parse(ref); err == nil { - return digestReference(dgst), nil - } - } - - return ParseNormalizedNamed(ref) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/reference/reference.go containerd-1.5.9/vendor/github.com/docker/distribution/reference/reference.go --- containerd-1.2.6/vendor/github.com/docker/distribution/reference/reference.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/reference/reference.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,433 +0,0 @@ -// Package reference provides a general type to represent any way of referencing images within the registry. -// Its main purpose is to abstract tags and digests (content-addressable hash). -// -// Grammar -// -// reference := name [ ":" tag ] [ "@" digest ] -// name := [domain '/'] path-component ['/' path-component]* -// domain := domain-component ['.' domain-component]* [':' port-number] -// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ -// port-number := /[0-9]+/ -// path-component := alpha-numeric [separator alpha-numeric]* -// alpha-numeric := /[a-z0-9]+/ -// separator := /[_.]|__|[-]*/ -// -// tag := /[\w][\w.-]{0,127}/ -// -// digest := digest-algorithm ":" digest-hex -// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* -// digest-algorithm-separator := /[+.-_]/ -// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ -// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value -// -// identifier := /[a-f0-9]{64}/ -// short-identifier := /[a-f0-9]{6,64}/ -package reference - -import ( - "errors" - "fmt" - "strings" - - "github.com/opencontainers/go-digest" -) - -const ( - // NameTotalLengthMax is the maximum total number of characters in a repository name. - NameTotalLengthMax = 255 -) - -var ( - // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. - ErrReferenceInvalidFormat = errors.New("invalid reference format") - - // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. - ErrTagInvalidFormat = errors.New("invalid tag format") - - // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. - ErrDigestInvalidFormat = errors.New("invalid digest format") - - // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. - ErrNameContainsUppercase = errors.New("repository name must be lowercase") - - // ErrNameEmpty is returned for empty, invalid repository names. - ErrNameEmpty = errors.New("repository name must have at least one component") - - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) - - // ErrNameNotCanonical is returned when a name is not canonical. - ErrNameNotCanonical = errors.New("repository name must be canonical") -) - -// Reference is an opaque object reference identifier that may include -// modifiers such as a hostname, name, tag, and digest. -type Reference interface { - // String returns the full reference - String() string -} - -// Field provides a wrapper type for resolving correct reference types when -// working with encoding. -type Field struct { - reference Reference -} - -// AsField wraps a reference in a Field for encoding. -func AsField(reference Reference) Field { - return Field{reference} -} - -// Reference unwraps the reference type from the field to -// return the Reference object. This object should be -// of the appropriate type to further check for different -// reference types. -func (f Field) Reference() Reference { - return f.reference -} - -// MarshalText serializes the field to byte text which -// is the string of the reference. -func (f Field) MarshalText() (p []byte, err error) { - return []byte(f.reference.String()), nil -} - -// UnmarshalText parses text bytes by invoking the -// reference parser to ensure the appropriately -// typed reference object is wrapped by field. -func (f *Field) UnmarshalText(p []byte) error { - r, err := Parse(string(p)) - if err != nil { - return err - } - - f.reference = r - return nil -} - -// Named is an object with a full name -type Named interface { - Reference - Name() string -} - -// Tagged is an object which has a tag -type Tagged interface { - Reference - Tag() string -} - -// NamedTagged is an object including a name and tag. -type NamedTagged interface { - Named - Tag() string -} - -// Digested is an object which has a digest -// in which it can be referenced by -type Digested interface { - Reference - Digest() digest.Digest -} - -// Canonical reference is an object with a fully unique -// name including a name with domain and digest -type Canonical interface { - Named - Digest() digest.Digest -} - -// namedRepository is a reference to a repository with a name. -// A namedRepository has both domain and path components. -type namedRepository interface { - Named - Domain() string - Path() string -} - -// Domain returns the domain part of the Named reference -func Domain(named Named) string { - if r, ok := named.(namedRepository); ok { - return r.Domain() - } - domain, _ := splitDomain(named.Name()) - return domain -} - -// Path returns the name without the domain part of the Named reference -func Path(named Named) (name string) { - if r, ok := named.(namedRepository); ok { - return r.Path() - } - _, path := splitDomain(named.Name()) - return path -} - -func splitDomain(name string) (string, string) { - match := anchoredNameRegexp.FindStringSubmatch(name) - if len(match) != 3 { - return "", name - } - return match[1], match[2] -} - -// SplitHostname splits a named reference into a -// hostname and name string. If no valid hostname is -// found, the hostname is empty and the full value -// is returned as name -// DEPRECATED: Use Domain or Path -func SplitHostname(named Named) (string, string) { - if r, ok := named.(namedRepository); ok { - return r.Domain(), r.Path() - } - return splitDomain(named.Name()) -} - -// Parse parses s and returns a syntactically valid Reference. -// If an error was encountered it is returned, along with a nil Reference. -// NOTE: Parse will not handle short digests. -func Parse(s string) (Reference, error) { - matches := ReferenceRegexp.FindStringSubmatch(s) - if matches == nil { - if s == "" { - return nil, ErrNameEmpty - } - if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { - return nil, ErrNameContainsUppercase - } - return nil, ErrReferenceInvalidFormat - } - - if len(matches[1]) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - - var repo repository - - nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) - if len(nameMatch) == 3 { - repo.domain = nameMatch[1] - repo.path = nameMatch[2] - } else { - repo.domain = "" - repo.path = matches[1] - } - - ref := reference{ - namedRepository: repo, - tag: matches[2], - } - if matches[3] != "" { - var err error - ref.digest, err = digest.Parse(matches[3]) - if err != nil { - return nil, err - } - } - - r := getBestReferenceType(ref) - if r == nil { - return nil, ErrNameEmpty - } - - return r, nil -} - -// ParseNamed parses s and returns a syntactically valid reference implementing -// the Named interface. The reference must have a name and be in the canonical -// form, otherwise an error is returned. -// If an error was encountered it is returned, along with a nil Reference. -// NOTE: ParseNamed will not handle short digests. -func ParseNamed(s string) (Named, error) { - named, err := ParseNormalizedNamed(s) - if err != nil { - return nil, err - } - if named.String() != s { - return nil, ErrNameNotCanonical - } - return named, nil -} - -// WithName returns a named object representing the given string. If the input -// is invalid ErrReferenceInvalidFormat will be returned. -func WithName(name string) (Named, error) { - if len(name) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - - match := anchoredNameRegexp.FindStringSubmatch(name) - if match == nil || len(match) != 3 { - return nil, ErrReferenceInvalidFormat - } - return repository{ - domain: match[1], - path: match[2], - }, nil -} - -// WithTag combines the name from "name" and the tag from "tag" to form a -// reference incorporating both the name and the tag. -func WithTag(name Named, tag string) (NamedTagged, error) { - if !anchoredTagRegexp.MatchString(tag) { - return nil, ErrTagInvalidFormat - } - var repo repository - if r, ok := name.(namedRepository); ok { - repo.domain = r.Domain() - repo.path = r.Path() - } else { - repo.path = name.Name() - } - if canonical, ok := name.(Canonical); ok { - return reference{ - namedRepository: repo, - tag: tag, - digest: canonical.Digest(), - }, nil - } - return taggedReference{ - namedRepository: repo, - tag: tag, - }, nil -} - -// WithDigest combines the name from "name" and the digest from "digest" to form -// a reference incorporating both the name and the digest. -func WithDigest(name Named, digest digest.Digest) (Canonical, error) { - if !anchoredDigestRegexp.MatchString(digest.String()) { - return nil, ErrDigestInvalidFormat - } - var repo repository - if r, ok := name.(namedRepository); ok { - repo.domain = r.Domain() - repo.path = r.Path() - } else { - repo.path = name.Name() - } - if tagged, ok := name.(Tagged); ok { - return reference{ - namedRepository: repo, - tag: tagged.Tag(), - digest: digest, - }, nil - } - return canonicalReference{ - namedRepository: repo, - digest: digest, - }, nil -} - -// TrimNamed removes any tag or digest from the named reference. -func TrimNamed(ref Named) Named { - domain, path := SplitHostname(ref) - return repository{ - domain: domain, - path: path, - } -} - -func getBestReferenceType(ref reference) Reference { - if ref.Name() == "" { - // Allow digest only references - if ref.digest != "" { - return digestReference(ref.digest) - } - return nil - } - if ref.tag == "" { - if ref.digest != "" { - return canonicalReference{ - namedRepository: ref.namedRepository, - digest: ref.digest, - } - } - return ref.namedRepository - } - if ref.digest == "" { - return taggedReference{ - namedRepository: ref.namedRepository, - tag: ref.tag, - } - } - - return ref -} - -type reference struct { - namedRepository - tag string - digest digest.Digest -} - -func (r reference) String() string { - return r.Name() + ":" + r.tag + "@" + r.digest.String() -} - -func (r reference) Tag() string { - return r.tag -} - -func (r reference) Digest() digest.Digest { - return r.digest -} - -type repository struct { - domain string - path string -} - -func (r repository) String() string { - return r.Name() -} - -func (r repository) Name() string { - if r.domain == "" { - return r.path - } - return r.domain + "/" + r.path -} - -func (r repository) Domain() string { - return r.domain -} - -func (r repository) Path() string { - return r.path -} - -type digestReference digest.Digest - -func (d digestReference) String() string { - return digest.Digest(d).String() -} - -func (d digestReference) Digest() digest.Digest { - return digest.Digest(d) -} - -type taggedReference struct { - namedRepository - tag string -} - -func (t taggedReference) String() string { - return t.Name() + ":" + t.tag -} - -func (t taggedReference) Tag() string { - return t.tag -} - -type canonicalReference struct { - namedRepository - digest digest.Digest -} - -func (c canonicalReference) String() string { - return c.Name() + "@" + c.digest.String() -} - -func (c canonicalReference) Digest() digest.Digest { - return c.digest -} diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/reference/regexp.go containerd-1.5.9/vendor/github.com/docker/distribution/reference/regexp.go --- containerd-1.2.6/vendor/github.com/docker/distribution/reference/regexp.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/reference/regexp.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -package reference - -import "regexp" - -var ( - // alphaNumericRegexp defines the alpha numeric atom, typically a - // component of names. This only allows lower case characters and digits. - alphaNumericRegexp = match(`[a-z0-9]+`) - - // separatorRegexp defines the separators allowed to be embedded in name - // components. This allow one period, one or two underscore and multiple - // dashes. - separatorRegexp = match(`(?:[._]|__|[-]*)`) - - // nameComponentRegexp restricts registry path component names to start - // with at least one letter or number, with following parts able to be - // separated by one period, one or two underscore and multiple dashes. - nameComponentRegexp = expression( - alphaNumericRegexp, - optional(repeated(separatorRegexp, alphaNumericRegexp))) - - // domainComponentRegexp restricts the registry domain component of a - // repository name to start with a component as defined by DomainRegexp - // and followed by an optional port. - domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) - - // DomainRegexp defines the structure of potential domain components - // that may be part of image names. This is purposely a subset of what is - // allowed by DNS to ensure backwards compatibility with Docker image - // names. - DomainRegexp = expression( - domainComponentRegexp, - optional(repeated(literal(`.`), domainComponentRegexp)), - optional(literal(`:`), match(`[0-9]+`))) - - // TagRegexp matches valid tag names. From docker/docker:graph/tags.go. - TagRegexp = match(`[\w][\w.-]{0,127}`) - - // anchoredTagRegexp matches valid tag names, anchored at the start and - // end of the matched string. - anchoredTagRegexp = anchored(TagRegexp) - - // DigestRegexp matches valid digests. - DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) - - // anchoredDigestRegexp matches valid digests, anchored at the start and - // end of the matched string. - anchoredDigestRegexp = anchored(DigestRegexp) - - // NameRegexp is the format for the name component of references. The - // regexp has capturing groups for the domain and name part omitting - // the separating forward slash from either. - NameRegexp = expression( - optional(DomainRegexp, literal(`/`)), - nameComponentRegexp, - optional(repeated(literal(`/`), nameComponentRegexp))) - - // anchoredNameRegexp is used to parse a name value, capturing the - // domain and trailing components. - anchoredNameRegexp = anchored( - optional(capture(DomainRegexp), literal(`/`)), - capture(nameComponentRegexp, - optional(repeated(literal(`/`), nameComponentRegexp)))) - - // ReferenceRegexp is the full supported format of a reference. The regexp - // is anchored and has capturing groups for name, tag, and digest - // components. - ReferenceRegexp = anchored(capture(NameRegexp), - optional(literal(":"), capture(TagRegexp)), - optional(literal("@"), capture(DigestRegexp))) - - // IdentifierRegexp is the format for string identifier used as a - // content addressable identifier using sha256. These identifiers - // are like digests without the algorithm, since sha256 is used. - IdentifierRegexp = match(`([a-f0-9]{64})`) - - // ShortIdentifierRegexp is the format used to represent a prefix - // of an identifier. A prefix may be used to match a sha256 identifier - // within a list of trusted identifiers. - ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) - - // anchoredIdentifierRegexp is used to check or match an - // identifier value, anchored at start and end of string. - anchoredIdentifierRegexp = anchored(IdentifierRegexp) - - // anchoredShortIdentifierRegexp is used to check if a value - // is a possible identifier prefix, anchored at start and end - // of string. - anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp) -) - -// match compiles the string to a regular expression. -var match = regexp.MustCompile - -// literal compiles s into a literal regular expression, escaping any regexp -// reserved characters. -func literal(s string) *regexp.Regexp { - re := match(regexp.QuoteMeta(s)) - - if _, complete := re.LiteralPrefix(); !complete { - panic("must be a literal") - } - - return re -} - -// expression defines a full expression, where each regular expression must -// follow the previous. -func expression(res ...*regexp.Regexp) *regexp.Regexp { - var s string - for _, re := range res { - s += re.String() - } - - return match(s) -} - -// optional wraps the expression in a non-capturing group and makes the -// production optional. -func optional(res ...*regexp.Regexp) *regexp.Regexp { - return match(group(expression(res...)).String() + `?`) -} - -// repeated wraps the regexp in a non-capturing group to get one or more -// matches. -func repeated(res ...*regexp.Regexp) *regexp.Regexp { - return match(group(expression(res...)).String() + `+`) -} - -// group wraps the regexp in a non-capturing group. -func group(res ...*regexp.Regexp) *regexp.Regexp { - return match(`(?:` + expression(res...).String() + `)`) -} - -// capture wraps the expression in a capturing group. -func capture(res ...*regexp.Regexp) *regexp.Regexp { - return match(`(` + expression(res...).String() + `)`) -} - -// anchored anchors the regular expression by adding start and end delimiters. -func anchored(res ...*regexp.Regexp) *regexp.Regexp { - return match(`^` + expression(res...).String() + `$`) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/distribution/vendor.conf containerd-1.5.9/vendor/github.com/docker/distribution/vendor.conf --- containerd-1.2.6/vendor/github.com/docker/distribution/vendor.conf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/distribution/vendor.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -github.com/Azure/azure-sdk-for-go 4650843026a7fdec254a8d9cf893693a254edd0b -github.com/Azure/go-autorest eaa7994b2278094c904d31993d26f56324db3052 -github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4 -github.com/aws/aws-sdk-go f831d5a0822a1ad72420ab18c6269bca1ddaf490 -github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a -github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 -github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274 -github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702 -github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782 -github.com/denverdino/aliyungo 6df11717a253d9c7d4141f9af4deaa7c580cd531 -github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04 -github.com/docker/go-metrics 399ea8c73916000c64c2c76e8da00ca82f8387ab -github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21 -github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257 -github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c -github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3 -github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b -github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604 -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d -github.com/marstr/guid 8bd9a64bf37eb297b492a4101fb28e80ac0b290f -github.com/satori/go.uuid f58768cc1a7a7e77a3bd49e98cdd21419399b6a3 -github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c -github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39 -github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef -github.com/ncw/swift a0320860b16212c2b59b4912bb6508cda1d7cee6 -github.com/prometheus/client_golang c332b6f63c0658a65eca15c0e5247ded801cf564 -github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c -github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563 -github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd -github.com/Shopify/logrus-bugsnag 577dee27f20dd8f1a529f82210094af593be12bd -github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064 -github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842 -github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985 -github.com/yvasiyarov/go-metrics 57bccd1ccd43f94bb17fdd8bf3007059b802f85e -github.com/yvasiyarov/gorelic a9bba5b9ab508a086f9a12b8c51fab68478e2128 -github.com/yvasiyarov/newrelic_platform_go b21fdbd4370f3717f3bbd2bf41c223bc273068e6 -golang.org/x/crypto c10c31b5e94b6f7a0283272dc2bb27163dcea24b -golang.org/x/net 4876518f9e71663000c348837735820161a42df7 -golang.org/x/oauth2 045497edb6234273d67dbc25da3f2ddbc4c4cacf -golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb -google.golang.org/api 9bf6e6e569ff057f75d9604a46c52928f17d2b54 -google.golang.org/appengine 12d5545dc1cfa6047a286d5e853841b6471f4c19 -google.golang.org/cloud 975617b05ea8a58727e6c1a06b6161ff4185a9f2 -google.golang.org/grpc d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994 -gopkg.in/check.v1 64131543e7896d5bcc6bd5a76287eb75ea96c673 -gopkg.in/square/go-jose.v1 40d457b439244b546f023d056628e5184136899b -gopkg.in/yaml.v2 v2.2.1 -rsc.io/letsencrypt e770c10b0f1a64775ae91d240407ce00d1a5bdeb https://github.com/dmcgowan/letsencrypt.git -github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb -github.com/opencontainers/image-spec ab7389ef9f50030c9b245bc16b981c7ddf192882 diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/nnp-test/nnp-test.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/nnp-test/nnp-test.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/nnp-test/nnp-test.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/nnp-test/nnp-test.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -#include -#include -#include - -int main(int argc, char *argv[]) -{ - printf("EUID=%d\n", geteuid()); - return 0; -} - diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/README.md containerd-1.5.9/vendor/github.com/docker/docker/contrib/README.md --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -The `contrib` directory contains scripts, images, and other helpful things -which are not part of the core docker distribution. Please note that they -could be out of date, since they do not receive the same attention as the -rest of the repository. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/acct.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/acct.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/acct.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/acct.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - int err = acct("/tmp/t"); - if (err == -1) { - fprintf(stderr, "acct failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/exit32.s containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/exit32.s --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/exit32.s 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/exit32.s 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -.globl _start -.text -_start: - xorl %eax, %eax - incl %eax - movb $0, %bl - int $0x80 diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/ns.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/ns.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/ns.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/ns.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */ - -struct clone_args { - char **argv; -}; - -// child_exec is the func that will be executed as the result of clone -static int child_exec(void *stuff) -{ - struct clone_args *args = (struct clone_args *)stuff; - if (execvp(args->argv[0], args->argv) != 0) { - fprintf(stderr, "failed to execvp arguments %s\n", - strerror(errno)); - exit(-1); - } - // we should never reach here! - exit(EXIT_FAILURE); -} - -int main(int argc, char **argv) -{ - struct clone_args args; - args.argv = &argv[1]; - - int clone_flags = CLONE_NEWNS | CLONE_NEWPID | SIGCHLD; - - // allocate stack for child - char *stack; /* Start of stack buffer */ - char *child_stack; /* End of stack buffer */ - stack = - mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0); - if (stack == MAP_FAILED) { - fprintf(stderr, "mmap failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - child_stack = stack + STACK_SIZE; /* Assume stack grows downward */ - - // the result of this call is that our child_exec will be run in another - // process returning its pid - pid_t pid = clone(child_exec, child_stack, clone_flags, &args); - if (pid < 0) { - fprintf(stderr, "clone failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - // lets wait on our child process here before we, the parent, exits - if (waitpid(pid, NULL, 0) == -1) { - fprintf(stderr, "failed to wait pid %d\n", pid); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/raw.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/raw.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/raw.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/raw.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#include -#include -#include -#include -#include - -int main() { - if (socket(PF_INET, SOCK_RAW, IPPROTO_UDP) == -1) { - perror("socket"); - return 1; - } - - return 0; -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/setgid.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/setgid.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/setgid.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/setgid.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -#include -#include -#include - -int main() { - if (setgid(1) == -1) { - perror("setgid"); - return 1; - } - return 0; -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/setuid.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/setuid.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/setuid.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/setuid.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -#include -#include -#include - -int main() { - if (setuid(1) == -1) { - perror("setuid"); - return 1; - } - return 0; -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/socket.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/socket.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/socket.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/socket.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -#include -#include -#include -#include -#include -#include - -int main() { - int s; - struct sockaddr_in sin; - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == -1) { - perror("socket"); - return 1; - } - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(80); - - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) { - perror("bind"); - return 1; - } - - close(s); - - return 0; -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/userns.c containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/userns.c --- containerd-1.2.6/vendor/github.com/docker/docker/contrib/syscall-test/userns.c 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/contrib/syscall-test/userns.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */ - -struct clone_args { - char **argv; -}; - -// child_exec is the func that will be executed as the result of clone -static int child_exec(void *stuff) -{ - struct clone_args *args = (struct clone_args *)stuff; - if (execvp(args->argv[0], args->argv) != 0) { - fprintf(stderr, "failed to execvp arguments %s\n", - strerror(errno)); - exit(-1); - } - // we should never reach here! - exit(EXIT_FAILURE); -} - -int main(int argc, char **argv) -{ - struct clone_args args; - args.argv = &argv[1]; - - int clone_flags = CLONE_NEWUSER | SIGCHLD; - - // allocate stack for child - char *stack; /* Start of stack buffer */ - char *child_stack; /* End of stack buffer */ - stack = - mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0); - if (stack == MAP_FAILED) { - fprintf(stderr, "mmap failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - child_stack = stack + STACK_SIZE; /* Assume stack grows downward */ - - // the result of this call is that our child_exec will be run in another - // process returning its pid - pid_t pid = clone(child_exec, child_stack, clone_flags, &args); - if (pid < 0) { - fprintf(stderr, "clone failed: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - // lets wait on our child process here before we, the parent, exits - if (waitpid(pid, NULL, 0) == -1) { - fprintf(stderr, "failed to wait pid %d\n", pid); - exit(EXIT_FAILURE); - } - exit(EXIT_SUCCESS); -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/LICENSE containerd-1.5.9/vendor/github.com/docker/docker/LICENSE --- containerd-1.2.6/vendor/github.com/docker/docker/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2013-2017 Docker, Inc. - - 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. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/NOTICE containerd-1.5.9/vendor/github.com/docker/docker/NOTICE --- containerd-1.2.6/vendor/github.com/docker/docker/NOTICE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/NOTICE 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Docker -Copyright 2012-2017 Docker, Inc. - -This product includes software developed at Docker, Inc. (https://www.docker.com). - -This product contains software (https://github.com/kr/pty) developed -by Keith Rarick, licensed under the MIT License. - -The following is courtesy of our legal counsel: - - -Use and transfer of Docker may be subject to certain restrictions by the -United States and other governments. -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see https://www.bis.doc.gov - -See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/buffer.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/buffer.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/buffer.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/buffer.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -package ioutils - -import ( - "errors" - "io" -) - -var errBufferFull = errors.New("buffer is full") - -type fixedBuffer struct { - buf []byte - pos int - lastRead int -} - -func (b *fixedBuffer) Write(p []byte) (int, error) { - n := copy(b.buf[b.pos:cap(b.buf)], p) - b.pos += n - - if n < len(p) { - if b.pos == cap(b.buf) { - return n, errBufferFull - } - return n, io.ErrShortWrite - } - return n, nil -} - -func (b *fixedBuffer) Read(p []byte) (int, error) { - n := copy(p, b.buf[b.lastRead:b.pos]) - b.lastRead += n - return n, nil -} - -func (b *fixedBuffer) Len() int { - return b.pos - b.lastRead -} - -func (b *fixedBuffer) Cap() int { - return cap(b.buf) -} - -func (b *fixedBuffer) Reset() { - b.pos = 0 - b.lastRead = 0 - b.buf = b.buf[:0] -} - -func (b *fixedBuffer) String() string { - return string(b.buf[b.lastRead:b.pos]) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/bytespipe.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -package ioutils - -import ( - "errors" - "io" - "sync" -) - -// maxCap is the highest capacity to use in byte slices that buffer data. -const maxCap = 1e6 - -// minCap is the lowest capacity to use in byte slices that buffer data -const minCap = 64 - -// blockThreshold is the minimum number of bytes in the buffer which will cause -// a write to BytesPipe to block when allocating a new slice. -const blockThreshold = 1e6 - -var ( - // ErrClosed is returned when Write is called on a closed BytesPipe. - ErrClosed = errors.New("write to closed BytesPipe") - - bufPools = make(map[int]*sync.Pool) - bufPoolsLock sync.Mutex -) - -// BytesPipe is io.ReadWriteCloser which works similarly to pipe(queue). -// All written data may be read at most once. Also, BytesPipe allocates -// and releases new byte slices to adjust to current needs, so the buffer -// won't be overgrown after peak loads. -type BytesPipe struct { - mu sync.Mutex - wait *sync.Cond - buf []*fixedBuffer - bufLen int - closeErr error // error to return from next Read. set to nil if not closed. -} - -// NewBytesPipe creates new BytesPipe, initialized by specified slice. -// If buf is nil, then it will be initialized with slice which cap is 64. -// buf will be adjusted in a way that len(buf) == 0, cap(buf) == cap(buf). -func NewBytesPipe() *BytesPipe { - bp := &BytesPipe{} - bp.buf = append(bp.buf, getBuffer(minCap)) - bp.wait = sync.NewCond(&bp.mu) - return bp -} - -// Write writes p to BytesPipe. -// It can allocate new []byte slices in a process of writing. -func (bp *BytesPipe) Write(p []byte) (int, error) { - bp.mu.Lock() - - written := 0 -loop0: - for { - if bp.closeErr != nil { - bp.mu.Unlock() - return written, ErrClosed - } - - if len(bp.buf) == 0 { - bp.buf = append(bp.buf, getBuffer(64)) - } - // get the last buffer - b := bp.buf[len(bp.buf)-1] - - n, err := b.Write(p) - written += n - bp.bufLen += n - - // errBufferFull is an error we expect to get if the buffer is full - if err != nil && err != errBufferFull { - bp.wait.Broadcast() - bp.mu.Unlock() - return written, err - } - - // if there was enough room to write all then break - if len(p) == n { - break - } - - // more data: write to the next slice - p = p[n:] - - // make sure the buffer doesn't grow too big from this write - for bp.bufLen >= blockThreshold { - bp.wait.Wait() - if bp.closeErr != nil { - continue loop0 - } - } - - // add new byte slice to the buffers slice and continue writing - nextCap := b.Cap() * 2 - if nextCap > maxCap { - nextCap = maxCap - } - bp.buf = append(bp.buf, getBuffer(nextCap)) - } - bp.wait.Broadcast() - bp.mu.Unlock() - return written, nil -} - -// CloseWithError causes further reads from a BytesPipe to return immediately. -func (bp *BytesPipe) CloseWithError(err error) error { - bp.mu.Lock() - if err != nil { - bp.closeErr = err - } else { - bp.closeErr = io.EOF - } - bp.wait.Broadcast() - bp.mu.Unlock() - return nil -} - -// Close causes further reads from a BytesPipe to return immediately. -func (bp *BytesPipe) Close() error { - return bp.CloseWithError(nil) -} - -// Read reads bytes from BytesPipe. -// Data could be read only once. -func (bp *BytesPipe) Read(p []byte) (n int, err error) { - bp.mu.Lock() - if bp.bufLen == 0 { - if bp.closeErr != nil { - bp.mu.Unlock() - return 0, bp.closeErr - } - bp.wait.Wait() - if bp.bufLen == 0 && bp.closeErr != nil { - err := bp.closeErr - bp.mu.Unlock() - return 0, err - } - } - - for bp.bufLen > 0 { - b := bp.buf[0] - read, _ := b.Read(p) // ignore error since fixedBuffer doesn't really return an error - n += read - bp.bufLen -= read - - if b.Len() == 0 { - // it's empty so return it to the pool and move to the next one - returnBuffer(b) - bp.buf[0] = nil - bp.buf = bp.buf[1:] - } - - if len(p) == read { - break - } - - p = p[read:] - } - - bp.wait.Broadcast() - bp.mu.Unlock() - return -} - -func returnBuffer(b *fixedBuffer) { - b.Reset() - bufPoolsLock.Lock() - pool := bufPools[b.Cap()] - bufPoolsLock.Unlock() - if pool != nil { - pool.Put(b) - } -} - -func getBuffer(size int) *fixedBuffer { - bufPoolsLock.Lock() - pool, ok := bufPools[size] - if !ok { - pool = &sync.Pool{New: func() interface{} { return &fixedBuffer{buf: make([]byte, 0, size)} }} - bufPools[size] = pool - } - bufPoolsLock.Unlock() - return pool.Get().(*fixedBuffer) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/fswriters.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,162 +0,0 @@ -package ioutils - -import ( - "io" - "io/ioutil" - "os" - "path/filepath" -) - -// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a -// temporary file and closing it atomically changes the temporary file to -// destination path. Writing and closing concurrently is not allowed. -func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { - f, err := ioutil.TempFile(filepath.Dir(filename), ".tmp-"+filepath.Base(filename)) - if err != nil { - return nil, err - } - - abspath, err := filepath.Abs(filename) - if err != nil { - return nil, err - } - return &atomicFileWriter{ - f: f, - fn: abspath, - perm: perm, - }, nil -} - -// AtomicWriteFile atomically writes data to a file named by filename. -func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { - f, err := NewAtomicFileWriter(filename, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - f.(*atomicFileWriter).writeErr = err - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -type atomicFileWriter struct { - f *os.File - fn string - writeErr error - perm os.FileMode -} - -func (w *atomicFileWriter) Write(dt []byte) (int, error) { - n, err := w.f.Write(dt) - if err != nil { - w.writeErr = err - } - return n, err -} - -func (w *atomicFileWriter) Close() (retErr error) { - defer func() { - if retErr != nil || w.writeErr != nil { - os.Remove(w.f.Name()) - } - }() - if err := w.f.Sync(); err != nil { - w.f.Close() - return err - } - if err := w.f.Close(); err != nil { - return err - } - if err := os.Chmod(w.f.Name(), w.perm); err != nil { - return err - } - if w.writeErr == nil { - return os.Rename(w.f.Name(), w.fn) - } - return nil -} - -// AtomicWriteSet is used to atomically write a set -// of files and ensure they are visible at the same time. -// Must be committed to a new directory. -type AtomicWriteSet struct { - root string -} - -// NewAtomicWriteSet creates a new atomic write set to -// atomically create a set of files. The given directory -// is used as the base directory for storing files before -// commit. If no temporary directory is given the system -// default is used. -func NewAtomicWriteSet(tmpDir string) (*AtomicWriteSet, error) { - td, err := ioutil.TempDir(tmpDir, "write-set-") - if err != nil { - return nil, err - } - - return &AtomicWriteSet{ - root: td, - }, nil -} - -// WriteFile writes a file to the set, guaranteeing the file -// has been synced. -func (ws *AtomicWriteSet) WriteFile(filename string, data []byte, perm os.FileMode) error { - f, err := ws.FileWriter(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } - if err1 := f.Close(); err == nil { - err = err1 - } - return err -} - -type syncFileCloser struct { - *os.File -} - -func (w syncFileCloser) Close() error { - err := w.File.Sync() - if err1 := w.File.Close(); err == nil { - err = err1 - } - return err -} - -// FileWriter opens a file writer inside the set. The file -// should be synced and closed before calling commit. -func (ws *AtomicWriteSet) FileWriter(name string, flag int, perm os.FileMode) (io.WriteCloser, error) { - f, err := os.OpenFile(filepath.Join(ws.root, name), flag, perm) - if err != nil { - return nil, err - } - return syncFileCloser{f}, nil -} - -// Cancel cancels the set and removes all temporary data -// created in the set. -func (ws *AtomicWriteSet) Cancel() error { - return os.RemoveAll(ws.root) -} - -// Commit moves all created files to the target directory. The -// target directory must not exist and the parent of the target -// directory must exist. -func (ws *AtomicWriteSet) Commit(target string) error { - return os.Rename(ws.root, target) -} - -// String returns the location the set is writing to. -func (ws *AtomicWriteSet) String() string { - return ws.root -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/readers.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/readers.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/readers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/readers.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -package ioutils - -import ( - "crypto/sha256" - "encoding/hex" - "io" - - "golang.org/x/net/context" -) - -type readCloserWrapper struct { - io.Reader - closer func() error -} - -func (r *readCloserWrapper) Close() error { - return r.closer() -} - -// NewReadCloserWrapper returns a new io.ReadCloser. -func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { - return &readCloserWrapper{ - Reader: r, - closer: closer, - } -} - -type readerErrWrapper struct { - reader io.Reader - closer func() -} - -func (r *readerErrWrapper) Read(p []byte) (int, error) { - n, err := r.reader.Read(p) - if err != nil { - r.closer() - } - return n, err -} - -// NewReaderErrWrapper returns a new io.Reader. -func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader { - return &readerErrWrapper{ - reader: r, - closer: closer, - } -} - -// HashData returns the sha256 sum of src. -func HashData(src io.Reader) (string, error) { - h := sha256.New() - if _, err := io.Copy(h, src); err != nil { - return "", err - } - return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil -} - -// OnEOFReader wraps an io.ReadCloser and a function -// the function will run at the end of file or close the file. -type OnEOFReader struct { - Rc io.ReadCloser - Fn func() -} - -func (r *OnEOFReader) Read(p []byte) (n int, err error) { - n, err = r.Rc.Read(p) - if err == io.EOF { - r.runFunc() - } - return -} - -// Close closes the file and run the function. -func (r *OnEOFReader) Close() error { - err := r.Rc.Close() - r.runFunc() - return err -} - -func (r *OnEOFReader) runFunc() { - if fn := r.Fn; fn != nil { - fn() - r.Fn = nil - } -} - -// cancelReadCloser wraps an io.ReadCloser with a context for cancelling read -// operations. -type cancelReadCloser struct { - cancel func() - pR *io.PipeReader // Stream to read from - pW *io.PipeWriter -} - -// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the -// context is cancelled. The returned io.ReadCloser must be closed when it is -// no longer needed. -func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { - pR, pW := io.Pipe() - - // Create a context used to signal when the pipe is closed - doneCtx, cancel := context.WithCancel(context.Background()) - - p := &cancelReadCloser{ - cancel: cancel, - pR: pR, - pW: pW, - } - - go func() { - _, err := io.Copy(pW, in) - select { - case <-ctx.Done(): - // If the context was closed, p.closeWithError - // was already called. Calling it again would - // change the error that Read returns. - default: - p.closeWithError(err) - } - in.Close() - }() - go func() { - for { - select { - case <-ctx.Done(): - p.closeWithError(ctx.Err()) - case <-doneCtx.Done(): - return - } - } - }() - - return p -} - -// Read wraps the Read method of the pipe that provides data from the wrapped -// ReadCloser. -func (p *cancelReadCloser) Read(buf []byte) (n int, err error) { - return p.pR.Read(buf) -} - -// closeWithError closes the wrapper and its underlying reader. It will -// cause future calls to Read to return err. -func (p *cancelReadCloser) closeWithError(err error) { - p.pW.CloseWithError(err) - p.cancel() -} - -// Close closes the wrapper its underlying reader. It will cause -// future calls to Read to return io.EOF. -func (p *cancelReadCloser) Close() error { - p.closeWithError(io.EOF) - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/temp_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -// +build !windows - -package ioutils - -import "io/ioutil" - -// TempDir on Unix systems is equivalent to ioutil.TempDir. -func TempDir(dir, prefix string) (string, error) { - return ioutil.TempDir(dir, prefix) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/temp_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -// +build windows - -package ioutils - -import ( - "io/ioutil" - - "github.com/docker/docker/pkg/longpath" -) - -// TempDir is the equivalent of ioutil.TempDir, except that the result is in Windows longpath format. -func TempDir(dir, prefix string) (string, error) { - tempDir, err := ioutil.TempDir(dir, prefix) - if err != nil { - return "", err - } - return longpath.AddPrefix(tempDir), nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -package ioutils - -import ( - "io" - "sync" -) - -// WriteFlusher wraps the Write and Flush operation ensuring that every write -// is a flush. In addition, the Close method can be called to intercept -// Read/Write calls if the targets lifecycle has already ended. -type WriteFlusher struct { - w io.Writer - flusher flusher - flushed chan struct{} - flushedOnce sync.Once - closed chan struct{} - closeLock sync.Mutex -} - -type flusher interface { - Flush() -} - -var errWriteFlusherClosed = io.EOF - -func (wf *WriteFlusher) Write(b []byte) (n int, err error) { - select { - case <-wf.closed: - return 0, errWriteFlusherClosed - default: - } - - n, err = wf.w.Write(b) - wf.Flush() // every write is a flush. - return n, err -} - -// Flush the stream immediately. -func (wf *WriteFlusher) Flush() { - select { - case <-wf.closed: - return - default: - } - - wf.flushedOnce.Do(func() { - close(wf.flushed) - }) - wf.flusher.Flush() -} - -// Flushed returns the state of flushed. -// If it's flushed, return true, or else it return false. -func (wf *WriteFlusher) Flushed() bool { - // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to - // be used to detect whether or a response code has been issued or not. - // Another hook should be used instead. - var flushed bool - select { - case <-wf.flushed: - flushed = true - default: - } - return flushed -} - -// Close closes the write flusher, disallowing any further writes to the -// target. After the flusher is closed, all calls to write or flush will -// result in an error. -func (wf *WriteFlusher) Close() error { - wf.closeLock.Lock() - defer wf.closeLock.Unlock() - - select { - case <-wf.closed: - return errWriteFlusherClosed - default: - close(wf.closed) - } - return nil -} - -// NewWriteFlusher returns a new WriteFlusher. -func NewWriteFlusher(w io.Writer) *WriteFlusher { - var fl flusher - if f, ok := w.(flusher); ok { - fl = f - } else { - fl = &NopFlusher{} - } - return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/writers.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/writers.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/ioutils/writers.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/ioutils/writers.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -package ioutils - -import "io" - -// NopWriter represents a type which write operation is nop. -type NopWriter struct{} - -func (*NopWriter) Write(buf []byte) (int, error) { - return len(buf), nil -} - -type nopWriteCloser struct { - io.Writer -} - -func (w *nopWriteCloser) Close() error { return nil } - -// NopWriteCloser returns a nopWriteCloser. -func NopWriteCloser(w io.Writer) io.WriteCloser { - return &nopWriteCloser{w} -} - -// NopFlusher represents a type which flush operation is nop. -type NopFlusher struct{} - -// Flush is a nop operation. -func (f *NopFlusher) Flush() {} - -type writeCloserWrapper struct { - io.Writer - closer func() error -} - -func (r *writeCloserWrapper) Close() error { - return r.closer() -} - -// NewWriteCloserWrapper returns a new io.WriteCloser. -func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { - return &writeCloserWrapper{ - Writer: r, - closer: closer, - } -} - -// WriteCounter wraps a concrete io.Writer and hold a count of the number -// of bytes written to the writer during a "session". -// This can be convenient when write return is masked -// (e.g., json.Encoder.Encode()) -type WriteCounter struct { - Count int64 - Writer io.Writer -} - -// NewWriteCounter returns a new WriteCounter. -func NewWriteCounter(w io.Writer) *WriteCounter { - return &WriteCounter{ - Writer: w, - } -} - -func (wc *WriteCounter) Write(p []byte) (count int, err error) { - count, err = wc.Writer.Write(p) - wc.Count += int64(count) - return -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/longpath/longpath.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/longpath/longpath.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/longpath/longpath.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/longpath/longpath.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -// longpath introduces some constants and helper functions for handling long paths -// in Windows, which are expected to be prepended with `\\?\` and followed by either -// a drive letter, a UNC server\share, or a volume identifier. - -package longpath - -import ( - "strings" -) - -// Prefix is the longpath prefix for Windows file paths. -const Prefix = `\\?\` - -// AddPrefix will add the Windows long path prefix to the path provided if -// it does not already have it. -func AddPrefix(path string) string { - if !strings.HasPrefix(path, Prefix) { - if strings.HasPrefix(path, `\\`) { - // This is a UNC path, so we need to add 'UNC' to the path as well. - path = Prefix + `UNC` + path[1:] - } else { - path = Prefix + path - } - } - return path -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -// +build freebsd,cgo - -package mount - -/* -#include -*/ -import "C" - -const ( - // RDONLY will mount the filesystem as read-only. - RDONLY = C.MNT_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = C.MNT_NOSUID - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = C.MNT_NOEXEC - - // SYNCHRONOUS will allow any I/O to the file system to be done synchronously. - SYNCHRONOUS = C.MNT_SYNCHRONOUS - - // NOATIME will not update the file access time when reading from a file. - NOATIME = C.MNT_NOATIME -) - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NODEV = 0 - NODIRATIME = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIVE = 0 - RELATIME = 0 - REMOUNT = 0 - STRICTATIME = 0 - mntDetach = 0 -) diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -package mount - -import ( - "fmt" - "strings" -) - -var flags = map[string]struct { - clear bool - flag int -}{ - "defaults": {false, 0}, - "ro": {false, RDONLY}, - "rw": {true, RDONLY}, - "suid": {true, NOSUID}, - "nosuid": {false, NOSUID}, - "dev": {true, NODEV}, - "nodev": {false, NODEV}, - "exec": {true, NOEXEC}, - "noexec": {false, NOEXEC}, - "sync": {false, SYNCHRONOUS}, - "async": {true, SYNCHRONOUS}, - "dirsync": {false, DIRSYNC}, - "remount": {false, REMOUNT}, - "mand": {false, MANDLOCK}, - "nomand": {true, MANDLOCK}, - "atime": {true, NOATIME}, - "noatime": {false, NOATIME}, - "diratime": {true, NODIRATIME}, - "nodiratime": {false, NODIRATIME}, - "bind": {false, BIND}, - "rbind": {false, RBIND}, - "unbindable": {false, UNBINDABLE}, - "runbindable": {false, RUNBINDABLE}, - "private": {false, PRIVATE}, - "rprivate": {false, RPRIVATE}, - "shared": {false, SHARED}, - "rshared": {false, RSHARED}, - "slave": {false, SLAVE}, - "rslave": {false, RSLAVE}, - "relatime": {false, RELATIME}, - "norelatime": {true, RELATIME}, - "strictatime": {false, STRICTATIME}, - "nostrictatime": {true, STRICTATIME}, -} - -var validFlags = map[string]bool{ - "": true, - "size": true, - "mode": true, - "uid": true, - "gid": true, - "nr_inodes": true, - "nr_blocks": true, - "mpol": true, -} - -var propagationFlags = map[string]bool{ - "bind": true, - "rbind": true, - "unbindable": true, - "runbindable": true, - "private": true, - "rprivate": true, - "shared": true, - "rshared": true, - "slave": true, - "rslave": true, -} - -// MergeTmpfsOptions merge mount options to make sure there is no duplicate. -func MergeTmpfsOptions(options []string) ([]string, error) { - // We use collisions maps to remove duplicates. - // For flag, the key is the flag value (the key for propagation flag is -1) - // For data=value, the key is the data - flagCollisions := map[int]bool{} - dataCollisions := map[string]bool{} - - var newOptions []string - // We process in reverse order - for i := len(options) - 1; i >= 0; i-- { - option := options[i] - if option == "defaults" { - continue - } - if f, ok := flags[option]; ok && f.flag != 0 { - // There is only one propagation mode - key := f.flag - if propagationFlags[option] { - key = -1 - } - // Check to see if there is collision for flag - if !flagCollisions[key] { - // We prepend the option and add to collision map - newOptions = append([]string{option}, newOptions...) - flagCollisions[key] = true - } - continue - } - opt := strings.SplitN(option, "=", 2) - if len(opt) != 2 || !validFlags[opt[0]] { - return nil, fmt.Errorf("Invalid tmpfs option %q", opt) - } - if !dataCollisions[opt[0]] { - // We prepend the option and add to collision map - newOptions = append([]string{option}, newOptions...) - dataCollisions[opt[0]] = true - } - } - - return newOptions, nil -} - -// Parse fstab type mount options into mount() flags -// and device specific data -func parseOptions(options string) (int, string) { - var ( - flag int - data []string - ) - - for _, o := range strings.Split(options, ",") { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &= ^f.flag - } else { - flag |= f.flag - } - } else { - data = append(data, o) - } - } - return flag, strings.Join(data, ",") -} - -// ParseTmpfsOptions parse fstab type mount options into flags and data -func ParseTmpfsOptions(options string) (int, string, error) { - flags, data := parseOptions(options) - for _, o := range strings.Split(data, ",") { - opt := strings.SplitN(o, "=", 2) - if !validFlags[opt[0]] { - return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt) - } - } - return flags, data, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -package mount - -import ( - "golang.org/x/sys/unix" -) - -const ( - // RDONLY will mount the file system read-only. - RDONLY = unix.MS_RDONLY - - // NOSUID will not allow set-user-identifier or set-group-identifier bits to - // take effect. - NOSUID = unix.MS_NOSUID - - // NODEV will not interpret character or block special devices on the file - // system. - NODEV = unix.MS_NODEV - - // NOEXEC will not allow execution of any binaries on the mounted file system. - NOEXEC = unix.MS_NOEXEC - - // SYNCHRONOUS will allow I/O to the file system to be done synchronously. - SYNCHRONOUS = unix.MS_SYNCHRONOUS - - // DIRSYNC will force all directory updates within the file system to be done - // synchronously. This affects the following system calls: create, link, - // unlink, symlink, mkdir, rmdir, mknod and rename. - DIRSYNC = unix.MS_DIRSYNC - - // REMOUNT will attempt to remount an already-mounted file system. This is - // commonly used to change the mount flags for a file system, especially to - // make a readonly file system writeable. It does not change device or mount - // point. - REMOUNT = unix.MS_REMOUNT - - // MANDLOCK will force mandatory locks on a filesystem. - MANDLOCK = unix.MS_MANDLOCK - - // NOATIME will not update the file access time when reading from a file. - NOATIME = unix.MS_NOATIME - - // NODIRATIME will not update the directory access time. - NODIRATIME = unix.MS_NODIRATIME - - // BIND remounts a subtree somewhere else. - BIND = unix.MS_BIND - - // RBIND remounts a subtree and all possible submounts somewhere else. - RBIND = unix.MS_BIND | unix.MS_REC - - // UNBINDABLE creates a mount which cannot be cloned through a bind operation. - UNBINDABLE = unix.MS_UNBINDABLE - - // RUNBINDABLE marks the entire mount tree as UNBINDABLE. - RUNBINDABLE = unix.MS_UNBINDABLE | unix.MS_REC - - // PRIVATE creates a mount which carries no propagation abilities. - PRIVATE = unix.MS_PRIVATE - - // RPRIVATE marks the entire mount tree as PRIVATE. - RPRIVATE = unix.MS_PRIVATE | unix.MS_REC - - // SLAVE creates a mount which receives propagation from its master, but not - // vice versa. - SLAVE = unix.MS_SLAVE - - // RSLAVE marks the entire mount tree as SLAVE. - RSLAVE = unix.MS_SLAVE | unix.MS_REC - - // SHARED creates a mount which provides the ability to create mirrors of - // that mount such that mounts and unmounts within any of the mirrors - // propagate to the other mirrors. - SHARED = unix.MS_SHARED - - // RSHARED marks the entire mount tree as SHARED. - RSHARED = unix.MS_SHARED | unix.MS_REC - - // RELATIME updates inode access times relative to modify or change time. - RELATIME = unix.MS_RELATIME - - // STRICTATIME allows to explicitly request full atime updates. This makes - // it possible for the kernel to default to relatime or noatime but still - // allow userspace to override it. - STRICTATIME = unix.MS_STRICTATIME - - mntDetach = unix.MNT_DETACH -) diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -// +build !linux,!freebsd freebsd,!cgo solaris,!cgo - -package mount - -// These flags are unsupported. -const ( - BIND = 0 - DIRSYNC = 0 - MANDLOCK = 0 - NOATIME = 0 - NODEV = 0 - NODIRATIME = 0 - NOEXEC = 0 - NOSUID = 0 - UNBINDABLE = 0 - RUNBINDABLE = 0 - PRIVATE = 0 - RPRIVATE = 0 - SHARED = 0 - RSHARED = 0 - SLAVE = 0 - RSLAVE = 0 - RBIND = 0 - RELATIME = 0 - RELATIVE = 0 - REMOUNT = 0 - STRICTATIME = 0 - SYNCHRONOUS = 0 - RDONLY = 0 - mntDetach = 0 -) diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -package mount - -/* -#include -#include -#include -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "strings" - "unsafe" - - "golang.org/x/sys/unix" -) - -func allocateIOVecs(options []string) []C.struct_iovec { - out := make([]C.struct_iovec, len(options)) - for i, option := range options { - out[i].iov_base = unsafe.Pointer(C.CString(option)) - out[i].iov_len = C.size_t(len(option) + 1) - } - return out -} - -func mount(device, target, mType string, flag uintptr, data string) error { - isNullFS := false - - xs := strings.Split(data, ",") - for _, x := range xs { - if x == "bind" { - isNullFS = true - } - } - - options := []string{"fspath", target} - if isNullFS { - options = append(options, "fstype", "nullfs", "target", device) - } else { - options = append(options, "fstype", mType, "from", device) - } - rawOptions := allocateIOVecs(options) - for _, rawOption := range rawOptions { - defer C.free(rawOption.iov_base) - } - - if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { - reason := C.GoString(C.strerror(*C.__error())) - return fmt.Errorf("Failed to call nmount: %s", reason) - } - return nil -} - -func unmount(target string, flag int) error { - return unix.Unmount(target, flag) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -package mount - -import ( - "golang.org/x/sys/unix" -) - -const ( - // ptypes is the set propagation types. - ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE - - // pflags is the full set valid flags for a change propagation call. - pflags = ptypes | unix.MS_REC | unix.MS_SILENT - - // broflags is the combination of bind and read only - broflags = unix.MS_BIND | unix.MS_RDONLY -) - -// isremount returns true if either device name or flags identify a remount request, false otherwise. -func isremount(device string, flags uintptr) bool { - switch { - // We treat device "" and "none" as a remount request to provide compatibility with - // requests that don't explicitly set MS_REMOUNT such as those manipulating bind mounts. - case flags&unix.MS_REMOUNT != 0, device == "", device == "none": - return true - default: - return false - } -} - -func mount(device, target, mType string, flags uintptr, data string) error { - oflags := flags &^ ptypes - if !isremount(device, flags) || data != "" { - // Initial call applying all non-propagation flags for mount - // or remount with changed data - if err := unix.Mount(device, target, mType, oflags, data); err != nil { - return err - } - } - - if flags&ptypes != 0 { - // Change the propagation type. - if err := unix.Mount("", target, "", flags&pflags, ""); err != nil { - return err - } - } - - if oflags&broflags == broflags { - // Remount the bind to apply read only. - return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "") - } - - return nil -} - -func unmount(target string, flag int) error { - return unix.Unmount(target, flag) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -// +build solaris,cgo - -package mount - -import ( - "unsafe" - - "golang.org/x/sys/unix" -) - -// #include -// #include -// #include -// int Mount(const char *spec, const char *dir, int mflag, -// char *fstype, char *dataptr, int datalen, char *optptr, int optlen) { -// return mount(spec, dir, mflag, fstype, dataptr, datalen, optptr, optlen); -// } -import "C" - -func mount(device, target, mType string, flag uintptr, data string) error { - spec := C.CString(device) - dir := C.CString(target) - fstype := C.CString(mType) - _, err := C.Mount(spec, dir, C.int(flag), fstype, nil, 0, nil, 0) - C.free(unsafe.Pointer(spec)) - C.free(unsafe.Pointer(dir)) - C.free(unsafe.Pointer(fstype)) - return err -} - -func unmount(target string, flag int) error { - err := unix.Unmount(target, flag) - return err -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -// +build !linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo - -package mount - -func mount(device, target, mType string, flag uintptr, data string) error { - panic("Not implemented") -} - -func unmount(target string, flag int) error { - panic("Not implemented") -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mount.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mount.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mount.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mount.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -package mount - -import ( - "sort" - "strings" -) - -// GetMounts retrieves a list of mounts for the current running process. -func GetMounts() ([]*Info, error) { - return parseMountTable() -} - -// Mounted determines if a specified mountpoint has been mounted. -// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. -func Mounted(mountpoint string) (bool, error) { - entries, err := parseMountTable() - if err != nil { - return false, err - } - - // Search the table for the mountpoint - for _, e := range entries { - if e.Mountpoint == mountpoint { - return true, nil - } - } - return false, nil -} - -// Mount will mount filesystem according to the specified configuration, on the -// condition that the target path is *not* already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func Mount(device, target, mType, options string) error { - flag, _ := parseOptions(options) - if flag&REMOUNT != REMOUNT { - if mounted, err := Mounted(target); err != nil || mounted { - return err - } - } - return ForceMount(device, target, mType, options) -} - -// ForceMount will mount a filesystem according to the specified configuration, -// *regardless* if the target path is not already mounted. Options must be -// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See -// flags.go for supported option flags. -func ForceMount(device, target, mType, options string) error { - flag, data := parseOptions(options) - return mount(device, target, mType, uintptr(flag), data) -} - -// Unmount lazily unmounts a filesystem on supported platforms, otherwise -// does a normal unmount. -func Unmount(target string) error { - if mounted, err := Mounted(target); err != nil || !mounted { - return err - } - return unmount(target, mntDetach) -} - -// RecursiveUnmount unmounts the target and all mounts underneath, starting with -// the deepsest mount first. -func RecursiveUnmount(target string) error { - mounts, err := GetMounts() - if err != nil { - return err - } - - // Make the deepest mount be first - sort.Sort(sort.Reverse(byMountpoint(mounts))) - - for i, m := range mounts { - if !strings.HasPrefix(m.Mountpoint, target) { - continue - } - if err := Unmount(m.Mountpoint); err != nil && i == len(mounts)-1 { - if mounted, err := Mounted(m.Mountpoint); err != nil || mounted { - return err - } - // Ignore errors for submounts and continue trying to unmount others - // The final unmount should fail if there ane any submounts remaining - } - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -package mount - -/* -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "reflect" - "unsafe" -) - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from -// bind mounts. -func parseMountTable() ([]*Info, error) { - var rawEntries *C.struct_statfs - - count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) - if count == 0 { - return nil, fmt.Errorf("Failed to call getmntinfo") - } - - var entries []C.struct_statfs - header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) - header.Cap = count - header.Len = count - header.Data = uintptr(unsafe.Pointer(rawEntries)) - - var out []*Info - for _, entry := range entries { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) - mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) - mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) - out = append(out, &mountinfo) - } - return out, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -package mount - -// Info reveals information about a particular mounted filesystem. This -// struct is populated from the content in the /proc//mountinfo file. -type Info struct { - // ID is a unique identifier of the mount (may be reused after umount). - ID int - - // Parent indicates the ID of the mount parent (or of self for the top of the - // mount tree). - Parent int - - // Major indicates one half of the device ID which identifies the device class. - Major int - - // Minor indicates one half of the device ID which identifies a specific - // instance of device. - Minor int - - // Root of the mount within the filesystem. - Root string - - // Mountpoint indicates the mount point relative to the process's root. - Mountpoint string - - // Opts represents mount-specific options. - Opts string - - // Optional represents optional fields. - Optional string - - // Fstype indicates the type of filesystem, such as EXT3. - Fstype string - - // Source indicates filesystem specific information or "none". - Source string - - // VfsOpts represents per super block options. - VfsOpts string -} - -type byMountpoint []*Info - -func (by byMountpoint) Len() int { - return len(by) -} - -func (by byMountpoint) Less(i, j int) bool { - return by[i].Mountpoint < by[j].Mountpoint -} - -func (by byMountpoint) Swap(i, j int) { - by[i], by[j] = by[j], by[i] -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -// +build linux - -package mount - -import ( - "bufio" - "fmt" - "io" - "os" - "strings" -) - -const ( - /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - - (1) mount ID: unique identifier of the mount (may be reused after umount) - (2) parent ID: ID of parent (or of self for the top of the mount tree) - (3) major:minor: value of st_dev for files on filesystem - (4) root: root of the mount within the filesystem - (5) mount point: mount point relative to the process's root - (6) mount options: per mount options - (7) optional fields: zero or more fields of the form "tag[:value]" - (8) separator: marks the end of the optional fields - (9) filesystem type: name of filesystem of the form "type[.subtype]" - (10) mount source: filesystem specific information or "none" - (11) super options: per super block options*/ - mountinfoFormat = "%d %d %d:%d %s %s %s %s" -) - -// Parse /proc/self/mountinfo because comparing Dev and ino does not work from -// bind mounts -func parseMountTable() ([]*Info, error) { - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} - -func parseInfoFile(r io.Reader) ([]*Info, error) { - var ( - s = bufio.NewScanner(r) - out = []*Info{} - ) - - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - - var ( - p = &Info{} - text = s.Text() - optionalFields string - ) - - if _, err := fmt.Sscanf(text, mountinfoFormat, - &p.ID, &p.Parent, &p.Major, &p.Minor, - &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { - return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) - } - // Safe as mountinfo encodes mountpoints with spaces as \040. - index := strings.Index(text, " - ") - postSeparatorFields := strings.Fields(text[index+3:]) - if len(postSeparatorFields) < 3 { - return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) - } - - if optionalFields != "-" { - p.Optional = optionalFields - } - - p.Fstype = postSeparatorFields[0] - p.Source = postSeparatorFields[1] - p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") - out = append(out, p) - } - return out, nil -} - -// PidMountInfo collects the mounts for a specific process ID. If the process -// ID is unknown, it is better to use `GetMounts` which will inspect -// "/proc/self/mountinfo" instead. -func PidMountInfo(pid int) ([]*Info, error) { - f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) - if err != nil { - return nil, err - } - defer f.Close() - - return parseInfoFile(f) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -// +build solaris,cgo - -package mount - -/* -#include -#include -#include -*/ -import "C" - -import ( - "fmt" - "unsafe" -) - -func parseMountTable() ([]*Info, error) { - path := C.CString(C.MNTTAB) - defer C.free(unsafe.Pointer(path)) - mode := C.CString("r") - defer C.free(unsafe.Pointer(mode)) - - mnttab := C.fopen(path, mode) - if mnttab == nil { - return nil, fmt.Errorf("Failed to open %s", C.MNTTAB) - } - - var out []*Info - var mp C.struct_mnttab - - ret := C.getmntent(mnttab, &mp) - for ret == 0 { - var mountinfo Info - mountinfo.Mountpoint = C.GoString(mp.mnt_mountp) - mountinfo.Source = C.GoString(mp.mnt_special) - mountinfo.Fstype = C.GoString(mp.mnt_fstype) - mountinfo.Opts = C.GoString(mp.mnt_mntopts) - out = append(out, &mountinfo) - ret = C.getmntent(mnttab, &mp) - } - - C.fclose(mnttab) - return out, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -// +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo - -package mount - -import ( - "fmt" - "runtime" -) - -func parseMountTable() ([]*Info, error) { - return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -package mount - -func parseMountTable() ([]*Info, error) { - // Do NOT return an error! - return nil, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -// +build linux - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - mounted, err := Mounted(mountPoint) - if err != nil { - return err - } - - if !mounted { - if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { - return err - } - } - if _, err = Mounted(mountPoint); err != nil { - return err - } - - return ForceMount("", mountPoint, "none", options) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -// +build solaris - -package mount - -// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "shared") -} - -// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRShared(mountPoint string) error { - return ensureMountedAs(mountPoint, "rshared") -} - -// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. -// See the supported options in flags.go for further reference. -func MakePrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "private") -} - -// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeRPrivate(mountPoint string) error { - return ensureMountedAs(mountPoint, "rprivate") -} - -// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "slave") -} - -// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. -// See the supported options in flags.go for further reference. -func MakeRSlave(mountPoint string) error { - return ensureMountedAs(mountPoint, "rslave") -} - -// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option -// enabled. See the supported options in flags.go for further reference. -func MakeUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "unbindable") -} - -// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount -// option enabled. See the supported options in flags.go for further reference. -func MakeRUnbindable(mountPoint string) error { - return ensureMountedAs(mountPoint, "runbindable") -} - -func ensureMountedAs(mountPoint, options string) error { - // TODO: Solaris does not support bind mounts. - // Evaluate lofs and also look at the relevant - // mount flags to be supported. - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/README.md containerd-1.5.9/vendor/github.com/docker/docker/pkg/README.md --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -pkg/ is a collection of utility packages used by the Docker project without being specific to its internals. - -Utility packages are kept separate from the docker core codebase to keep it as small and concise as possible. -If some utilities grow larger and their APIs stabilize, they may be moved to their own repository under the -Docker organization, to facilitate re-use by other projects. However that is not the priority. - -The directory `pkg` is named after the same directory in the camlistore project. Since Brad is a core -Go maintainer, we thought it made sense to copy his methods for organizing Go code :) Thanks Brad! - -Because utility packages are small and neatly separated from the rest of the codebase, they are a good -place to start for aspiring maintainers and contributors. Get in touch if you want to help maintain them! diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/README.md containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/README.md --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -This package provides helper functions for dealing with signals across various operating systems \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_darwin.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_darwin.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_darwin.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -package signal - -import ( - "syscall" -) - -// SignalMap is a map of Darwin signals. -var SignalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUG": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CONT": syscall.SIGCONT, - "EMT": syscall.SIGEMT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INFO": syscall.SIGINFO, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "PIPE": syscall.SIGPIPE, - "PROF": syscall.SIGPROF, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -package signal - -import ( - "syscall" -) - -// SignalMap is a map of FreeBSD signals. -var SignalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUF": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CONT": syscall.SIGCONT, - "EMT": syscall.SIGEMT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INFO": syscall.SIGINFO, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "LWP": syscall.SIGLWP, - "PIPE": syscall.SIGPIPE, - "PROF": syscall.SIGPROF, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "THR": syscall.SIGTHR, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -// Package signal provides helper functions for dealing with signals across -// various operating systems. -package signal - -import ( - "fmt" - "os" - "os/signal" - "strconv" - "strings" - "syscall" -) - -// CatchAll catches all signals and relays them to the specified channel. -func CatchAll(sigc chan os.Signal) { - handledSigs := []os.Signal{} - for _, s := range SignalMap { - handledSigs = append(handledSigs, s) - } - signal.Notify(sigc, handledSigs...) -} - -// StopCatch stops catching the signals and closes the specified channel. -func StopCatch(sigc chan os.Signal) { - signal.Stop(sigc) - close(sigc) -} - -// ParseSignal translates a string to a valid syscall signal. -// It returns an error if the signal map doesn't include the given signal. -func ParseSignal(rawSignal string) (syscall.Signal, error) { - s, err := strconv.Atoi(rawSignal) - if err == nil { - if s == 0 { - return -1, fmt.Errorf("Invalid signal: %s", rawSignal) - } - return syscall.Signal(s), nil - } - signal, ok := SignalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")] - if !ok { - return -1, fmt.Errorf("Invalid signal: %s", rawSignal) - } - return signal, nil -} - -// ValidSignalForPlatform returns true if a signal is valid on the platform -func ValidSignalForPlatform(sig syscall.Signal) bool { - for _, v := range SignalMap { - if v == sig { - return true - } - } - return false -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -package signal - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -const ( - sigrtmin = 34 - sigrtmax = 64 -) - -// SignalMap is a map of Linux signals. -var SignalMap = map[string]syscall.Signal{ - "ABRT": unix.SIGABRT, - "ALRM": unix.SIGALRM, - "BUS": unix.SIGBUS, - "CHLD": unix.SIGCHLD, - "CLD": unix.SIGCLD, - "CONT": unix.SIGCONT, - "FPE": unix.SIGFPE, - "HUP": unix.SIGHUP, - "ILL": unix.SIGILL, - "INT": unix.SIGINT, - "IO": unix.SIGIO, - "IOT": unix.SIGIOT, - "KILL": unix.SIGKILL, - "PIPE": unix.SIGPIPE, - "POLL": unix.SIGPOLL, - "PROF": unix.SIGPROF, - "PWR": unix.SIGPWR, - "QUIT": unix.SIGQUIT, - "SEGV": unix.SIGSEGV, - "STKFLT": unix.SIGSTKFLT, - "STOP": unix.SIGSTOP, - "SYS": unix.SIGSYS, - "TERM": unix.SIGTERM, - "TRAP": unix.SIGTRAP, - "TSTP": unix.SIGTSTP, - "TTIN": unix.SIGTTIN, - "TTOU": unix.SIGTTOU, - "URG": unix.SIGURG, - "USR1": unix.SIGUSR1, - "USR2": unix.SIGUSR2, - "VTALRM": unix.SIGVTALRM, - "WINCH": unix.SIGWINCH, - "XCPU": unix.SIGXCPU, - "XFSZ": unix.SIGXFSZ, - "RTMIN": sigrtmin, - "RTMIN+1": sigrtmin + 1, - "RTMIN+2": sigrtmin + 2, - "RTMIN+3": sigrtmin + 3, - "RTMIN+4": sigrtmin + 4, - "RTMIN+5": sigrtmin + 5, - "RTMIN+6": sigrtmin + 6, - "RTMIN+7": sigrtmin + 7, - "RTMIN+8": sigrtmin + 8, - "RTMIN+9": sigrtmin + 9, - "RTMIN+10": sigrtmin + 10, - "RTMIN+11": sigrtmin + 11, - "RTMIN+12": sigrtmin + 12, - "RTMIN+13": sigrtmin + 13, - "RTMIN+14": sigrtmin + 14, - "RTMIN+15": sigrtmin + 15, - "RTMAX-14": sigrtmax - 14, - "RTMAX-13": sigrtmax - 13, - "RTMAX-12": sigrtmax - 12, - "RTMAX-11": sigrtmax - 11, - "RTMAX-10": sigrtmax - 10, - "RTMAX-9": sigrtmax - 9, - "RTMAX-8": sigrtmax - 8, - "RTMAX-7": sigrtmax - 7, - "RTMAX-6": sigrtmax - 6, - "RTMAX-5": sigrtmax - 5, - "RTMAX-4": sigrtmax - 4, - "RTMAX-3": sigrtmax - 3, - "RTMAX-2": sigrtmax - 2, - "RTMAX-1": sigrtmax - 1, - "RTMAX": sigrtmax, -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -package signal - -import ( - "syscall" -) - -// SignalMap is a map of Solaris signals. -// SIGINFO and SIGTHR not defined for Solaris -var SignalMap = map[string]syscall.Signal{ - "ABRT": syscall.SIGABRT, - "ALRM": syscall.SIGALRM, - "BUF": syscall.SIGBUS, - "CHLD": syscall.SIGCHLD, - "CONT": syscall.SIGCONT, - "EMT": syscall.SIGEMT, - "FPE": syscall.SIGFPE, - "HUP": syscall.SIGHUP, - "ILL": syscall.SIGILL, - "INT": syscall.SIGINT, - "IO": syscall.SIGIO, - "IOT": syscall.SIGIOT, - "KILL": syscall.SIGKILL, - "LWP": syscall.SIGLWP, - "PIPE": syscall.SIGPIPE, - "PROF": syscall.SIGPROF, - "QUIT": syscall.SIGQUIT, - "SEGV": syscall.SIGSEGV, - "STOP": syscall.SIGSTOP, - "SYS": syscall.SIGSYS, - "TERM": syscall.SIGTERM, - "TRAP": syscall.SIGTRAP, - "TSTP": syscall.SIGTSTP, - "TTIN": syscall.SIGTTIN, - "TTOU": syscall.SIGTTOU, - "URG": syscall.SIGURG, - "USR1": syscall.SIGUSR1, - "USR2": syscall.SIGUSR2, - "VTALRM": syscall.SIGVTALRM, - "WINCH": syscall.SIGWINCH, - "XCPU": syscall.SIGXCPU, - "XFSZ": syscall.SIGXFSZ, -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -// +build !windows - -package signal - -import ( - "syscall" -) - -// Signals used in cli/command (no windows equivalent, use -// invalid signals so they don't get handled) - -const ( - // SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted. - SIGCHLD = syscall.SIGCHLD - // SIGWINCH is a signal sent to a process when its controlling terminal changes its size - SIGWINCH = syscall.SIGWINCH - // SIGPIPE is a signal sent to a process when a pipe is written to before the other end is open for reading - SIGPIPE = syscall.SIGPIPE - // DefaultStopSignal is the syscall signal used to stop a container in unix systems. - DefaultStopSignal = "SIGTERM" -) diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -// +build !linux,!darwin,!freebsd,!windows,!solaris - -package signal - -import ( - "syscall" -) - -// SignalMap is an empty map of signals for unsupported platform. -var SignalMap = map[string]syscall.Signal{} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/signal_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/signal_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// +build windows - -package signal - -import ( - "syscall" -) - -// Signals used in cli/command (no windows equivalent, use -// invalid signals so they don't get handled) -const ( - SIGCHLD = syscall.Signal(0xff) - SIGWINCH = syscall.Signal(0xff) - SIGPIPE = syscall.Signal(0xff) - // DefaultStopSignal is the syscall signal used to stop a container in windows systems. - DefaultStopSignal = "15" -) - -// SignalMap is a map of "supported" signals. As per the comment in GOLang's -// ztypes_windows.go: "More invented values for signals". Windows doesn't -// really support signals in any way, shape or form that Unix does. -// -// We have these so that docker kill can be used to gracefully (TERM) and -// forcibly (KILL) terminate a container on Windows. -var SignalMap = map[string]syscall.Signal{ - "KILL": syscall.SIGKILL, - "TERM": syscall.SIGTERM, -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/trap.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/trap.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/signal/trap.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/signal/trap.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -package signal - -import ( - "fmt" - "os" - gosignal "os/signal" - "path/filepath" - "runtime" - "strings" - "sync/atomic" - "syscall" - "time" - - "github.com/pkg/errors" -) - -// Trap sets up a simplified signal "trap", appropriate for common -// behavior expected from a vanilla unix command-line tool in general -// (and the Docker engine in particular). -// -// * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated. -// * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is -// skipped and the process is terminated immediately (allows force quit of stuck daemon) -// * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit. -// * Ignore SIGPIPE events. These are generated by systemd when journald is restarted while -// the docker daemon is not restarted and also running under systemd. -// Fixes https://github.com/docker/docker/issues/19728 -// -func Trap(cleanup func(), logger interface { - Info(args ...interface{}) -}) { - c := make(chan os.Signal, 1) - // we will handle INT, TERM, QUIT, SIGPIPE here - signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE} - gosignal.Notify(c, signals...) - go func() { - interruptCount := uint32(0) - for sig := range c { - if sig == syscall.SIGPIPE { - continue - } - - go func(sig os.Signal) { - logger.Info(fmt.Sprintf("Processing signal '%v'", sig)) - switch sig { - case os.Interrupt, syscall.SIGTERM: - if atomic.LoadUint32(&interruptCount) < 3 { - // Initiate the cleanup only once - if atomic.AddUint32(&interruptCount, 1) == 1 { - // Call the provided cleanup handler - cleanup() - os.Exit(0) - } else { - return - } - } else { - // 3 SIGTERM/INT signals received; force exit without cleanup - logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received") - } - case syscall.SIGQUIT: - DumpStacks("") - logger.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT") - } - //for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal # - os.Exit(128 + int(sig.(syscall.Signal))) - }(sig) - } - }() -} - -const stacksLogNameTemplate = "goroutine-stacks-%s.log" - -// DumpStacks appends the runtime stack into file in dir and returns full path -// to that file. -func DumpStacks(dir string) (string, error) { - var ( - buf []byte - stackSize int - ) - bufferLen := 16384 - for stackSize == len(buf) { - buf = make([]byte, bufferLen) - stackSize = runtime.Stack(buf, true) - bufferLen *= 2 - } - buf = buf[:stackSize] - var f *os.File - if dir != "" { - path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1))) - var err error - f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - return "", errors.Wrap(err, "failed to open file to write the goroutine stacks") - } - defer f.Close() - defer f.Sync() - } else { - f = os.Stderr - } - if _, err := f.Write(buf); err != nil { - return "", errors.Wrap(err, "failed to write goroutine stacks") - } - return f.Name(), nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.BSD file. - -// This code is a modified version of path/filepath/symlink.go from the Go standard library. - -package symlink - -import ( - "bytes" - "errors" - "os" - "path/filepath" - "strings" - - "github.com/docker/docker/pkg/system" -) - -// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an -// absolute path. This function handles paths in a platform-agnostic manner. -func FollowSymlinkInScope(path, root string) (string, error) { - path, err := filepath.Abs(filepath.FromSlash(path)) - if err != nil { - return "", err - } - root, err = filepath.Abs(filepath.FromSlash(root)) - if err != nil { - return "", err - } - return evalSymlinksInScope(path, root) -} - -// evalSymlinksInScope will evaluate symlinks in `path` within a scope `root` and return -// a result guaranteed to be contained within the scope `root`, at the time of the call. -// Symlinks in `root` are not evaluated and left as-is. -// Errors encountered while attempting to evaluate symlinks in path will be returned. -// Non-existing paths are valid and do not constitute an error. -// `path` has to contain `root` as a prefix, or else an error will be returned. -// Trying to break out from `root` does not constitute an error. -// -// Example: -// If /foo/bar -> /outside, -// FollowSymlinkInScope("/foo/bar", "/foo") == "/foo/outside" instead of "/outside" -// -// IMPORTANT: it is the caller's responsibility to call evalSymlinksInScope *after* relevant symlinks -// are created and not to create subsequently, additional symlinks that could potentially make a -// previously-safe path, unsafe. Example: if /foo/bar does not exist, evalSymlinksInScope("/foo/bar", "/foo") -// would return "/foo/bar". If one makes /foo/bar a symlink to /baz subsequently, then "/foo/bar" should -// no longer be considered safely contained in "/foo". -func evalSymlinksInScope(path, root string) (string, error) { - root = filepath.Clean(root) - if path == root { - return path, nil - } - if !strings.HasPrefix(path, root) { - return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root) - } - const maxIter = 255 - originalPath := path - // given root of "/a" and path of "/a/b/../../c" we want path to be "/b/../../c" - path = path[len(root):] - if root == string(filepath.Separator) { - path = string(filepath.Separator) + path - } - if !strings.HasPrefix(path, string(filepath.Separator)) { - return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root) - } - path = filepath.Clean(path) - // consume path by taking each frontmost path element, - // expanding it if it's a symlink, and appending it to b - var b bytes.Buffer - // b here will always be considered to be the "current absolute path inside - // root" when we append paths to it, we also append a slash and use - // filepath.Clean after the loop to trim the trailing slash - for n := 0; path != ""; n++ { - if n > maxIter { - return "", errors.New("evalSymlinksInScope: too many links in " + originalPath) - } - - // find next path component, p - i := strings.IndexRune(path, filepath.Separator) - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } - - if p == "" { - continue - } - - // this takes a b.String() like "b/../" and a p like "c" and turns it - // into "/b/../c" which then gets filepath.Cleaned into "/c" and then - // root gets prepended and we Clean again (to remove any trailing slash - // if the first Clean gave us just "/") - cleanP := filepath.Clean(string(filepath.Separator) + b.String() + p) - if isDriveOrRoot(cleanP) { - // never Lstat "/" itself, or drive letters on Windows - b.Reset() - continue - } - fullP := filepath.Clean(root + cleanP) - - fi, err := os.Lstat(fullP) - if os.IsNotExist(err) { - // if p does not exist, accept it - b.WriteString(p) - b.WriteRune(filepath.Separator) - continue - } - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p) - b.WriteRune(filepath.Separator) - continue - } - - // it's a symlink, put it at the front of path - dest, err := os.Readlink(fullP) - if err != nil { - return "", err - } - if system.IsAbs(dest) { - b.Reset() - } - path = dest + string(filepath.Separator) + path - } - - // see note above on "fullP := ..." for why this is double-cleaned and - // what's happening here - return filepath.Clean(root + filepath.Clean(string(filepath.Separator)+b.String())), nil -} - -// EvalSymlinks returns the path name after the evaluation of any symbolic -// links. -// If path is relative the result will be relative to the current directory, -// unless one of the components is an absolute symbolic link. -// This version has been updated to support long paths prepended with `\\?\`. -func EvalSymlinks(path string) (string, error) { - return evalSymlinks(path) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -// +build !windows - -package symlink - -import ( - "path/filepath" -) - -func evalSymlinks(path string) (string, error) { - return filepath.EvalSymlinks(path) -} - -func isDriveOrRoot(p string) bool { - return p == string(filepath.Separator) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -package symlink - -import ( - "bytes" - "errors" - "os" - "path/filepath" - "strings" - - "github.com/docker/docker/pkg/longpath" - "golang.org/x/sys/windows" -) - -func toShort(path string) (string, error) { - p, err := windows.UTF16FromString(path) - if err != nil { - return "", err - } - b := p // GetShortPathName says we can reuse buffer - n, err := windows.GetShortPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - if n > uint32(len(b)) { - b = make([]uint16, n) - if _, err = windows.GetShortPathName(&p[0], &b[0], uint32(len(b))); err != nil { - return "", err - } - } - return windows.UTF16ToString(b), nil -} - -func toLong(path string) (string, error) { - p, err := windows.UTF16FromString(path) - if err != nil { - return "", err - } - b := p // GetLongPathName says we can reuse buffer - n, err := windows.GetLongPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - if n > uint32(len(b)) { - b = make([]uint16, n) - n, err = windows.GetLongPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - } - b = b[:n] - return windows.UTF16ToString(b), nil -} - -func evalSymlinks(path string) (string, error) { - path, err := walkSymlinks(path) - if err != nil { - return "", err - } - - p, err := toShort(path) - if err != nil { - return "", err - } - p, err = toLong(p) - if err != nil { - return "", err - } - // windows.GetLongPathName does not change the case of the drive letter, - // but the result of EvalSymlinks must be unique, so we have - // EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`). - // Make drive letter upper case. - if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' { - p = string(p[0]+'A'-'a') + p[1:] - } else if len(p) >= 6 && p[5] == ':' && 'a' <= p[4] && p[4] <= 'z' { - p = p[:3] + string(p[4]+'A'-'a') + p[5:] - } - return filepath.Clean(p), nil -} - -const utf8RuneSelf = 0x80 - -func walkSymlinks(path string) (string, error) { - const maxIter = 255 - originalPath := path - // consume path by taking each frontmost path element, - // expanding it if it's a symlink, and appending it to b - var b bytes.Buffer - for n := 0; path != ""; n++ { - if n > maxIter { - return "", errors.New("EvalSymlinks: too many links in " + originalPath) - } - - // A path beginning with `\\?\` represents the root, so automatically - // skip that part and begin processing the next segment. - if strings.HasPrefix(path, longpath.Prefix) { - b.WriteString(longpath.Prefix) - path = path[4:] - continue - } - - // find next path component, p - var i = -1 - for j, c := range path { - if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) { - i = j - break - } - } - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } - - if p == "" { - if b.Len() == 0 { - // must be absolute path - b.WriteRune(filepath.Separator) - } - continue - } - - // If this is the first segment after the long path prefix, accept the - // current segment as a volume root or UNC share and move on to the next. - if b.String() == longpath.Prefix { - b.WriteString(p) - b.WriteRune(filepath.Separator) - continue - } - - fi, err := os.Lstat(b.String() + p) - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p) - if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') { - b.WriteRune(filepath.Separator) - } - continue - } - - // it's a symlink, put it at the front of path - dest, err := os.Readlink(b.String() + p) - if err != nil { - return "", err - } - if filepath.IsAbs(dest) || os.IsPathSeparator(dest[0]) { - b.Reset() - } - path = dest + string(filepath.Separator) + path - } - return filepath.Clean(b.String()), nil -} - -func isDriveOrRoot(p string) bool { - if p == string(filepath.Separator) { - return true - } - - length := len(p) - if length >= 2 { - if p[length-1] == ':' && (('a' <= p[length-2] && p[length-2] <= 'z') || ('A' <= p[length-2] && p[length-2] <= 'Z')) { - return true - } - } - return false -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2014-2017 Docker, Inc. - - 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. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -Copyright (c) 2014-2017 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/README.md containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/README.md --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/symlink/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/symlink/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -Package symlink implements EvalSymlinksInScope which is an extension of filepath.EvalSymlinks, -as well as a Windows long-path aware version of filepath.EvalSymlinks -from the [Go standard library](https://golang.org/pkg/path/filepath). - -The code from filepath.EvalSymlinks has been adapted in fs.go. -Please read the LICENSE.BSD file that governs fs.go and LICENSE.APACHE for fs_test.go. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -package system - -import ( - "os" - "time" -) - -// Chtimes changes the access time and modified time of a file at the given path -func Chtimes(name string, atime time.Time, mtime time.Time) error { - unixMinTime := time.Unix(0, 0) - unixMaxTime := maxTime - - // If the modified time is prior to the Unix Epoch, or after the - // end of Unix Time, os.Chtimes has undefined behavior - // default to Unix Epoch in this case, just in case - - if atime.Before(unixMinTime) || atime.After(unixMaxTime) { - atime = unixMinTime - } - - if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) { - mtime = unixMinTime - } - - if err := os.Chtimes(name, atime, mtime); err != nil { - return err - } - - // Take platform specific action for setting create time. - if err := setCTime(name, mtime); err != nil { - return err - } - - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -// +build !windows - -package system - -import ( - "time" -) - -//setCTime will set the create time on a file. On Unix, the create -//time is updated as a side effect of setting the modified time, so -//no action is required. -func setCTime(path string, ctime time.Time) error { - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/chtimes_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -// +build windows - -package system - -import ( - "time" - - "golang.org/x/sys/windows" -) - -//setCTime will set the create time on a file. On Windows, this requires -//calling SetFileTime and explicitly including the create time. -func setCTime(path string, ctime time.Time) error { - ctimespec := windows.NsecToTimespec(ctime.UnixNano()) - pathp, e := windows.UTF16PtrFromString(path) - if e != nil { - return e - } - h, e := windows.CreateFile(pathp, - windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil, - windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0) - if e != nil { - return e - } - defer windows.Close(h) - c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec)) - return windows.SetFileTime(h, &c, nil, nil) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/errors.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/errors.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/errors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/errors.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -package system - -import ( - "errors" -) - -var ( - // ErrNotSupportedPlatform means the platform is not supported. - ErrNotSupportedPlatform = errors.New("platform and architecture is not supported") -) diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/exitcode.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/exitcode.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/exitcode.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/exitcode.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -package system - -import ( - "fmt" - "os/exec" - "syscall" -) - -// GetExitCode returns the ExitStatus of the specified error if its type is -// exec.ExitError, returns 0 and an error otherwise. -func GetExitCode(err error) (int, error) { - exitCode := 0 - if exiterr, ok := err.(*exec.ExitError); ok { - if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { - return procExit.ExitStatus(), nil - } - } - return exitCode, fmt.Errorf("failed to get exit code") -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/filesys.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/filesys.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/filesys.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/filesys.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -// +build !windows - -package system - -import ( - "io/ioutil" - "os" - "path/filepath" -) - -// MkdirAllWithACL is a wrapper for MkdirAll on unix systems. -func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { - return MkdirAll(path, perm, sddl) -} - -// MkdirAll creates a directory named path along with any necessary parents, -// with permission specified by attribute perm for all dir created. -func MkdirAll(path string, perm os.FileMode, sddl string) error { - return os.MkdirAll(path, perm) -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. -func IsAbs(path string) bool { - return filepath.IsAbs(path) -} - -// The functions below here are wrappers for the equivalents in the os and ioutils packages. -// They are passthrough on Unix platforms, and only relevant on Windows. - -// CreateSequential creates the named file with mode 0666 (before umask), truncating -// it if it already exists. If successful, methods on the returned -// File can be used for I/O; the associated file descriptor has mode -// O_RDWR. -// If there is an error, it will be of type *PathError. -func CreateSequential(name string) (*os.File, error) { - return os.Create(name) -} - -// OpenSequential opens the named file for reading. If successful, methods on -// the returned file can be used for reading; the associated file -// descriptor has mode O_RDONLY. -// If there is an error, it will be of type *PathError. -func OpenSequential(name string) (*os.File, error) { - return os.Open(name) -} - -// OpenFileSequential is the generalized open call; most users will use Open -// or Create instead. It opens the named file with specified flag -// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, -// methods on the returned File can be used for I/O. -// If there is an error, it will be of type *PathError. -func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) { - return os.OpenFile(name, flag, perm) -} - -// TempFileSequential creates a new temporary file in the directory dir -// with a name beginning with prefix, opens the file for reading -// and writing, and returns the resulting *os.File. -// If dir is the empty string, TempFile uses the default directory -// for temporary files (see os.TempDir). -// Multiple programs calling TempFile simultaneously -// will not choose the same file. The caller can use f.Name() -// to find the pathname of the file. It is the caller's responsibility -// to remove the file when no longer needed. -func TempFileSequential(dir, prefix string) (f *os.File, err error) { - return ioutil.TempFile(dir, prefix) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/filesys_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/filesys_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/filesys_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/filesys_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,298 +0,0 @@ -// +build windows - -package system - -import ( - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "sync" - "syscall" - "time" - "unsafe" - - winio "github.com/Microsoft/go-winio" - "golang.org/x/sys/windows" -) - -const ( - // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System - SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" - // SddlNtvmAdministratorsLocalSystem is NT VIRTUAL MACHINE\Virtual Machines plus local administrators plus NT AUTHORITY\System - SddlNtvmAdministratorsLocalSystem = "D:P(A;OICI;GA;;;S-1-5-83-0)(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" -) - -// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory -// with an appropriate SDDL defined ACL. -func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { - return mkdirall(path, true, sddl) -} - -// MkdirAll implementation that is volume path aware for Windows. -func MkdirAll(path string, _ os.FileMode, sddl string) error { - return mkdirall(path, false, sddl) -} - -// mkdirall is a custom version of os.MkdirAll modified for use on Windows -// so that it is both volume path aware, and can create a directory with -// a DACL. -func mkdirall(path string, applyACL bool, sddl string) error { - if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { - return nil - } - - // The rest of this method is largely copied from os.MkdirAll and should be kept - // as-is to ensure compatibility. - - // Fast path: if we can tell whether path is a directory or file, stop with success or error. - dir, err := os.Stat(path) - if err == nil { - if dir.IsDir() { - return nil - } - return &os.PathError{ - Op: "mkdir", - Path: path, - Err: syscall.ENOTDIR, - } - } - - // Slow path: make sure parent exists and then call Mkdir for path. - i := len(path) - for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. - i-- - } - - j := i - for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. - j-- - } - - if j > 1 { - // Create parent - err = mkdirall(path[0:j-1], false, sddl) - if err != nil { - return err - } - } - - // Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result. - if applyACL { - err = mkdirWithACL(path, sddl) - } else { - err = os.Mkdir(path, 0) - } - - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := os.Lstat(path) - if err1 == nil && dir.IsDir() { - return nil - } - return err - } - return nil -} - -// mkdirWithACL creates a new directory. If there is an error, it will be of -// type *PathError. . -// -// This is a modified and combined version of os.Mkdir and windows.Mkdir -// in golang to cater for creating a directory am ACL permitting full -// access, with inheritance, to any subfolder/file for Built-in Administrators -// and Local System. -func mkdirWithACL(name string, sddl string) error { - sa := windows.SecurityAttributes{Length: 0} - sd, err := winio.SddlToSecurityDescriptor(sddl) - if err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - sa.SecurityDescriptor = uintptr(unsafe.Pointer(&sd[0])) - - namep, err := windows.UTF16PtrFromString(name) - if err != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: err} - } - - e := windows.CreateDirectory(namep, &sa) - if e != nil { - return &os.PathError{Op: "mkdir", Path: name, Err: e} - } - return nil -} - -// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows, -// golang filepath.IsAbs does not consider a path \windows\system32 as absolute -// as it doesn't start with a drive-letter/colon combination. However, in -// docker we need to verify things such as WORKDIR /windows/system32 in -// a Dockerfile (which gets translated to \windows\system32 when being processed -// by the daemon. This SHOULD be treated as absolute from a docker processing -// perspective. -func IsAbs(path string) bool { - if !filepath.IsAbs(path) { - if !strings.HasPrefix(path, string(os.PathSeparator)) { - return false - } - } - return true -} - -// The origin of the functions below here are the golang OS and windows packages, -// slightly modified to only cope with files, not directories due to the -// specific use case. -// -// The alteration is to allow a file on Windows to be opened with -// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating -// the standby list, particularly when accessing large files such as layer.tar. - -// CreateSequential creates the named file with mode 0666 (before umask), truncating -// it if it already exists. If successful, methods on the returned -// File can be used for I/O; the associated file descriptor has mode -// O_RDWR. -// If there is an error, it will be of type *PathError. -func CreateSequential(name string) (*os.File, error) { - return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0) -} - -// OpenSequential opens the named file for reading. If successful, methods on -// the returned file can be used for reading; the associated file -// descriptor has mode O_RDONLY. -// If there is an error, it will be of type *PathError. -func OpenSequential(name string) (*os.File, error) { - return OpenFileSequential(name, os.O_RDONLY, 0) -} - -// OpenFileSequential is the generalized open call; most users will use Open -// or Create instead. -// If there is an error, it will be of type *PathError. -func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) { - if name == "" { - return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT} - } - r, errf := windowsOpenFileSequential(name, flag, 0) - if errf == nil { - return r, nil - } - return nil, &os.PathError{Op: "open", Path: name, Err: errf} -} - -func windowsOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) { - r, e := windowsOpenSequential(name, flag|windows.O_CLOEXEC, 0) - if e != nil { - return nil, e - } - return os.NewFile(uintptr(r), name), nil -} - -func makeInheritSa() *windows.SecurityAttributes { - var sa windows.SecurityAttributes - sa.Length = uint32(unsafe.Sizeof(sa)) - sa.InheritHandle = 1 - return &sa -} - -func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) { - if len(path) == 0 { - return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND - } - pathp, err := windows.UTF16PtrFromString(path) - if err != nil { - return windows.InvalidHandle, err - } - var access uint32 - switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) { - case windows.O_RDONLY: - access = windows.GENERIC_READ - case windows.O_WRONLY: - access = windows.GENERIC_WRITE - case windows.O_RDWR: - access = windows.GENERIC_READ | windows.GENERIC_WRITE - } - if mode&windows.O_CREAT != 0 { - access |= windows.GENERIC_WRITE - } - if mode&windows.O_APPEND != 0 { - access &^= windows.GENERIC_WRITE - access |= windows.FILE_APPEND_DATA - } - sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE) - var sa *windows.SecurityAttributes - if mode&windows.O_CLOEXEC == 0 { - sa = makeInheritSa() - } - var createmode uint32 - switch { - case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL): - createmode = windows.CREATE_NEW - case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC): - createmode = windows.CREATE_ALWAYS - case mode&windows.O_CREAT == windows.O_CREAT: - createmode = windows.OPEN_ALWAYS - case mode&windows.O_TRUNC == windows.O_TRUNC: - createmode = windows.TRUNCATE_EXISTING - default: - createmode = windows.OPEN_EXISTING - } - // Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang. - //https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx - const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN - h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0) - return h, e -} - -// Helpers for TempFileSequential -var rand uint32 -var randmu sync.Mutex - -func reseed() uint32 { - return uint32(time.Now().UnixNano() + int64(os.Getpid())) -} -func nextSuffix() string { - randmu.Lock() - r := rand - if r == 0 { - r = reseed() - } - r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r - randmu.Unlock() - return strconv.Itoa(int(1e9 + r%1e9))[1:] -} - -// TempFileSequential is a copy of ioutil.TempFile, modified to use sequential -// file access. Below is the original comment from golang: -// TempFile creates a new temporary file in the directory dir -// with a name beginning with prefix, opens the file for reading -// and writing, and returns the resulting *os.File. -// If dir is the empty string, TempFile uses the default directory -// for temporary files (see os.TempDir). -// Multiple programs calling TempFile simultaneously -// will not choose the same file. The caller can use f.Name() -// to find the pathname of the file. It is the caller's responsibility -// to remove the file when no longer needed. -func TempFileSequential(dir, prefix string) (f *os.File, err error) { - if dir == "" { - dir = os.TempDir() - } - - nconflict := 0 - for i := 0; i < 10000; i++ { - name := filepath.Join(dir, prefix+nextSuffix()) - f, err = OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) - if os.IsExist(err) { - if nconflict++; nconflict > 10 { - randmu.Lock() - rand = reseed() - randmu.Unlock() - } - continue - } - break - } - return -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -package system - -import ( - "syscall" - "time" - "unsafe" -) - -// Used by chtimes -var maxTime time.Time - -func init() { - // chtimes initialization - if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { - // This is a 64 bit timespec - // os.Chtimes limits time to the following - maxTime = time.Unix(0, 1<<63-1) - } else { - // This is a 32 bit timespec - maxTime = time.Unix(1<<31-1, 0) - } -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -// +build !windows - -package system - -// InitLCOW does nothing since LCOW is a windows only feature -func InitLCOW(experimental bool) { -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/init_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/init_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -package system - -import "os" - -// lcowSupported determines if Linux Containers on Windows are supported. -var lcowSupported = false - -// InitLCOW sets whether LCOW is supported or not -// TODO @jhowardmsft. -// 1. Replace with RS3 RTM build number. -// 2. Remove the getenv check when image-store is coalesced as shouldn't be needed anymore. -func InitLCOW(experimental bool) { - v := GetOSVersion() - if experimental && v.Build > 16270 && os.Getenv("LCOW_SUPPORTED") != "" { - lcowSupported = true - } -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -package system - -import ( - "fmt" - "runtime" - "strings" - - specs "github.com/opencontainers/image-spec/specs-go/v1" -) - -// ValidatePlatform determines if a platform structure is valid. -// TODO This is a temporary function - can be replaced by parsing from -// https://github.com/containerd/containerd/pull/1403/files at a later date. -// @jhowardmsft -func ValidatePlatform(platform *specs.Platform) error { - platform.Architecture = strings.ToLower(platform.Architecture) - platform.OS = strings.ToLower(platform.OS) - // Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do - // not support anything except operating system. - if platform.Architecture != "" { - return fmt.Errorf("invalid platform architecture %q", platform.Architecture) - } - if platform.OS != "" { - if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { - return fmt.Errorf("invalid platform os %q", platform.OS) - } - } - if len(platform.OSFeatures) != 0 { - return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures) - } - if platform.OSVersion != "" { - return fmt.Errorf("invalid platform osversion %q", platform.OSVersion) - } - if platform.Variant != "" { - return fmt.Errorf("invalid platform variant %q", platform.Variant) - } - return nil -} - -// ParsePlatform parses a platform string in the format os[/arch[/variant] -// into an OCI image-spec platform structure. -// TODO This is a temporary function - can be replaced by parsing from -// https://github.com/containerd/containerd/pull/1403/files at a later date. -// @jhowardmsft -func ParsePlatform(in string) *specs.Platform { - p := &specs.Platform{} - elements := strings.SplitN(strings.ToLower(in), "/", 3) - if len(elements) == 3 { - p.Variant = elements[2] - } - if len(elements) >= 2 { - p.Architecture = elements[1] - } - if len(elements) >= 1 { - p.OS = elements[0] - } - return p -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -// +build !windows - -package system - -// LCOWSupported returns true if Linux containers on Windows are supported. -func LCOWSupported() bool { - return false -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lcow_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lcow_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -package system - -// LCOWSupported returns true if Linux containers on Windows are supported. -func LCOWSupported() bool { - return lcowSupported -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lstat_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lstat_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lstat_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lstat_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -// +build !windows - -package system - -import ( - "syscall" -) - -// Lstat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Lstat(path string) (*StatT, error) { - s := &syscall.Stat_t{} - if err := syscall.Lstat(path, s); err != nil { - return nil, err - } - return fromStatT(s) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lstat_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lstat_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/lstat_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/lstat_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -package system - -import "os" - -// Lstat calls os.Lstat to get a fileinfo interface back. -// This is then copied into our own locally defined structure. -func Lstat(path string) (*StatT, error) { - fi, err := os.Lstat(path) - if err != nil { - return nil, err - } - - return fromStatT(&fi) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -package system - -// MemInfo contains memory statistics of the host system. -type MemInfo struct { - // Total usable RAM (i.e. physical RAM minus a few reserved bits and the - // kernel binary code). - MemTotal int64 - - // Amount of free memory. - MemFree int64 - - // Total amount of swap space available. - SwapTotal int64 - - // Amount of swap space that is currently unused. - SwapFree int64 -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -package system - -import ( - "bufio" - "io" - "os" - "strconv" - "strings" - - "github.com/docker/go-units" -) - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - file, err := os.Open("/proc/meminfo") - if err != nil { - return nil, err - } - defer file.Close() - return parseMemInfo(file) -} - -// parseMemInfo parses the /proc/meminfo file into -// a MemInfo object given an io.Reader to the file. -// Throws error if there are problems reading from the file -func parseMemInfo(reader io.Reader) (*MemInfo, error) { - meminfo := &MemInfo{} - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - // Expected format: ["MemTotal:", "1234", "kB"] - parts := strings.Fields(scanner.Text()) - - // Sanity checks: Skip malformed entries. - if len(parts) < 3 || parts[2] != "kB" { - continue - } - - // Convert to bytes. - size, err := strconv.Atoi(parts[1]) - if err != nil { - continue - } - bytes := int64(size) * units.KiB - - switch parts[0] { - case "MemTotal:": - meminfo.MemTotal = bytes - case "MemFree:": - meminfo.MemFree = bytes - case "SwapTotal:": - meminfo.SwapTotal = bytes - case "SwapFree:": - meminfo.SwapFree = bytes - } - - } - - // Handle errors that may have occurred during the reading of the file. - if err := scanner.Err(); err != nil { - return nil, err - } - - return meminfo, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -// +build solaris,cgo - -package system - -import ( - "fmt" - "unsafe" -) - -// #cgo CFLAGS: -std=c99 -// #cgo LDFLAGS: -lkstat -// #include -// #include -// #include -// #include -// #include -// #include -// struct swaptable *allocSwaptable(int num) { -// struct swaptable *st; -// struct swapent *swapent; -// st = (struct swaptable *)malloc(num * sizeof(swapent_t) + sizeof (int)); -// swapent = st->swt_ent; -// for (int i = 0; i < num; i++,swapent++) { -// swapent->ste_path = (char *)malloc(MAXPATHLEN * sizeof (char)); -// } -// st->swt_n = num; -// return st; -//} -// void freeSwaptable (struct swaptable *st) { -// struct swapent *swapent = st->swt_ent; -// for (int i = 0; i < st->swt_n; i++,swapent++) { -// free(swapent->ste_path); -// } -// free(st); -// } -// swapent_t getSwapEnt(swapent_t *ent, int i) { -// return ent[i]; -// } -// int64_t getPpKernel() { -// int64_t pp_kernel = 0; -// kstat_ctl_t *ksc; -// kstat_t *ks; -// kstat_named_t *knp; -// kid_t kid; -// -// if ((ksc = kstat_open()) == NULL) { -// return -1; -// } -// if ((ks = kstat_lookup(ksc, "unix", 0, "system_pages")) == NULL) { -// return -1; -// } -// if (((kid = kstat_read(ksc, ks, NULL)) == -1) || -// ((knp = kstat_data_lookup(ks, "pp_kernel")) == NULL)) { -// return -1; -// } -// switch (knp->data_type) { -// case KSTAT_DATA_UINT64: -// pp_kernel = knp->value.ui64; -// break; -// case KSTAT_DATA_UINT32: -// pp_kernel = knp->value.ui32; -// break; -// } -// pp_kernel *= sysconf(_SC_PAGESIZE); -// return (pp_kernel > 0 ? pp_kernel : -1); -// } -import "C" - -// Get the system memory info using sysconf same as prtconf -func getTotalMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_PHYS_PAGES) - return int64(pagesize * npages) -} - -func getFreeMem() int64 { - pagesize := C.sysconf(C._SC_PAGESIZE) - npages := C.sysconf(C._SC_AVPHYS_PAGES) - return int64(pagesize * npages) -} - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - - ppKernel := C.getPpKernel() - MemTotal := getTotalMem() - MemFree := getFreeMem() - SwapTotal, SwapFree, err := getSysSwap() - - if ppKernel < 0 || MemTotal < 0 || MemFree < 0 || SwapTotal < 0 || - SwapFree < 0 { - return nil, fmt.Errorf("error getting system memory info %v\n", err) - } - - meminfo := &MemInfo{} - // Total memory is total physical memory less than memory locked by kernel - meminfo.MemTotal = MemTotal - int64(ppKernel) - meminfo.MemFree = MemFree - meminfo.SwapTotal = SwapTotal - meminfo.SwapFree = SwapFree - - return meminfo, nil -} - -func getSysSwap() (int64, int64, error) { - var tSwap int64 - var fSwap int64 - var diskblksPerPage int64 - num, err := C.swapctl(C.SC_GETNSWP, nil) - if err != nil { - return -1, -1, err - } - st := C.allocSwaptable(num) - _, err = C.swapctl(C.SC_LIST, unsafe.Pointer(st)) - if err != nil { - C.freeSwaptable(st) - return -1, -1, err - } - - diskblksPerPage = int64(C.sysconf(C._SC_PAGESIZE) >> C.DEV_BSHIFT) - for i := 0; i < int(num); i++ { - swapent := C.getSwapEnt(&st.swt_ent[0], C.int(i)) - tSwap += int64(swapent.ste_pages) * diskblksPerPage - fSwap += int64(swapent.ste_free) * diskblksPerPage - } - C.freeSwaptable(st) - return tSwap, fSwap, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -// +build !linux,!windows,!solaris - -package system - -// ReadMemInfo is not supported on platforms other than linux and windows. -func ReadMemInfo() (*MemInfo, error) { - return nil, ErrNotSupportedPlatform -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/meminfo_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -package system - -import ( - "unsafe" - - "golang.org/x/sys/windows" -) - -var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - - procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") -) - -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx -// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx -type memorystatusex struct { - dwLength uint32 - dwMemoryLoad uint32 - ullTotalPhys uint64 - ullAvailPhys uint64 - ullTotalPageFile uint64 - ullAvailPageFile uint64 - ullTotalVirtual uint64 - ullAvailVirtual uint64 - ullAvailExtendedVirtual uint64 -} - -// ReadMemInfo retrieves memory statistics of the host system and returns a -// MemInfo type. -func ReadMemInfo() (*MemInfo, error) { - msi := &memorystatusex{ - dwLength: 64, - } - r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi))) - if r1 == 0 { - return &MemInfo{}, nil - } - return &MemInfo{ - MemTotal: int64(msi.ullTotalPhys), - MemFree: int64(msi.ullAvailPhys), - SwapTotal: int64(msi.ullTotalPageFile), - SwapFree: int64(msi.ullAvailPageFile), - }, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/mknod.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/mknod.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/mknod.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/mknod.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -// +build !windows - -package system - -import ( - "golang.org/x/sys/unix" -) - -// Mknod creates a filesystem node (file, device special file or named pipe) named path -// with attributes specified by mode and dev. -func Mknod(path string, mode uint32, dev int) error { - return unix.Mknod(path, mode, dev) -} - -// Mkdev is used to build the value of linux devices (in /dev/) which specifies major -// and minor number of the newly created device special file. -// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. -// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, -// then the top 12 bits of the minor. -func Mkdev(major int64, minor int64) uint32 { - return uint32(unix.Mkdev(uint32(major), uint32(minor))) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/mknod_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/mknod_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/mknod_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/mknod_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -// +build windows - -package system - -// Mknod is not implemented on Windows. -func Mknod(path string, mode uint32, dev int) error { - return ErrNotSupportedPlatform -} - -// Mkdev is not implemented on Windows. -func Mkdev(major int64, minor int64) uint32 { - panic("Mkdev not implemented on Windows.") -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/path.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/path.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/path.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/path.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -package system - -import ( - "fmt" - "path/filepath" - "runtime" - "strings" - - "github.com/containerd/continuity/pathdriver" -) - -const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - -// DefaultPathEnv is unix style list of directories to search for -// executables. Each directory is separated from the next by a colon -// ':' character . -func DefaultPathEnv(os string) string { - if runtime.GOOS == "windows" { - if os != runtime.GOOS { - return defaultUnixPathEnv - } - // Deliberately empty on Windows containers on Windows as the default path will be set by - // the container. Docker has no context of what the default path should be. - return "" - } - return defaultUnixPathEnv - -} - -// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, -// is the system drive. -// On Linux: this is a no-op. -// On Windows: this does the following> -// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. -// This is used, for example, when validating a user provided path in docker cp. -// If a drive letter is supplied, it must be the system drive. The drive letter -// is always removed. Also, it translates it to OS semantics (IOW / to \). We -// need the path in this syntax so that it can ultimately be contatenated with -// a Windows long-path which doesn't support drive-letters. Examples: -// C: --> Fail -// C:\ --> \ -// a --> a -// /a --> \a -// d:\ --> Fail -func CheckSystemDriveAndRemoveDriveLetter(path string, driver pathdriver.PathDriver) (string, error) { - if runtime.GOOS != "windows" || LCOWSupported() { - return path, nil - } - - if len(path) == 2 && string(path[1]) == ":" { - return "", fmt.Errorf("No relative path specified in %q", path) - } - if !driver.IsAbs(path) || len(path) < 2 { - return filepath.FromSlash(path), nil - } - if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { - return "", fmt.Errorf("The specified path is not on the system drive (C:)") - } - return filepath.FromSlash(path[2:]), nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/process_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/process_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/process_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/process_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -// +build linux freebsd solaris darwin - -package system - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -// IsProcessAlive returns true if process with a given pid is running. -func IsProcessAlive(pid int) bool { - err := unix.Kill(pid, syscall.Signal(0)) - if err == nil || err == unix.EPERM { - return true - } - - return false -} - -// KillProcess force-stops a process. -func KillProcess(pid int) { - unix.Kill(pid, unix.SIGKILL) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/rm.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/rm.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/rm.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/rm.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -package system - -import ( - "os" - "syscall" - "time" - - "github.com/docker/docker/pkg/mount" - "github.com/pkg/errors" -) - -// EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can -// often be remedied. -// Only use `EnsureRemoveAll` if you really want to make every effort to remove -// a directory. -// -// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there -// can be a race between reading directory entries and then actually attempting -// to remove everything in the directory. -// These types of errors do not need to be returned since it's ok for the dir to -// be gone we can just retry the remove operation. -// -// This should not return a `os.ErrNotExist` kind of error under any circumstances -func EnsureRemoveAll(dir string) error { - notExistErr := make(map[string]bool) - - // track retries - exitOnErr := make(map[string]int) - maxRetry := 5 - - // Attempt to unmount anything beneath this dir first - mount.RecursiveUnmount(dir) - - for { - err := os.RemoveAll(dir) - if err == nil { - return err - } - - pe, ok := err.(*os.PathError) - if !ok { - return err - } - - if os.IsNotExist(err) { - if notExistErr[pe.Path] { - return err - } - notExistErr[pe.Path] = true - - // There is a race where some subdir can be removed but after the parent - // dir entries have been read. - // So the path could be from `os.Remove(subdir)` - // If the reported non-existent path is not the passed in `dir` we - // should just retry, but otherwise return with no error. - if pe.Path == dir { - return nil - } - continue - } - - if pe.Err != syscall.EBUSY { - return err - } - - if mounted, _ := mount.Mounted(pe.Path); mounted { - if e := mount.Unmount(pe.Path); e != nil { - if mounted, _ := mount.Mounted(pe.Path); mounted { - return errors.Wrapf(e, "error while removing %s", dir) - } - } - } - - if exitOnErr[pe.Path] == maxRetry { - return err - } - exitOnErr[pe.Path]++ - time.Sleep(100 * time.Millisecond) - } -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_darwin.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_darwin.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_darwin.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtimespec}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtimespec}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: s.Mode, - uid: s.Uid, - gid: s.Gid, - rdev: s.Rdev, - mtim: s.Mtim}, nil -} - -// FromStatT converts a syscall.Stat_t type to a system.Stat_t type -// This is exposed on Linux as pkg/archive/changes uses it. -func FromStatT(s *syscall.Stat_t) (*StatT, error) { - return fromStatT(s) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_openbsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtim}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_solaris.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_solaris.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_solaris.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_solaris.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -package system - -import "syscall" - -// fromStatT converts a syscall.Stat_t type to a system.Stat_t type -func fromStatT(s *syscall.Stat_t) (*StatT, error) { - return &StatT{size: s.Size, - mode: uint32(s.Mode), - uid: s.Uid, - gid: s.Gid, - rdev: uint64(s.Rdev), - mtim: s.Mtim}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -// +build !windows - -package system - -import ( - "syscall" -) - -// StatT type contains status of a file. It contains metadata -// like permission, owner, group, size, etc about a file. -type StatT struct { - mode uint32 - uid uint32 - gid uint32 - rdev uint64 - size int64 - mtim syscall.Timespec -} - -// Mode returns file's permission mode. -func (s StatT) Mode() uint32 { - return s.mode -} - -// UID returns file's user id of owner. -func (s StatT) UID() uint32 { - return s.uid -} - -// GID returns file's group id of owner. -func (s StatT) GID() uint32 { - return s.gid -} - -// Rdev returns file's device ID (if it's special file). -func (s StatT) Rdev() uint64 { - return s.rdev -} - -// Size returns file's size. -func (s StatT) Size() int64 { - return s.size -} - -// Mtim returns file's last modification time. -func (s StatT) Mtim() syscall.Timespec { - return s.mtim -} - -// Stat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Stat(path string) (*StatT, error) { - s := &syscall.Stat_t{} - if err := syscall.Stat(path, s); err != nil { - return nil, err - } - return fromStatT(s) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/stat_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/stat_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -package system - -import ( - "os" - "time" -) - -// StatT type contains status of a file. It contains metadata -// like permission, size, etc about a file. -type StatT struct { - mode os.FileMode - size int64 - mtim time.Time -} - -// Size returns file's size. -func (s StatT) Size() int64 { - return s.size -} - -// Mode returns file's permission mode. -func (s StatT) Mode() os.FileMode { - return os.FileMode(s.mode) -} - -// Mtim returns file's last modification time. -func (s StatT) Mtim() time.Time { - return time.Time(s.mtim) -} - -// Stat takes a path to a file and returns -// a system.StatT type pertaining to that file. -// -// Throws an error if the file does not exist -func Stat(path string) (*StatT, error) { - fi, err := os.Stat(path) - if err != nil { - return nil, err - } - return fromStatT(&fi) -} - -// fromStatT converts a os.FileInfo type to a system.StatT type -func fromStatT(fi *os.FileInfo) (*StatT, error) { - return &StatT{ - size: (*fi).Size(), - mode: (*fi).Mode(), - mtim: (*fi).ModTime()}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/syscall_unix.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/syscall_unix.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/syscall_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/syscall_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -// +build linux freebsd - -package system - -import "golang.org/x/sys/unix" - -// Unmount is a platform-specific helper function to call -// the unmount syscall. -func Unmount(dest string) error { - return unix.Unmount(dest, 0) -} - -// CommandLineToArgv should not be used on Unix. -// It simply returns commandLine in the only element in the returned array. -func CommandLineToArgv(commandLine string) ([]string, error) { - return []string{commandLine}, nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/syscall_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/syscall_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/syscall_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/syscall_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -package system - -import ( - "unsafe" - - "github.com/sirupsen/logrus" - "golang.org/x/sys/windows" -) - -var ( - ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") - procGetVersionExW = modkernel32.NewProc("GetVersionExW") - procGetProductInfo = modkernel32.NewProc("GetProductInfo") -) - -// OSVersion is a wrapper for Windows version information -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx -type OSVersion struct { - Version uint32 - MajorVersion uint8 - MinorVersion uint8 - Build uint16 -} - -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx -type osVersionInfoEx struct { - OSVersionInfoSize uint32 - MajorVersion uint32 - MinorVersion uint32 - BuildNumber uint32 - PlatformID uint32 - CSDVersion [128]uint16 - ServicePackMajor uint16 - ServicePackMinor uint16 - SuiteMask uint16 - ProductType byte - Reserve byte -} - -// GetOSVersion gets the operating system version on Windows. Note that -// docker.exe must be manifested to get the correct version information. -func GetOSVersion() OSVersion { - var err error - osv := OSVersion{} - osv.Version, err = windows.GetVersion() - if err != nil { - // GetVersion never fails. - panic(err) - } - osv.MajorVersion = uint8(osv.Version & 0xFF) - osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) - osv.Build = uint16(osv.Version >> 16) - return osv -} - -// IsWindowsClient returns true if the SKU is client -// @engine maintainers - this function should not be removed or modified as it -// is used to enforce licensing restrictions on Windows. -func IsWindowsClient() bool { - osviex := &osVersionInfoEx{OSVersionInfoSize: 284} - r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex))) - if r1 == 0 { - logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err) - return false - } - const verNTWorkstation = 0x00000001 - return osviex.ProductType == verNTWorkstation -} - -// IsIoTCore returns true if the currently running image is based off of -// Windows 10 IoT Core. -// @engine maintainers - this function should not be removed or modified as it -// is used to enforce licensing restrictions on Windows. -func IsIoTCore() bool { - var returnedProductType uint32 - r1, _, err := procGetProductInfo.Call(6, 1, 0, 0, uintptr(unsafe.Pointer(&returnedProductType))) - if r1 == 0 { - logrus.Warnf("GetProductInfo failed - assuming this is not IoT: %v", err) - return false - } - const productIoTUAP = 0x0000007B - const productIoTUAPCommercial = 0x00000083 - return returnedProductType == productIoTUAP || returnedProductType == productIoTUAPCommercial -} - -// Unmount is a platform-specific helper function to call -// the unmount syscall. Not supported on Windows -func Unmount(dest string) error { - return nil -} - -// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array. -func CommandLineToArgv(commandLine string) ([]string, error) { - var argc int32 - - argsPtr, err := windows.UTF16PtrFromString(commandLine) - if err != nil { - return nil, err - } - - argv, err := windows.CommandLineToArgv(argsPtr, &argc) - if err != nil { - return nil, err - } - defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argv)))) - - newArgs := make([]string, argc) - for i, v := range (*argv)[:argc] { - newArgs[i] = string(windows.UTF16ToString((*v)[:])) - } - - return newArgs, nil -} - -// HasWin32KSupport determines whether containers that depend on win32k can -// run on this machine. Win32k is the driver used to implement windowing. -func HasWin32KSupport() bool { - // For now, check for ntuser API support on the host. In the future, a host - // may support win32k in containers even if the host does not support ntuser - // APIs. - return ntuserApiset.Load() == nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/umask.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/umask.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/umask.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/umask.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -// +build !windows - -package system - -import ( - "golang.org/x/sys/unix" -) - -// Umask sets current process's file mode creation mask to newmask -// and returns oldmask. -func Umask(newmask int) (oldmask int, err error) { - return unix.Umask(newmask), nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/umask_windows.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/umask_windows.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/umask_windows.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/umask_windows.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -// +build windows - -package system - -// Umask is not supported on the windows platform. -func Umask(newmask int) (oldmask int, err error) { - // should not be called on cli code path - return 0, ErrNotSupportedPlatform -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_freebsd.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/unix" -) - -// LUtimesNano is used to change access and modification time of the specified path. -// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. -func LUtimesNano(path string, ts []syscall.Timespec) error { - var _path *byte - _path, err := unix.BytePtrFromString(path) - if err != nil { - return err - } - - if _, _, err := unix.Syscall(unix.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != unix.ENOSYS { - return err - } - - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -package system - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/unix" -) - -// LUtimesNano is used to change access and modification time of the specified path. -// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. -func LUtimesNano(path string, ts []syscall.Timespec) error { - atFdCwd := unix.AT_FDCWD - - var _path *byte - _path, err := unix.BytePtrFromString(path) - if err != nil { - return err - } - if _, _, err := unix.Syscall6(unix.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), unix.AT_SYMLINK_NOFOLLOW, 0, 0); err != 0 && err != unix.ENOSYS { - return err - } - - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -// +build !linux,!freebsd - -package system - -import "syscall" - -// LUtimesNano is only supported on linux and freebsd. -func LUtimesNano(path string, ts []syscall.Timespec) error { - return ErrNotSupportedPlatform -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/xattrs_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -package system - -import "golang.org/x/sys/unix" - -// Lgetxattr retrieves the value of the extended attribute identified by attr -// and associated with the given path in the file system. -// It will returns a nil slice and nil error if the xattr is not set. -func Lgetxattr(path string, attr string) ([]byte, error) { - dest := make([]byte, 128) - sz, errno := unix.Lgetxattr(path, attr, dest) - if errno == unix.ENODATA { - return nil, nil - } - if errno == unix.ERANGE { - dest = make([]byte, sz) - sz, errno = unix.Lgetxattr(path, attr, dest) - } - if errno != nil { - return nil, errno - } - - return dest[:sz], nil -} - -// Lsetxattr sets the value of the extended attribute identified by attr -// and associated with the given path in the file system. -func Lsetxattr(path string, attr string, data []byte, flags int) error { - return unix.Lsetxattr(path, attr, data, flags) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -// +build !linux - -package system - -// Lgetxattr is not supported on platforms other than linux. -func Lgetxattr(path string, attr string) ([]byte, error) { - return nil, ErrNotSupportedPlatform -} - -// Lsetxattr is not supported on platforms other than linux. -func Lsetxattr(path string, attr string, data []byte, flags int) error { - return ErrNotSupportedPlatform -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go containerd-1.5.9/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go --- containerd-1.2.6/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -// Package truncindex provides a general 'index tree', used by Docker -// in order to be able to reference containers by only a few unambiguous -// characters of their id. -package truncindex - -import ( - "errors" - "fmt" - "strings" - "sync" - - "github.com/tchap/go-patricia/patricia" -) - -var ( - // ErrEmptyPrefix is an error returned if the prefix was empty. - ErrEmptyPrefix = errors.New("Prefix can't be empty") - - // ErrIllegalChar is returned when a space is in the ID - ErrIllegalChar = errors.New("illegal character: ' '") - - // ErrNotExist is returned when ID or its prefix not found in index. - ErrNotExist = errors.New("ID does not exist") -) - -// ErrAmbiguousPrefix is returned if the prefix was ambiguous -// (multiple ids for the prefix). -type ErrAmbiguousPrefix struct { - prefix string -} - -func (e ErrAmbiguousPrefix) Error() string { - return fmt.Sprintf("Multiple IDs found with provided prefix: %s", e.prefix) -} - -// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes. -// This is used to retrieve image and container IDs by more convenient shorthand prefixes. -type TruncIndex struct { - sync.RWMutex - trie *patricia.Trie - ids map[string]struct{} -} - -// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs. -func NewTruncIndex(ids []string) (idx *TruncIndex) { - idx = &TruncIndex{ - ids: make(map[string]struct{}), - - // Change patricia max prefix per node length, - // because our len(ID) always 64 - trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)), - } - for _, id := range ids { - idx.addID(id) - } - return -} - -func (idx *TruncIndex) addID(id string) error { - if strings.Contains(id, " ") { - return ErrIllegalChar - } - if id == "" { - return ErrEmptyPrefix - } - if _, exists := idx.ids[id]; exists { - return fmt.Errorf("id already exists: '%s'", id) - } - idx.ids[id] = struct{}{} - if inserted := idx.trie.Insert(patricia.Prefix(id), struct{}{}); !inserted { - return fmt.Errorf("failed to insert id: %s", id) - } - return nil -} - -// Add adds a new ID to the TruncIndex. -func (idx *TruncIndex) Add(id string) error { - idx.Lock() - defer idx.Unlock() - return idx.addID(id) -} - -// Delete removes an ID from the TruncIndex. If there are multiple IDs -// with the given prefix, an error is thrown. -func (idx *TruncIndex) Delete(id string) error { - idx.Lock() - defer idx.Unlock() - if _, exists := idx.ids[id]; !exists || id == "" { - return fmt.Errorf("no such id: '%s'", id) - } - delete(idx.ids, id) - if deleted := idx.trie.Delete(patricia.Prefix(id)); !deleted { - return fmt.Errorf("no such id: '%s'", id) - } - return nil -} - -// Get retrieves an ID from the TruncIndex. If there are multiple IDs -// with the given prefix, an error is thrown. -func (idx *TruncIndex) Get(s string) (string, error) { - if s == "" { - return "", ErrEmptyPrefix - } - var ( - id string - ) - subTreeVisitFunc := func(prefix patricia.Prefix, item patricia.Item) error { - if id != "" { - // we haven't found the ID if there are two or more IDs - id = "" - return ErrAmbiguousPrefix{prefix: string(prefix)} - } - id = string(prefix) - return nil - } - - idx.RLock() - defer idx.RUnlock() - if err := idx.trie.VisitSubtree(patricia.Prefix(s), subTreeVisitFunc); err != nil { - return "", err - } - if id != "" { - return id, nil - } - return "", ErrNotExist -} - -// Iterate iterates over all stored IDs and passes each of them to the given -// handler. Take care that the handler method does not call any public -// method on truncindex as the internal locking is not reentrant/recursive -// and will result in deadlock. -func (idx *TruncIndex) Iterate(handler func(id string)) { - idx.Lock() - defer idx.Unlock() - idx.trie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { - handler(string(prefix)) - return nil - }) -} diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/README.md containerd-1.5.9/vendor/github.com/docker/docker/README.md --- containerd-1.2.6/vendor/github.com/docker/docker/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -The Moby Project -================ - -![Moby Project logo](docs/static_files/moby-project-logo.png "The Moby Project") - -Moby is an open-source project created by Docker to enable and accelerate software containerization. - -It provides a "Lego set" of toolkit components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts and professionals to experiment and exchange ideas. -Components include container build tools, a container registry, orchestration tools, a runtime and more, and these can be used as building blocks in conjunction with other tools and projects. - -## Principles - -Moby is an open project guided by strong principles, aiming to be modular, flexible and without too strong an opinion on user experience. -It is open to the community to help set its direction. - -- Modular: the project includes lots of components that have well-defined functions and APIs that work together. -- Batteries included but swappable: Moby includes enough components to build fully featured container system, but its modular architecture ensures that most of the components can be swapped by different implementations. -- Usable security: Moby provides secure defaults without compromising usability. -- Developer focused: The APIs are intended to be functional and useful to build powerful tools. -They are not necessarily intended as end user tools but as components aimed at developers. -Documentation and UX is aimed at developers not end users. - -## Audience - -The Moby Project is intended for engineers, integrators and enthusiasts looking to modify, hack, fix, experiment, invent and build systems based on containers. -It is not for people looking for a commercially supported system, but for people who want to work and learn with open source code. - -## Relationship with Docker - -The components and tools in the Moby Project are initially the open source components that Docker and the community have built for the Docker Project. -New projects can be added if they fit with the community goals. Docker is committed to using Moby as the upstream for the Docker Product. -However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed. - -The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful. -The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases. - ------ - -Legal -===== - -*Brought to you courtesy of our legal counsel. For more context, -please see the [NOTICE](https://github.com/moby/moby/blob/master/NOTICE) document in this repo.* - -Use and transfer of Moby may be subject to certain restrictions by the -United States and other governments. - -It is your responsibility to ensure that your use and/or transfer does not -violate applicable laws. - -For more information, please see https://www.bis.doc.gov - -Licensing -========= -Moby is licensed under the Apache License, Version 2.0. See -[LICENSE](https://github.com/moby/moby/blob/master/LICENSE) for the full -license text. diff -Nru containerd-1.2.6/vendor/github.com/docker/docker/vendor.conf containerd-1.5.9/vendor/github.com/docker/docker/vendor.conf --- containerd-1.2.6/vendor/github.com/docker/docker/vendor.conf 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/docker/vendor.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -# the following lines are in sorted order, FYI -github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 -github.com/Microsoft/hcsshim v0.6.5 -github.com/Microsoft/go-winio v0.4.5 -github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76 -github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a -github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git -github.com/gorilla/context v1.1 -github.com/gorilla/mux v1.1 -github.com/Microsoft/opengcs v0.3.4 -github.com/kr/pty 5cf931ef8f -github.com/mattn/go-shellwords v1.0.3 -github.com/sirupsen/logrus v1.0.3 -github.com/tchap/go-patricia v2.2.6 -github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 -golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 -golang.org/x/sys 8dbc5d05d6edcc104950cc299a1ce6641235bc86 -github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 -github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d -golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 -github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987 -github.com/pmezard/go-difflib v1.0.0 -github.com/gotestyourself/gotestyourself v1.1.0 - -github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 -github.com/imdario/mergo 0.2.1 -golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0 - -github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8 -github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8 -github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2 - -#get libnetwork packages -github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce -github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 -github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 -github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec -github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b -github.com/hashicorp/memberlist v0.1.0 -github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 -github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d -github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e -github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 -github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef -github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 -github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969 -github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060 -github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 -github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d -github.com/coreos/etcd v3.2.1 -github.com/coreos/go-semver v0.2.0 -github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065 -github.com/hashicorp/consul v0.5.2 -github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 -github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 - -# get graph and distribution packages -github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c -github.com/vbatts/tar-split v0.10.1 -github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb - -# get go-zfs packages -github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa -github.com/pborman/uuid v1.0 - -google.golang.org/grpc v1.3.0 - -# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly -github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d -github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 -github.com/opencontainers/runtime-spec v1.0.0 - -github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 - -# libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) -github.com/coreos/go-systemd v4 -github.com/godbus/dbus v4.0.0 -github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 -github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 - -# gelf logging driver deps -github.com/Graylog2/go-gelf v2 - -github.com/fluent/fluent-logger-golang v1.2.1 -# fluent-logger-golang deps -github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972 -github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c - -# fsnotify -github.com/fsnotify/fsnotify v1.4.2 - -# awslogs deps -github.com/aws/aws-sdk-go v1.4.22 -github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0 -github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74 - -# logentries -github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf - -# gcplogs deps -golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0 -google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823 -cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525 -github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7 -google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 - -# containerd -github.com/containerd/containerd 06b9cb35161009dcb7123345749fef02f7cea8e0 -github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 - -# cluster -github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0 -github.com/gogo/protobuf v0.4 -github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a -github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e -golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca -golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb -github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad -github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 -github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 -github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 -github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0 -github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e -github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 -github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 -github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8 -github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 -github.com/matttproud/golang_protobuf_extensions v1.0.0 -github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 -github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 - -# cli -github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git -github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7 -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty - -# metrics -github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18 - -github.com/opencontainers/selinux v1.0.0-rc1 - -# archive/tar -# mkdir -p ./vendor/archive -# git clone git://github.com/tonistiigi/go-1.git ./go -# git --git-dir ./go/.git --work-tree ./go checkout revert-prefix-ignore -# cp -a go/src/archive/tar ./vendor/archive/tar -# rm -rf ./go -# vndr diff -Nru containerd-1.2.6/vendor/github.com/docker/go-events/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/docker/go-events/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/docker/go-events/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-events/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,70 @@ +# Contributing to Docker open source projects + +Want to hack on go-events? Awesome! Here are instructions to get you started. + +go-events is part of the [Docker](https://www.docker.com) project, and +follows the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read Docker's +[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), +[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), +[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and +[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). + +For an in-depth description of our contribution process, visit the +contributors guide: [Understand how to contribute](https://docs.docker.com/opensource/workflow/make-a-contribution/) + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-events/.gitignore containerd-1.5.9/vendor/github.com/docker/go-events/.gitignore --- containerd-1.2.6/vendor/github.com/docker/go-events/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-events/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff -Nru containerd-1.2.6/vendor/github.com/docker/go-events/MAINTAINERS containerd-1.5.9/vendor/github.com/docker/go-events/MAINTAINERS --- containerd-1.2.6/vendor/github.com/docker/go-events/MAINTAINERS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-events/MAINTAINERS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +# go-events maintainers file +# +# This file describes who runs the docker/go-events project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "aaronlehmann", + "aluzzardi", + "lk4d4", + "stevvooe", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.aaronlehmann] + Name = "Aaron Lehmann" + Email = "aaron.lehmann@docker.com" + GitHub = "aaronlehmann" + + [people.aluzzardi] + Name = "Andrea Luzzardi" + Email = "al@docker.com" + GitHub = "aluzzardi" + + [people.lk4d4] + Name = "Alexander Morozov" + Email = "lk4d4@docker.com" + GitHub = "lk4d4" + + [people.stevvooe] + Name = "Stephen Day" + Email = "stephen.day@docker.com" + GitHub = "stevvooe" diff -Nru containerd-1.2.6/vendor/github.com/docker/go-events/retry.go containerd-1.5.9/vendor/github.com/docker/go-events/retry.go --- containerd-1.2.6/vendor/github.com/docker/go-events/retry.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-events/retry.go 2022-01-05 17:30:58.000000000 +0000 @@ -203,8 +203,8 @@ // ExponentialBackoff implements random backoff with exponentially increasing // bounds as the number consecutive failures increase. type ExponentialBackoff struct { + failures uint64 // consecutive failure counter (needs to be 64-bit aligned) config ExponentialBackoffConfig - failures uint64 // consecutive failure counter. } // NewExponentialBackoff returns an exponential backoff strategy with the diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/docker/go-metrics/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/docker/go-metrics/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,55 @@ +# Contributing + +## Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/go.mod containerd-1.5.9/vendor/github.com/docker/go-metrics/go.mod --- containerd-1.2.6/vendor/github.com/docker/go-metrics/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +module github.com/docker/go-metrics + +go 1.11 + +require github.com/prometheus/client_golang v1.1.0 diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/go.sum containerd-1.5.9/vendor/github.com/docker/go-metrics/go.sum --- containerd-1.2.6/vendor/github.com/docker/go-metrics/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,67 @@ +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/handler.go containerd-1.5.9/vendor/github.com/docker/go-metrics/handler.go --- containerd-1.2.6/vendor/github.com/docker/go-metrics/handler.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/handler.go 2022-01-05 17:30:58.000000000 +0000 @@ -4,10 +4,71 @@ "net/http" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +// HTTPHandlerOpts describes a set of configurable options of http metrics +type HTTPHandlerOpts struct { + DurationBuckets []float64 + RequestSizeBuckets []float64 + ResponseSizeBuckets []float64 +} + +const ( + InstrumentHandlerResponseSize = iota + InstrumentHandlerRequestSize + InstrumentHandlerDuration + InstrumentHandlerCounter + InstrumentHandlerInFlight +) + +type HTTPMetric struct { + prometheus.Collector + handlerType int +} + +var ( + defaultDurationBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 25, 60} + defaultRequestSizeBuckets = prometheus.ExponentialBuckets(1024, 2, 22) //1K to 4G + defaultResponseSizeBuckets = defaultRequestSizeBuckets ) // Handler returns the global http.Handler that provides the prometheus -// metrics format on GET requests +// metrics format on GET requests. This handler is no longer instrumented. func Handler() http.Handler { - return prometheus.Handler() + return promhttp.Handler() +} + +func InstrumentHandler(metrics []*HTTPMetric, handler http.Handler) http.HandlerFunc { + return InstrumentHandlerFunc(metrics, handler.ServeHTTP) +} + +func InstrumentHandlerFunc(metrics []*HTTPMetric, handlerFunc http.HandlerFunc) http.HandlerFunc { + var handler http.Handler + handler = http.HandlerFunc(handlerFunc) + for _, metric := range metrics { + switch metric.handlerType { + case InstrumentHandlerResponseSize: + if collector, ok := metric.Collector.(prometheus.ObserverVec); ok { + handler = promhttp.InstrumentHandlerResponseSize(collector, handler) + } + case InstrumentHandlerRequestSize: + if collector, ok := metric.Collector.(prometheus.ObserverVec); ok { + handler = promhttp.InstrumentHandlerRequestSize(collector, handler) + } + case InstrumentHandlerDuration: + if collector, ok := metric.Collector.(prometheus.ObserverVec); ok { + handler = promhttp.InstrumentHandlerDuration(collector, handler) + } + case InstrumentHandlerCounter: + if collector, ok := metric.Collector.(*prometheus.CounterVec); ok { + handler = promhttp.InstrumentHandlerCounter(collector, handler) + } + case InstrumentHandlerInFlight: + if collector, ok := metric.Collector.(prometheus.Gauge); ok { + handler = promhttp.InstrumentHandlerInFlight(collector, handler) + } + } + } + return handler.ServeHTTP } diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/LICENSE containerd-1.5.9/vendor/github.com/docker/go-metrics/LICENSE --- containerd-1.2.6/vendor/github.com/docker/go-metrics/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2013-2016 Docker, Inc. + + 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. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/LICENSE.code containerd-1.5.9/vendor/github.com/docker/go-metrics/LICENSE.code --- containerd-1.2.6/vendor/github.com/docker/go-metrics/LICENSE.code 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/LICENSE.code 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2013-2016 Docker, Inc. - - 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. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/namespace.go containerd-1.5.9/vendor/github.com/docker/go-metrics/namespace.go --- containerd-1.2.6/vendor/github.com/docker/go-metrics/namespace.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/namespace.go 2022-01-05 17:30:58.000000000 +0000 @@ -179,3 +179,137 @@ return fmt.Sprintf("%s_%s", name, unit) } + +func (n *Namespace) NewDefaultHttpMetrics(handlerName string) []*HTTPMetric { + return n.NewHttpMetricsWithOpts(handlerName, HTTPHandlerOpts{ + DurationBuckets: defaultDurationBuckets, + RequestSizeBuckets: defaultResponseSizeBuckets, + ResponseSizeBuckets: defaultResponseSizeBuckets, + }) +} + +func (n *Namespace) NewHttpMetrics(handlerName string, durationBuckets, requestSizeBuckets, responseSizeBuckets []float64) []*HTTPMetric { + return n.NewHttpMetricsWithOpts(handlerName, HTTPHandlerOpts{ + DurationBuckets: durationBuckets, + RequestSizeBuckets: requestSizeBuckets, + ResponseSizeBuckets: responseSizeBuckets, + }) +} + +func (n *Namespace) NewHttpMetricsWithOpts(handlerName string, opts HTTPHandlerOpts) []*HTTPMetric { + var httpMetrics []*HTTPMetric + inFlightMetric := n.NewInFlightGaugeMetric(handlerName) + requestTotalMetric := n.NewRequestTotalMetric(handlerName) + requestDurationMetric := n.NewRequestDurationMetric(handlerName, opts.DurationBuckets) + requestSizeMetric := n.NewRequestSizeMetric(handlerName, opts.RequestSizeBuckets) + responseSizeMetric := n.NewResponseSizeMetric(handlerName, opts.ResponseSizeBuckets) + httpMetrics = append(httpMetrics, inFlightMetric, requestDurationMetric, requestTotalMetric, requestSizeMetric, responseSizeMetric) + return httpMetrics +} + +func (n *Namespace) NewInFlightGaugeMetric(handlerName string) *HTTPMetric { + labels := prometheus.Labels(n.labels) + labels["handler"] = handlerName + metric := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: n.name, + Subsystem: n.subsystem, + Name: "in_flight_requests", + Help: "The in-flight HTTP requests", + ConstLabels: prometheus.Labels(labels), + }) + httpMetric := &HTTPMetric{ + Collector: metric, + handlerType: InstrumentHandlerInFlight, + } + n.Add(httpMetric) + return httpMetric +} + +func (n *Namespace) NewRequestTotalMetric(handlerName string) *HTTPMetric { + labels := prometheus.Labels(n.labels) + labels["handler"] = handlerName + metric := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: n.name, + Subsystem: n.subsystem, + Name: "requests_total", + Help: "Total number of HTTP requests made.", + ConstLabels: prometheus.Labels(labels), + }, + []string{"code", "method"}, + ) + httpMetric := &HTTPMetric{ + Collector: metric, + handlerType: InstrumentHandlerCounter, + } + n.Add(httpMetric) + return httpMetric +} +func (n *Namespace) NewRequestDurationMetric(handlerName string, buckets []float64) *HTTPMetric { + if len(buckets) == 0 { + panic("DurationBuckets must be provided") + } + labels := prometheus.Labels(n.labels) + labels["handler"] = handlerName + opts := prometheus.HistogramOpts{ + Namespace: n.name, + Subsystem: n.subsystem, + Name: "request_duration_seconds", + Help: "The HTTP request latencies in seconds.", + Buckets: buckets, + ConstLabels: prometheus.Labels(labels), + } + metric := prometheus.NewHistogramVec(opts, []string{"method"}) + httpMetric := &HTTPMetric{ + Collector: metric, + handlerType: InstrumentHandlerDuration, + } + n.Add(httpMetric) + return httpMetric +} + +func (n *Namespace) NewRequestSizeMetric(handlerName string, buckets []float64) *HTTPMetric { + if len(buckets) == 0 { + panic("RequestSizeBuckets must be provided") + } + labels := prometheus.Labels(n.labels) + labels["handler"] = handlerName + opts := prometheus.HistogramOpts{ + Namespace: n.name, + Subsystem: n.subsystem, + Name: "request_size_bytes", + Help: "The HTTP request sizes in bytes.", + Buckets: buckets, + ConstLabels: prometheus.Labels(labels), + } + metric := prometheus.NewHistogramVec(opts, []string{}) + httpMetric := &HTTPMetric{ + Collector: metric, + handlerType: InstrumentHandlerRequestSize, + } + n.Add(httpMetric) + return httpMetric +} + +func (n *Namespace) NewResponseSizeMetric(handlerName string, buckets []float64) *HTTPMetric { + if len(buckets) == 0 { + panic("ResponseSizeBuckets must be provided") + } + labels := prometheus.Labels(n.labels) + labels["handler"] = handlerName + opts := prometheus.HistogramOpts{ + Namespace: n.name, + Subsystem: n.subsystem, + Name: "response_size_bytes", + Help: "The HTTP response sizes in bytes.", + Buckets: buckets, + ConstLabels: prometheus.Labels(labels), + } + metrics := prometheus.NewHistogramVec(opts, []string{}) + httpMetric := &HTTPMetric{ + Collector: metrics, + handlerType: InstrumentHandlerResponseSize, + } + n.Add(httpMetric) + return httpMetric +} diff -Nru containerd-1.2.6/vendor/github.com/docker/go-metrics/README.md containerd-1.5.9/vendor/github.com/docker/go-metrics/README.md --- containerd-1.2.6/vendor/github.com/docker/go-metrics/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-metrics/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -68,6 +68,18 @@ Package documentation can be found [here](https://godoc.org/github.com/docker/go-metrics). +## HTTP Metrics + +To instrument a http handler, you can wrap the code like this: + +```go +namespace := metrics.NewNamespace("docker_distribution", "http", metrics.Labels{"handler": "your_http_handler_name"}) +httpMetrics := namespace.NewDefaultHttpMetrics() +metrics.Register(namespace) +instrumentedHandler = metrics.InstrumentHandler(httpMetrics, unInstrumentedHandler) +``` +Note: The `handler` label must be provided when a new namespace is created. + ## Additional Metrics Additional metrics are also defined here that are not available in the prometheus client. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/circle.yml containerd-1.5.9/vendor/github.com/docker/go-units/circle.yml --- containerd-1.2.6/vendor/github.com/docker/go-units/circle.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/circle.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +dependencies: + post: + # install golint + - go get golang.org/x/lint/golint + +test: + pre: + # run analysis before tests + - go vet ./... + - test -z "$(golint ./... | tee /dev/stderr)" + - test -z "$(gofmt -s -l . | tee /dev/stderr)" diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/docker/go-units/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/docker/go-units/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,67 @@ +# Contributing to go-units + +Want to hack on go-units? Awesome! Here are instructions to get you started. + +go-units is a part of the [Docker](https://www.docker.com) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read Docker's +[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), +[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md), +[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and +[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md). + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/duration.go containerd-1.5.9/vendor/github.com/docker/go-units/duration.go --- containerd-1.2.6/vendor/github.com/docker/go-units/duration.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/duration.go 2022-01-05 17:30:58.000000000 +0000 @@ -12,19 +12,21 @@ func HumanDuration(d time.Duration) string { if seconds := int(d.Seconds()); seconds < 1 { return "Less than a second" + } else if seconds == 1 { + return "1 second" } else if seconds < 60 { return fmt.Sprintf("%d seconds", seconds) } else if minutes := int(d.Minutes()); minutes == 1 { return "About a minute" } else if minutes < 60 { return fmt.Sprintf("%d minutes", minutes) - } else if hours := int(d.Hours()); hours == 1 { + } else if hours := int(d.Hours() + 0.5); hours == 1 { return "About an hour" } else if hours < 48 { return fmt.Sprintf("%d hours", hours) } else if hours < 24*7*2 { return fmt.Sprintf("%d days", hours/24) - } else if hours < 24*30*3 { + } else if hours < 24*30*2 { return fmt.Sprintf("%d weeks", hours/24/7) } else if hours < 24*365*2 { return fmt.Sprintf("%d months", hours/24/30) diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/MAINTAINERS containerd-1.5.9/vendor/github.com/docker/go-units/MAINTAINERS --- containerd-1.2.6/vendor/github.com/docker/go-units/MAINTAINERS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/MAINTAINERS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,46 @@ +# go-units maintainers file +# +# This file describes who runs the docker/go-units project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "akihirosuda", + "dnephin", + "thajeztah", + "vdemeester", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.akihirosuda] + Name = "Akihiro Suda" + Email = "akihiro.suda.cz@hco.ntt.co.jp" + GitHub = "AkihiroSuda" + + [people.dnephin] + Name = "Daniel Nephin" + Email = "dnephin@gmail.com" + GitHub = "dnephin" + + [people.thajeztah] + Name = "Sebastiaan van Stijn" + Email = "github@gone.nl" + GitHub = "thaJeztah" + + [people.vdemeester] + Name = "Vincent Demeester" + Email = "vincent@sbr.pm" + GitHub = "vdemeester" \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/size.go containerd-1.5.9/vendor/github.com/docker/go-units/size.go --- containerd-1.2.6/vendor/github.com/docker/go-units/size.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/size.go 2022-01-05 17:30:58.000000000 +0000 @@ -31,34 +31,46 @@ var ( decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB} binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB} - sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`) + sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`) ) var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} -// CustomSize returns a human-readable approximation of a size -// using custom format. -func CustomSize(format string, size float64, base float64, _map []string) string { +func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) { i := 0 unitsLimit := len(_map) - 1 for size >= base && i < unitsLimit { size = size / base i++ } - return fmt.Sprintf(format, size, _map[i]) + return size, _map[i] +} + +// CustomSize returns a human-readable approximation of a size +// using custom format. +func CustomSize(format string, size float64, base float64, _map []string) string { + size, unit := getSizeAndUnit(size, base, _map) + return fmt.Sprintf(format, size, unit) +} + +// HumanSizeWithPrecision allows the size to be in any precision, +// instead of 4 digit precision used in units.HumanSize. +func HumanSizeWithPrecision(size float64, precision int) string { + size, unit := getSizeAndUnit(size, 1000.0, decimapAbbrs) + return fmt.Sprintf("%.*g%s", precision, size, unit) } // HumanSize returns a human-readable approximation of a size // capped at 4 valid numbers (eg. "2.746 MB", "796 KB"). func HumanSize(size float64) string { - return CustomSize("%.4g %s", size, 1000.0, decimapAbbrs) + return HumanSizeWithPrecision(size, 4) } // BytesSize returns a human-readable size in bytes, kibibytes, // mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB"). func BytesSize(size float64) string { - return CustomSize("%.4g %s", size, 1024.0, binaryAbbrs) + return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs) } // FromHumanSize returns an integer from a human-readable specification of a diff -Nru containerd-1.2.6/vendor/github.com/docker/go-units/ulimit.go containerd-1.5.9/vendor/github.com/docker/go-units/ulimit.go --- containerd-1.2.6/vendor/github.com/docker/go-units/ulimit.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/go-units/ulimit.go 2022-01-05 17:30:58.000000000 +0000 @@ -96,8 +96,13 @@ return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]) } - if soft > *hard { - return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard) + if *hard != -1 { + if soft == -1 { + return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: soft: -1 (unlimited), hard: %d", *hard) + } + if soft > *hard { + return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard) + } } return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil diff -Nru containerd-1.2.6/vendor/github.com/docker/spdystream/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/docker/spdystream/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/docker/spdystream/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/spdystream/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,13 @@ +# Contributing to SpdyStream + +Want to hack on spdystream? Awesome! Here are instructions to get you +started. + +SpdyStream is a part of the [Docker](https://docker.io) project, and follows +the same rules and principles. If you're already familiar with the way +Docker does things, you'll feel right at home. + +Otherwise, go read +[Docker's contributions guidelines](https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md). + +Happy hacking! diff -Nru containerd-1.2.6/vendor/github.com/docker/spdystream/MAINTAINERS containerd-1.5.9/vendor/github.com/docker/spdystream/MAINTAINERS --- containerd-1.2.6/vendor/github.com/docker/spdystream/MAINTAINERS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/docker/spdystream/MAINTAINERS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +# Spdystream maintainers file +# +# This file describes who runs the docker/spdystream project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "dmcgowan", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.dmcgowan] + Name = "Derek McGowan" + Email = "derek@docker.com" + GitHub = "dmcgowan" diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/bench_test.sh containerd-1.5.9/vendor/github.com/emicklei/go-restful/bench_test.sh --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/bench_test.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/bench_test.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,10 @@ +#go test -run=none -file bench_test.go -test.bench . -cpuprofile=bench_test.out + +go test -c +./go-restful.test -test.run=none -test.cpuprofile=tmp.prof -test.bench=BenchmarkMany +./go-restful.test -test.run=none -test.cpuprofile=curly.prof -test.bench=BenchmarkManyCurly + +#go tool pprof go-restful.test tmp.prof +go tool pprof go-restful.test curly.prof + + diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/CHANGES.md containerd-1.5.9/vendor/github.com/emicklei/go-restful/CHANGES.md --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/CHANGES.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/CHANGES.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,273 @@ +## Change history of go-restful + + +v2.9.5 +- fix panic in Response.WriteError if err == nil + +v2.9.4 + +- fix issue #400 , parsing mime type quality +- Route Builder added option for contentEncodingEnabled (#398) + +v2.9.3 + +- Avoid return of 415 Unsupported Media Type when request body is empty (#396) + +v2.9.2 + +- Reduce allocations in per-request methods to improve performance (#395) + +v2.9.1 + +- Fix issue with default responses and invalid status code 0. (#393) + +v2.9.0 + +- add per Route content encoding setting (overrides container setting) + +v2.8.0 + +- add Request.QueryParameters() +- add json-iterator (via build tag) +- disable vgo module (until log is moved) + +v2.7.1 + +- add vgo module + +v2.6.1 + +- add JSONNewDecoderFunc to allow custom JSON Decoder usage (go 1.10+) + +v2.6.0 + +- Make JSR 311 routing and path param processing consistent +- Adding description to RouteBuilder.Reads() +- Update example for Swagger12 and OpenAPI + +2017-09-13 + +- added route condition functions using `.If(func)` in route building. + +2017-02-16 + +- solved issue #304, make operation names unique + +2017-01-30 + + [IMPORTANT] For swagger users, change your import statement to: + swagger "github.com/emicklei/go-restful-swagger12" + +- moved swagger 1.2 code to go-restful-swagger12 +- created TAG 2.0.0 + +2017-01-27 + +- remove defer request body close +- expose Dispatch for testing filters and Routefunctions +- swagger response model cannot be array +- created TAG 1.0.0 + +2016-12-22 + +- (API change) Remove code related to caching request content. Removes SetCacheReadEntity(doCache bool) + +2016-11-26 + +- Default change! now use CurlyRouter (was RouterJSR311) +- Default change! no more caching of request content +- Default change! do not recover from panics + +2016-09-22 + +- fix the DefaultRequestContentType feature + +2016-02-14 + +- take the qualify factor of the Accept header mediatype into account when deciding the contentype of the response +- add constructors for custom entity accessors for xml and json + +2015-09-27 + +- rename new WriteStatusAnd... to WriteHeaderAnd... for consistency + +2015-09-25 + +- fixed problem with changing Header after WriteHeader (issue 235) + +2015-09-14 + +- changed behavior of WriteHeader (immediate write) and WriteEntity (no status write) +- added support for custom EntityReaderWriters. + +2015-08-06 + +- add support for reading entities from compressed request content +- use sync.Pool for compressors of http response and request body +- add Description to Parameter for documentation in Swagger UI + +2015-03-20 + +- add configurable logging + +2015-03-18 + +- if not specified, the Operation is derived from the Route function + +2015-03-17 + +- expose Parameter creation functions +- make trace logger an interface +- fix OPTIONSFilter +- customize rendering of ServiceError +- JSR311 router now handles wildcards +- add Notes to Route + +2014-11-27 + +- (api add) PrettyPrint per response. (as proposed in #167) + +2014-11-12 + +- (api add) ApiVersion(.) for documentation in Swagger UI + +2014-11-10 + +- (api change) struct fields tagged with "description" show up in Swagger UI + +2014-10-31 + +- (api change) ReturnsError -> Returns +- (api add) RouteBuilder.Do(aBuilder) for DRY use of RouteBuilder +- fix swagger nested structs +- sort Swagger response messages by code + +2014-10-23 + +- (api add) ReturnsError allows you to document Http codes in swagger +- fixed problem with greedy CurlyRouter +- (api add) Access-Control-Max-Age in CORS +- add tracing functionality (injectable) for debugging purposes +- support JSON parse 64bit int +- fix empty parameters for swagger +- WebServicesUrl is now optional for swagger +- fixed duplicate AccessControlAllowOrigin in CORS +- (api change) expose ServeMux in container +- (api add) added AllowedDomains in CORS +- (api add) ParameterNamed for detailed documentation + +2014-04-16 + +- (api add) expose constructor of Request for testing. + +2014-06-27 + +- (api add) ParameterNamed gives access to a Parameter definition and its data (for further specification). +- (api add) SetCacheReadEntity allow scontrol over whether or not the request body is being cached (default true for compatibility reasons). + +2014-07-03 + +- (api add) CORS can be configured with a list of allowed domains + +2014-03-12 + +- (api add) Route path parameters can use wildcard or regular expressions. (requires CurlyRouter) + +2014-02-26 + +- (api add) Request now provides information about the matched Route, see method SelectedRoutePath + +2014-02-17 + +- (api change) renamed parameter constants (go-lint checks) + +2014-01-10 + +- (api add) support for CloseNotify, see http://golang.org/pkg/net/http/#CloseNotifier + +2014-01-07 + +- (api change) Write* methods in Response now return the error or nil. +- added example of serving HTML from a Go template. +- fixed comparing Allowed headers in CORS (is now case-insensitive) + +2013-11-13 + +- (api add) Response knows how many bytes are written to the response body. + +2013-10-29 + +- (api add) RecoverHandler(handler RecoverHandleFunction) to change how panic recovery is handled. Default behavior is to log and return a stacktrace. This may be a security issue as it exposes sourcecode information. + +2013-10-04 + +- (api add) Response knows what HTTP status has been written +- (api add) Request can have attributes (map of string->interface, also called request-scoped variables + +2013-09-12 + +- (api change) Router interface simplified +- Implemented CurlyRouter, a Router that does not use|allow regular expressions in paths + +2013-08-05 + - add OPTIONS support + - add CORS support + +2013-08-27 + +- fixed some reported issues (see github) +- (api change) deprecated use of WriteError; use WriteErrorString instead + +2014-04-15 + +- (fix) v1.0.1 tag: fix Issue 111: WriteErrorString + +2013-08-08 + +- (api add) Added implementation Container: a WebServices collection with its own http.ServeMux allowing multiple endpoints per program. Existing uses of go-restful will register their services to the DefaultContainer. +- (api add) the swagger package has be extended to have a UI per container. +- if panic is detected then a small stack trace is printed (thanks to runner-mei) +- (api add) WriteErrorString to Response + +Important API changes: + +- (api remove) package variable DoNotRecover no longer works ; use restful.DefaultContainer.DoNotRecover(true) instead. +- (api remove) package variable EnableContentEncoding no longer works ; use restful.DefaultContainer.EnableContentEncoding(true) instead. + + +2013-07-06 + +- (api add) Added support for response encoding (gzip and deflate(zlib)). This feature is disabled on default (for backwards compatibility). Use restful.EnableContentEncoding = true in your initialization to enable this feature. + +2013-06-19 + +- (improve) DoNotRecover option, moved request body closer, improved ReadEntity + +2013-06-03 + +- (api change) removed Dispatcher interface, hide PathExpression +- changed receiver names of type functions to be more idiomatic Go + +2013-06-02 + +- (optimize) Cache the RegExp compilation of Paths. + +2013-05-22 + +- (api add) Added support for request/response filter functions + +2013-05-18 + + +- (api add) Added feature to change the default Http Request Dispatch function (travis cline) +- (api change) Moved Swagger Webservice to swagger package (see example restful-user) + +[2012-11-14 .. 2013-05-18> + +- See https://github.com/emicklei/go-restful/commits + +2012-11-14 + +- Initial commit + + diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/container.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/container.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/container.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/container.go 2022-01-05 17:30:58.000000000 +0000 @@ -97,7 +97,7 @@ // cannot have duplicate root paths for _, each := range c.webServices { if each.RootPath() == service.RootPath() { - log.Printf("[restful] WebService with duplicate root path detected:['%v']", each) + log.Printf("WebService with duplicate root path detected:['%v']", each) os.Exit(1) } } @@ -139,7 +139,7 @@ func (c *Container) Remove(ws *WebService) error { if c.ServeMux == http.DefaultServeMux { - errMsg := fmt.Sprintf("[restful] cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws) + errMsg := fmt.Sprintf("cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws) log.Print(errMsg) return errors.New(errMsg) } @@ -168,7 +168,7 @@ // This may be a security issue as it exposes sourcecode information. func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) { var buffer bytes.Buffer - buffer.WriteString(fmt.Sprintf("[restful] recover from panic situation: - %v\r\n", panicReason)) + buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason)) for i := 2; ; i += 1 { _, file, line, ok := runtime.Caller(i) if !ok { @@ -220,31 +220,37 @@ }() } + // Find best match Route ; err is non nil if no match was found + var webService *WebService + var route *Route + var err error + func() { + c.webServicesLock.RLock() + defer c.webServicesLock.RUnlock() + webService, route, err = c.router.SelectRoute( + c.webServices, + httpRequest) + }() + // Detect if compression is needed // assume without compression, test for override - if c.contentEncodingEnabled { + contentEncodingEnabled := c.contentEncodingEnabled + if route != nil && route.contentEncodingEnabled != nil { + contentEncodingEnabled = *route.contentEncodingEnabled + } + if contentEncodingEnabled { doCompress, encoding := wantsCompressedResponse(httpRequest) if doCompress { var err error writer, err = NewCompressingResponseWriter(httpWriter, encoding) if err != nil { - log.Print("[restful] unable to install compressor: ", err) + log.Print("unable to install compressor: ", err) httpWriter.WriteHeader(http.StatusInternalServerError) return } } } - // Find best match Route ; err is non nil if no match was found - var webService *WebService - var route *Route - var err error - func() { - c.webServicesLock.RLock() - defer c.webServicesLock.RUnlock() - webService, route, err = c.router.SelectRoute( - c.webServices, - httpRequest) - }() + if err != nil { // a non-200 response has already been written // run container filters anyway ; they should not touch the response... @@ -259,7 +265,12 @@ chain.ProcessFilter(NewRequest(httpRequest), NewResponse(writer)) return } - wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest) + pathProcessor, routerProcessesPath := c.router.(PathProcessor) + if !routerProcessesPath { + pathProcessor = defaultPathProcessor{} + } + pathParams := pathProcessor.ExtractParameters(route, webService, httpRequest.URL.Path) + wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer, httpRequest, pathParams) // pass through filters (if any) if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 { // compose filter chain diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/coverage.sh containerd-1.5.9/vendor/github.com/emicklei/go-restful/coverage.sh --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/coverage.sh 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/coverage.sh 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +go test -coverprofile=coverage.out +go tool cover -html=coverage.out \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/curly.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/curly.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/curly.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/curly.go 2022-01-05 17:30:58.000000000 +0000 @@ -45,14 +45,14 @@ // selectRoutes return a collection of Route from a WebService that matches the path tokens from the request. func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes { - candidates := sortableCurlyRoutes{} + candidates := make(sortableCurlyRoutes, 0, 8) for _, each := range ws.routes { matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens) if matches { candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers? } } - sort.Sort(sort.Reverse(candidates)) + sort.Sort(candidates) return candidates } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/curly_route.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/curly_route.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/curly_route.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/curly_route.go 2022-01-05 17:30:58.000000000 +0000 @@ -11,6 +11,7 @@ staticCount int } +// sortableCurlyRoutes orders by most parameters and path elements first. type sortableCurlyRoutes []curlyRoute func (s *sortableCurlyRoutes) add(route curlyRoute) { @@ -18,6 +19,7 @@ } func (s sortableCurlyRoutes) routes() (routes []Route) { + routes = make([]Route, 0, len(s)) for _, each := range s { routes = append(routes, each.route) // TODO change return type } @@ -31,22 +33,22 @@ s[i], s[j] = s[j], s[i] } func (s sortableCurlyRoutes) Less(i, j int) bool { - ci := s[i] - cj := s[j] + a := s[j] + b := s[i] // primary key - if ci.staticCount < cj.staticCount { + if a.staticCount < b.staticCount { return true } - if ci.staticCount > cj.staticCount { + if a.staticCount > b.staticCount { return false } // secundary key - if ci.paramCount < cj.paramCount { + if a.paramCount < b.paramCount { return true } - if ci.paramCount > cj.paramCount { + if a.paramCount > b.paramCount { return false } - return ci.route.Path < cj.route.Path + return a.route.Path < b.route.Path } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/entity_accessors.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/entity_accessors.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/entity_accessors.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/entity_accessors.go 2022-01-05 17:30:58.000000000 +0000 @@ -5,7 +5,6 @@ // that can be found in the LICENSE file. import ( - "encoding/json" "encoding/xml" "strings" "sync" @@ -128,7 +127,7 @@ // Read unmarshalls the value from JSON func (e entityJSONAccess) Read(req *Request, v interface{}) error { - decoder := json.NewDecoder(req.Request.Body) + decoder := NewDecoder(req.Request.Body) decoder.UseNumber() return decoder.Decode(v) } @@ -147,7 +146,7 @@ } if resp.prettyPrint { // pretty output must be created and written explicitly - output, err := json.MarshalIndent(v, " ", " ") + output, err := MarshalIndent(v, "", " ") if err != nil { return err } @@ -159,5 +158,5 @@ // not-so-pretty resp.Header().Set(HEADER_ContentType, contentType) resp.WriteHeader(status) - return json.NewEncoder(resp).Encode(v) + return NewEncoder(resp).Encode(v) } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/.gitignore containerd-1.5.9/vendor/github.com/emicklei/go-restful/.gitignore --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,70 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +restful.html + +*.out + +tmp.prof + +go-restful.test + +examples/restful-basic-authentication + +examples/restful-encoding-filter + +examples/restful-filters + +examples/restful-hello-world + +examples/restful-resource-functions + +examples/restful-serve-static + +examples/restful-user-service + +*.DS_Store +examples/restful-user-resource + +examples/restful-multi-containers + +examples/restful-form-handling + +examples/restful-CORS-filter + +examples/restful-options-filter + +examples/restful-curly-router + +examples/restful-cpuprofiler-service + +examples/restful-pre-post-filters + +curly.prof + +examples/restful-NCSA-logging + +examples/restful-html-template + +s.html +restful-path-tail diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/json.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/json.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/json.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/json.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +// +build !jsoniter + +package restful + +import "encoding/json" + +var ( + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder + NewEncoder = json.NewEncoder +) diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/jsoniter.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/jsoniter.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/jsoniter.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/jsoniter.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +// +build jsoniter + +package restful + +import "github.com/json-iterator/go" + +var ( + json = jsoniter.ConfigCompatibleWithStandardLibrary + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder + NewEncoder = json.NewEncoder +) diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/jsr311.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/jsr311.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/jsr311.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/jsr311.go 2022-01-05 17:30:58.000000000 +0000 @@ -39,57 +39,106 @@ return dispatcher, route, ok } +// ExtractParameters is used to obtain the path parameters from the route using the same matching +// engine as the JSR 311 router. +func (r RouterJSR311) ExtractParameters(route *Route, webService *WebService, urlPath string) map[string]string { + webServiceExpr := webService.pathExpr + webServiceMatches := webServiceExpr.Matcher.FindStringSubmatch(urlPath) + pathParameters := r.extractParams(webServiceExpr, webServiceMatches) + routeExpr := route.pathExpr + routeMatches := routeExpr.Matcher.FindStringSubmatch(webServiceMatches[len(webServiceMatches)-1]) + routeParams := r.extractParams(routeExpr, routeMatches) + for key, value := range routeParams { + pathParameters[key] = value + } + return pathParameters +} + +func (RouterJSR311) extractParams(pathExpr *pathExpression, matches []string) map[string]string { + params := map[string]string{} + for i := 1; i < len(matches); i++ { + if len(pathExpr.VarNames) >= i { + params[pathExpr.VarNames[i-1]] = matches[i] + } + } + return params +} + // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) { + candidates := make([]*Route, 0, 8) + for i, each := range routes { + ok := true + for _, fn := range each.If { + if !fn(httpRequest) { + ok = false + break + } + } + if ok { + candidates = append(candidates, &routes[i]) + } + } + if len(candidates) == 0 { + if trace { + traceLogger.Printf("no Route found (from %d) that passes conditional checks", len(routes)) + } + return nil, NewError(http.StatusNotFound, "404: Not Found") + } + // http method - methodOk := []Route{} - for _, each := range routes { + previous := candidates + candidates = candidates[:0] + for _, each := range previous { if httpRequest.Method == each.Method { - methodOk = append(methodOk, each) + candidates = append(candidates, each) } } - if len(methodOk) == 0 { + if len(candidates) == 0 { if trace { - traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(routes), httpRequest.Method) + traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(previous), httpRequest.Method) } return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed") } - inputMediaOk := methodOk // content-type contentType := httpRequest.Header.Get(HEADER_ContentType) - inputMediaOk = []Route{} - for _, each := range methodOk { + previous = candidates + candidates = candidates[:0] + for _, each := range previous { if each.matchesContentType(contentType) { - inputMediaOk = append(inputMediaOk, each) + candidates = append(candidates, each) } } - if len(inputMediaOk) == 0 { + if len(candidates) == 0 { if trace { - traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType) + traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(previous), contentType) + } + if httpRequest.ContentLength > 0 { + return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type") } - return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type") } // accept - outputMediaOk := []Route{} + previous = candidates + candidates = candidates[:0] accept := httpRequest.Header.Get(HEADER_Accept) if len(accept) == 0 { accept = "*/*" } - for _, each := range inputMediaOk { + for _, each := range previous { if each.matchesAccept(accept) { - outputMediaOk = append(outputMediaOk, each) + candidates = append(candidates, each) } } - if len(outputMediaOk) == 0 { + if len(candidates) == 0 { if trace { - traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(inputMediaOk), accept) + traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(previous), accept) } return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable") } // return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil - return &outputMediaOk[0], nil + return candidates[0], nil } // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/Makefile containerd-1.5.9/vendor/github.com/emicklei/go-restful/Makefile --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/Makefile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,7 @@ +all: test + +test: + go test -v . + +ex: + cd examples && ls *.go | xargs go build -o /tmp/ignore \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/mime.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/mime.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/mime.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/mime.go 2022-01-05 17:30:58.000000000 +0000 @@ -22,7 +22,10 @@ return append(l, e) } +const qFactorWeightingKey = "q" + // sortedMimes returns a list of mime sorted (desc) by its specified quality. +// e.g. text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 func sortedMimes(accept string) (sorted []mime) { for _, each := range strings.Split(accept, ",") { typeAndQuality := strings.Split(strings.Trim(each, " "), ";") @@ -30,14 +33,16 @@ sorted = insertMime(sorted, mime{typeAndQuality[0], 1.0}) } else { // take factor - parts := strings.Split(typeAndQuality[1], "=") - if len(parts) == 2 { - f, err := strconv.ParseFloat(parts[1], 64) + qAndWeight := strings.Split(typeAndQuality[1], "=") + if len(qAndWeight) == 2 && strings.Trim(qAndWeight[0], " ") == qFactorWeightingKey { + f, err := strconv.ParseFloat(qAndWeight[1], 64) if err != nil { traceLogger.Printf("unable to parse quality in %s, %v", each, err) } else { sorted = insertMime(sorted, mime{typeAndQuality[0], f}) } + } else { + sorted = insertMime(sorted, mime{typeAndQuality[0], 1.0}) } } } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/options_filter.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/options_filter.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/options_filter.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/options_filter.go 2022-01-05 17:30:58.000000000 +0000 @@ -15,7 +15,15 @@ chain.ProcessFilter(req, resp) return } - resp.AddHeader(HEADER_Allow, strings.Join(c.computeAllowedMethods(req), ",")) + + archs := req.Request.Header.Get(HEADER_AccessControlRequestHeaders) + methods := strings.Join(c.computeAllowedMethods(req), ",") + origin := req.Request.Header.Get(HEADER_Origin) + + resp.AddHeader(HEADER_Allow, methods) + resp.AddHeader(HEADER_AccessControlAllowOrigin, origin) + resp.AddHeader(HEADER_AccessControlAllowHeaders, archs) + resp.AddHeader(HEADER_AccessControlAllowMethods, methods) } // OPTIONSFilter is a filter function that inspects the Http Request for the OPTIONS method diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/parameter.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/parameter.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/parameter.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/parameter.go 2022-01-05 17:30:58.000000000 +0000 @@ -19,8 +19,30 @@ // FormParameterKind = indicator of Request parameter type "form" FormParameterKind + + // CollectionFormatCSV comma separated values `foo,bar` + CollectionFormatCSV = CollectionFormat("csv") + + // CollectionFormatSSV space separated values `foo bar` + CollectionFormatSSV = CollectionFormat("ssv") + + // CollectionFormatTSV tab separated values `foo\tbar` + CollectionFormatTSV = CollectionFormat("tsv") + + // CollectionFormatPipes pipe separated values `foo|bar` + CollectionFormatPipes = CollectionFormat("pipes") + + // CollectionFormatMulti corresponds to multiple parameter instances instead of multiple values for a single + // instance `foo=bar&foo=baz`. This is valid only for QueryParameters and FormParameters + CollectionFormatMulti = CollectionFormat("multi") ) +type CollectionFormat string + +func (cf CollectionFormat) String() string { + return string(cf) +} + // Parameter is for documententing the parameter used in a Http Request // ParameterData kinds are Path,Query and Body type Parameter struct { @@ -36,6 +58,7 @@ AllowableValues map[string]string AllowMultiple bool DefaultValue string + CollectionFormat string } // Data returns the state of the Parameter @@ -112,3 +135,9 @@ p.data.Description = doc return p } + +// CollectionFormat sets the collection format for an array type +func (p *Parameter) CollectionFormat(format CollectionFormat) *Parameter { + p.data.CollectionFormat = format.String() + return p +} diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/path_expression.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/path_expression.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/path_expression.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/path_expression.go 2022-01-05 17:30:58.000000000 +0000 @@ -14,8 +14,9 @@ // PathExpression holds a compiled path expression (RegExp) needed to match against // Http request paths and to extract path parameter values. type pathExpression struct { - LiteralCount int // the number of literal characters (means those not resulting from template variable substitution) - VarCount int // the number of named parameters (enclosed by {}) in the path + LiteralCount int // the number of literal characters (means those not resulting from template variable substitution) + VarNames []string // the names of parameters (enclosed by {}) in the path + VarCount int // the number of named parameters (enclosed by {}) in the path Matcher *regexp.Regexp Source string // Path as defined by the RouteBuilder tokens []string @@ -24,16 +25,16 @@ // NewPathExpression creates a PathExpression from the input URL path. // Returns an error if the path is invalid. func newPathExpression(path string) (*pathExpression, error) { - expression, literalCount, varCount, tokens := templateToRegularExpression(path) + expression, literalCount, varNames, varCount, tokens := templateToRegularExpression(path) compiled, err := regexp.Compile(expression) if err != nil { return nil, err } - return &pathExpression{literalCount, varCount, compiled, expression, tokens}, nil + return &pathExpression{literalCount, varNames, varCount, compiled, expression, tokens}, nil } // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-370003.7.3 -func templateToRegularExpression(template string) (expression string, literalCount int, varCount int, tokens []string) { +func templateToRegularExpression(template string) (expression string, literalCount int, varNames []string, varCount int, tokens []string) { var buffer bytes.Buffer buffer.WriteString("^") //tokens = strings.Split(template, "/") @@ -46,8 +47,10 @@ if strings.HasPrefix(each, "{") { // check for regular expression in variable colon := strings.Index(each, ":") + var varName string if colon != -1 { // extract expression + varName = strings.TrimSpace(each[1:colon]) paramExpr := strings.TrimSpace(each[colon+1 : len(each)-1]) if paramExpr == "*" { // special case buffer.WriteString("(.*)") @@ -56,8 +59,10 @@ } } else { // plain var + varName = strings.TrimSpace(each[1 : len(each)-1]) buffer.WriteString("([^/]+?)") } + varNames = append(varNames, varName) varCount += 1 } else { literalCount += len(each) @@ -65,5 +70,5 @@ buffer.WriteString(regexp.QuoteMeta(encoded)) } } - return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varCount, tokens + return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varNames, varCount, tokens } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/path_processor.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/path_processor.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/path_processor.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/path_processor.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,63 @@ +package restful + +import ( + "bytes" + "strings" +) + +// Copyright 2018 Ernest Micklei. All rights reserved. +// Use of this source code is governed by a license +// that can be found in the LICENSE file. + +// PathProcessor is extra behaviour that a Router can provide to extract path parameters from the path. +// If a Router does not implement this interface then the default behaviour will be used. +type PathProcessor interface { + // ExtractParameters gets the path parameters defined in the route and webService from the urlPath + ExtractParameters(route *Route, webService *WebService, urlPath string) map[string]string +} + +type defaultPathProcessor struct{} + +// Extract the parameters from the request url path +func (d defaultPathProcessor) ExtractParameters(r *Route, _ *WebService, urlPath string) map[string]string { + urlParts := tokenizePath(urlPath) + pathParameters := map[string]string{} + for i, key := range r.pathParts { + var value string + if i >= len(urlParts) { + value = "" + } else { + value = urlParts[i] + } + if strings.HasPrefix(key, "{") { // path-parameter + if colon := strings.Index(key, ":"); colon != -1 { + // extract by regex + regPart := key[colon+1 : len(key)-1] + keyPart := key[1:colon] + if regPart == "*" { + pathParameters[keyPart] = untokenizePath(i, urlParts) + break + } else { + pathParameters[keyPart] = value + } + } else { + // without enclosing {} + pathParameters[key[1:len(key)-1]] = value + } + } + } + return pathParameters +} + +// Untokenize back into an URL path using the slash separator +func untokenizePath(offset int, parts []string) string { + var buffer bytes.Buffer + for p := offset; p < len(parts); p++ { + buffer.WriteString(parts[p]) + // do not end + if p < len(parts)-1 { + buffer.WriteString("/") + } + } + return buffer.String() +} diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/README.md containerd-1.5.9/vendor/github.com/emicklei/go-restful/README.md --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -56,13 +56,26 @@ - Content encoding (gzip,deflate) of request and response payloads - Automatic responses on OPTIONS (using a filter) - Automatic CORS request handling (using a filter) -- API declaration for Swagger UI (see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12),[go-restful-openapi](https://github.com/emicklei/go-restful-openapi)) +- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi), see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12)) - Panic recovery to produce HTTP 500, customizable using RecoverHandler(...) - Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...) - Configurable (trace) logging - Customizable gzip/deflate readers and writers using CompressorProvider registration - -### Resources + +## How to customize +There are several hooks to customize the behavior of the go-restful package. + +- Router algorithm +- Panic recovery +- JSON decoder +- Trace logging +- Compression +- Encoders for other serializers +- Use [jsoniter](https://github.com/json-iterator/go) by build this package using a tag, e.g. `go build -tags=jsoniter .` + +TODO: write examples of these. + +## Resources - [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/) - [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/) @@ -72,4 +85,4 @@ Type ```git shortlog -s``` for a full list of contributors. -© 2012 - 2017, http://ernestmicklei.com. MIT License. Contributions are welcome. +© 2012 - 2018, http://ernestmicklei.com. MIT License. Contributions are welcome. diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/request.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/request.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/request.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/request.go 2022-01-05 17:30:58.000000000 +0000 @@ -51,6 +51,11 @@ return r.Request.FormValue(name) } +// QueryParameters returns the all the query parameters values by name +func (r *Request) QueryParameters(name string) []string { + return r.Request.URL.Query()[name] +} + // BodyParameter parses the body of the request (once for typically a POST or a PUT) and returns the value of the given name or an error. func (r *Request) BodyParameter(name string) (string, error) { err := r.Request.ParseForm() diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/response.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/response.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/response.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/response.go 2022-01-05 17:30:58.000000000 +0000 @@ -5,7 +5,9 @@ // that can be found in the LICENSE file. import ( + "bufio" "errors" + "net" "net/http" ) @@ -19,17 +21,19 @@ // It provides several convenience methods to prepare and write response content. type Response struct { http.ResponseWriter - requestAccept string // mime-type what the Http Request says it wants to receive - routeProduces []string // mime-types what the Route says it can produce - statusCode int // HTTP status code that has been written explicitly (if zero then net/http has written 200) - contentLength int // number of bytes written for the response body - prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses. - err error // err property is kept when WriteError is called + requestAccept string // mime-type what the Http Request says it wants to receive + routeProduces []string // mime-types what the Route says it can produce + statusCode int // HTTP status code that has been written explicitly (if zero then net/http has written 200) + contentLength int // number of bytes written for the response body + prettyPrint bool // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses. + err error // err property is kept when WriteError is called + hijacker http.Hijacker // if underlying ResponseWriter supports it } // NewResponse creates a new response based on a http ResponseWriter. func NewResponse(httpWriter http.ResponseWriter) *Response { - return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types + hijacker, _ := httpWriter.(http.Hijacker) + return &Response{ResponseWriter: httpWriter, routeProduces: []string{}, statusCode: http.StatusOK, prettyPrint: PrettyPrintResponses, hijacker: hijacker} } // DefaultResponseContentType set a default. @@ -48,6 +52,16 @@ return r } +// Hijack implements the http.Hijacker interface. This expands +// the Response to fulfill http.Hijacker if the underlying +// http.ResponseWriter supports it. +func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { + if r.hijacker == nil { + return nil, nil, errors.New("http.Hijacker not implemented by underlying http.ResponseWriter") + } + return r.hijacker.Hijack() +} + // PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output. func (r *Response) PrettyPrint(bePretty bool) { r.prettyPrint = bePretty @@ -160,10 +174,15 @@ return writeJSON(r, status, contentType, value) } -// WriteError write the http status and the error string on the response. +// WriteError write the http status and the error string on the response. err can be nil. func (r *Response) WriteError(httpStatus int, err error) error { r.err = err - return r.WriteErrorString(httpStatus, err.Error()) + if err == nil { + r.WriteErrorString(httpStatus, "") + } else { + r.WriteErrorString(httpStatus, err.Error()) + } + return err } // WriteServiceError is a convenience method for a responding with a status and a ServiceError diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/route_builder.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/route_builder.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/route_builder.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/route_builder.go 2022-01-05 17:30:58.000000000 +0000 @@ -24,6 +24,7 @@ httpMethod string // required function RouteFunction // required filters []FilterFunction + conditions []RouteSelectionConditionFunction typeNameHandleFunc TypeNameHandleFunction // required @@ -34,7 +35,10 @@ readSample, writeSample interface{} parameters []*Parameter errorMap map[int]ResponseError + defaultResponse *ResponseError metadata map[string]interface{} + deprecated bool + contentEncodingEnabled *bool } // Do evaluates each argument with the RouteBuilder itself. @@ -97,15 +101,18 @@ // Reads tells what resource type will be read from the request payload. Optional. // A parameter of type "body" is added ,required is set to true and the dataType is set to the qualified name of the sample's type. -func (b *RouteBuilder) Reads(sample interface{}) *RouteBuilder { +func (b *RouteBuilder) Reads(sample interface{}, optionalDescription ...string) *RouteBuilder { fn := b.typeNameHandleFunc if fn == nil { fn = reflectTypeName } typeAsName := fn(sample) - + description := "" + if len(optionalDescription) > 0 { + description = optionalDescription[0] + } b.readSample = sample - bodyParameter := &Parameter{&ParameterData{Name: "body"}} + bodyParameter := &Parameter{&ParameterData{Name: "body", Description: description}} bodyParameter.beBody() bodyParameter.Required(true) bodyParameter.DataType(typeAsName) @@ -159,7 +166,7 @@ Code: code, Message: message, Model: model, - IsDefault: false, + IsDefault: false, // this field is deprecated, use default response instead. } // lazy init because there is no NewRouteBuilder (yet) if b.errorMap == nil { @@ -169,17 +176,11 @@ return b } -// DefaultReturns is a special Returns call that sets the default of the response ; the code is zero. +// DefaultReturns is a special Returns call that sets the default of the response. func (b *RouteBuilder) DefaultReturns(message string, model interface{}) *RouteBuilder { - b.Returns(0, message, model) - // Modify the ResponseError just added/updated - re := b.errorMap[0] - // errorMap is initialized - b.errorMap[0] = ResponseError{ - Code: re.Code, - Message: re.Message, - Model: re.Model, - IsDefault: true, + b.defaultResponse = &ResponseError{ + Message: message, + Model: model, } return b } @@ -193,6 +194,12 @@ return b } +// Deprecate sets the value of deprecated to true. Deprecated routes have a special UI treatment to warn against use +func (b *RouteBuilder) Deprecate() *RouteBuilder { + b.deprecated = true + return b +} + // ResponseError represents a response; not necessarily an error. type ResponseError struct { Code int @@ -212,6 +219,27 @@ return b } +// If sets a condition function that controls matching the Route based on custom logic. +// The condition function is provided the HTTP request and should return true if the route +// should be considered. +// +// Efficiency note: the condition function is called before checking the method, produces, and +// consumes criteria, so that the correct HTTP status code can be returned. +// +// Lifecycle note: no filter functions have been called prior to calling the condition function, +// so the condition function should not depend on any context that might be set up by container +// or route filters. +func (b *RouteBuilder) If(condition RouteSelectionConditionFunction) *RouteBuilder { + b.conditions = append(b.conditions, condition) + return b +} + +// ContentEncodingEnabled allows you to override the Containers value for auto-compressing this route response. +func (b *RouteBuilder) ContentEncodingEnabled(enabled bool) *RouteBuilder { + b.contentEncodingEnabled = &enabled + return b +} + // If no specific Route path then set to rootPath // If no specific Produces then set to rootProduces // If no specific Consumes then set to rootConsumes @@ -235,11 +263,11 @@ func (b *RouteBuilder) Build() Route { pathExpr, err := newPathExpression(b.currentPath) if err != nil { - log.Printf("[restful] Invalid path:%s because:%v", b.currentPath, err) + log.Printf("Invalid path:%s because:%v", b.currentPath, err) os.Exit(1) } if b.function == nil { - log.Printf("[restful] No function specified for route:" + b.currentPath) + log.Printf("No function specified for route:" + b.currentPath) os.Exit(1) } operationName := b.operation @@ -248,22 +276,27 @@ operationName = nameOfFunction(b.function) } route := Route{ - Method: b.httpMethod, - Path: concatPath(b.rootPath, b.currentPath), - Produces: b.produces, - Consumes: b.consumes, - Function: b.function, - Filters: b.filters, - relativePath: b.currentPath, - pathExpr: pathExpr, - Doc: b.doc, - Notes: b.notes, - Operation: operationName, - ParameterDocs: b.parameters, - ResponseErrors: b.errorMap, - ReadSample: b.readSample, - WriteSample: b.writeSample, - Metadata: b.metadata} + Method: b.httpMethod, + Path: concatPath(b.rootPath, b.currentPath), + Produces: b.produces, + Consumes: b.consumes, + Function: b.function, + Filters: b.filters, + If: b.conditions, + relativePath: b.currentPath, + pathExpr: pathExpr, + Doc: b.doc, + Notes: b.notes, + Operation: operationName, + ParameterDocs: b.parameters, + ResponseErrors: b.errorMap, + DefaultResponse: b.defaultResponse, + ReadSample: b.readSample, + WriteSample: b.writeSample, + Metadata: b.metadata, + Deprecated: b.deprecated, + contentEncodingEnabled: b.contentEncodingEnabled, + } route.postBuild() return route } diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/route.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/route.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/route.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/route.go 2022-01-05 17:30:58.000000000 +0000 @@ -5,7 +5,6 @@ // that can be found in the LICENSE file. import ( - "bytes" "net/http" "strings" ) @@ -13,6 +12,11 @@ // RouteFunction declares the signature of a function that can be bound to a Route. type RouteFunction func(*Request, *Response) +// RouteSelectionConditionFunction declares the signature of a function that +// can be used to add extra conditional logic when selecting whether the route +// matches the HTTP request. +type RouteSelectionConditionFunction func(httpRequest *http.Request) bool + // Route binds a HTTP Method,Path,Consumes combination to a RouteFunction. type Route struct { Method string @@ -21,6 +25,7 @@ Path string // webservice root path + described path Function RouteFunction Filters []FilterFunction + If []RouteSelectionConditionFunction // cached values for dispatching relativePath string @@ -33,10 +38,17 @@ Operation string ParameterDocs []*Parameter ResponseErrors map[int]ResponseError + DefaultResponse *ResponseError ReadSample, WriteSample interface{} // structs that model an example request or response payload // Extra information used to store custom information about the route. Metadata map[string]interface{} + + // marks a route as deprecated + Deprecated bool + + //Overrides the container.contentEncodingEnabled + contentEncodingEnabled *bool } // Initialize for Route @@ -45,10 +57,9 @@ } // Create Request and Response from their http versions -func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) { - params := r.extractParameters(httpRequest.URL.Path) +func (r *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request, pathParams map[string]string) (*Request, *Response) { wrappedRequest := NewRequest(httpRequest) - wrappedRequest.pathParameters = params + wrappedRequest.pathParameters = pathParams wrappedRequest.selectedRoutePath = r.Path wrappedResponse := NewResponse(httpWriter) wrappedResponse.requestAccept = httpRequest.Header.Get(HEADER_Accept) @@ -67,28 +78,36 @@ } } +func stringTrimSpaceCutset(r rune) bool { + return r == ' ' +} + // Return whether the mimeType matches to what this Route can produce. func (r Route) matchesAccept(mimeTypesWithQuality string) bool { - parts := strings.Split(mimeTypesWithQuality, ",") - for _, each := range parts { - var withoutQuality string - if strings.Contains(each, ";") { - withoutQuality = strings.Split(each, ";")[0] + remaining := mimeTypesWithQuality + for { + var mimeType string + if end := strings.Index(remaining, ","); end == -1 { + mimeType, remaining = remaining, "" } else { - withoutQuality = each + mimeType, remaining = remaining[:end], remaining[end+1:] } - // trim before compare - withoutQuality = strings.Trim(withoutQuality, " ") - if withoutQuality == "*/*" { + if quality := strings.Index(mimeType, ";"); quality != -1 { + mimeType = mimeType[:quality] + } + mimeType = strings.TrimFunc(mimeType, stringTrimSpaceCutset) + if mimeType == "*/*" { return true } for _, producibleType := range r.Produces { - if producibleType == "*/*" || producibleType == withoutQuality { + if producibleType == "*/*" || producibleType == mimeType { return true } } + if len(remaining) == 0 { + return false + } } - return false } // Return whether this Route can consume content with a type specified by mimeTypes (can be empty). @@ -109,73 +128,33 @@ mimeTypes = MIME_OCTET } - parts := strings.Split(mimeTypes, ",") - for _, each := range parts { - var contentType string - if strings.Contains(each, ";") { - contentType = strings.Split(each, ";")[0] + remaining := mimeTypes + for { + var mimeType string + if end := strings.Index(remaining, ","); end == -1 { + mimeType, remaining = remaining, "" } else { - contentType = each + mimeType, remaining = remaining[:end], remaining[end+1:] + } + if quality := strings.Index(mimeType, ";"); quality != -1 { + mimeType = mimeType[:quality] } - // trim before compare - contentType = strings.Trim(contentType, " ") + mimeType = strings.TrimFunc(mimeType, stringTrimSpaceCutset) for _, consumeableType := range r.Consumes { - if consumeableType == "*/*" || consumeableType == contentType { + if consumeableType == "*/*" || consumeableType == mimeType { return true } } - } - return false -} - -// Extract the parameters from the request url path -func (r Route) extractParameters(urlPath string) map[string]string { - urlParts := tokenizePath(urlPath) - pathParameters := map[string]string{} - for i, key := range r.pathParts { - var value string - if i >= len(urlParts) { - value = "" - } else { - value = urlParts[i] - } - if strings.HasPrefix(key, "{") { // path-parameter - if colon := strings.Index(key, ":"); colon != -1 { - // extract by regex - regPart := key[colon+1 : len(key)-1] - keyPart := key[1:colon] - if regPart == "*" { - pathParameters[keyPart] = untokenizePath(i, urlParts) - break - } else { - pathParameters[keyPart] = value - } - } else { - // without enclosing {} - pathParameters[key[1:len(key)-1]] = value - } - } - } - return pathParameters -} - -// Untokenize back into an URL path using the slash separator -func untokenizePath(offset int, parts []string) string { - var buffer bytes.Buffer - for p := offset; p < len(parts); p++ { - buffer.WriteString(parts[p]) - // do not end - if p < len(parts)-1 { - buffer.WriteString("/") + if len(remaining) == 0 { + return false } } - return buffer.String() } // Tokenize an URL path using the slash separator ; the result does not have empty tokens func tokenizePath(path string) []string { if "/" == path { - return []string{} + return nil } return strings.Split(strings.Trim(path, "/"), "/") } @@ -184,3 +163,8 @@ func (r Route) String() string { return r.Method + " " + r.Path } + +// EnableContentEncoding (default=false) allows for GZIP or DEFLATE encoding of responses. Overrides the container.contentEncodingEnabled value. +func (r Route) EnableContentEncoding(enabled bool) { + r.contentEncodingEnabled = &enabled +} diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/router.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/router.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/router.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/router.go 2022-01-05 17:30:58.000000000 +0000 @@ -7,6 +7,8 @@ import "net/http" // A RouteSelector finds the best matching Route given the input HTTP Request +// RouteSelectors can optionally also implement the PathProcessor interface to also calculate the +// path parameters after the route has been selected. type RouteSelector interface { // SelectRoute finds a Route given the input HTTP Request and a list of WebServices. diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/Srcfile containerd-1.5.9/vendor/github.com/emicklei/go-restful/Srcfile --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/Srcfile 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/Srcfile 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +{"SkipDirs": ["examples"]} diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/.travis.yml containerd-1.5.9/vendor/github.com/emicklei/go-restful/.travis.yml --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,6 @@ +language: go + +go: + - 1.x + +script: go test -v \ No newline at end of file diff -Nru containerd-1.2.6/vendor/github.com/emicklei/go-restful/web_service.go containerd-1.5.9/vendor/github.com/emicklei/go-restful/web_service.go --- containerd-1.2.6/vendor/github.com/emicklei/go-restful/web_service.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/emicklei/go-restful/web_service.go 2022-01-05 17:30:58.000000000 +0000 @@ -60,7 +60,7 @@ func (w *WebService) compilePathExpression() { compiled, err := newPathExpression(w.rootPath) if err != nil { - log.Printf("[restful] invalid path:%s because:%v", w.rootPath, err) + log.Printf("invalid path:%s because:%v", w.rootPath, err) os.Exit(1) } w.pathExpr = compiled @@ -118,7 +118,7 @@ // QueryParameter creates a new Parameter of kind Query for documentation purposes. // It is initialized as not required with string as its DataType. func QueryParameter(name, description string) *Parameter { - p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}} + p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string", CollectionFormat: CollectionFormatCSV.String()}} p.beQuery() return p } diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/AUTHORS containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/AUTHORS --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/AUTHORS 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/AUTHORS 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,52 @@ +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# You can update this list using the following command: +# +# $ git shortlog -se | awk '{print $2 " " $3 " " $4}' + +# Please keep the list sorted. + +Aaron L +Adrien Bustany +Amit Krishnan +Anmol Sethi +Bjørn Erik Pedersen +Bruno Bigras +Caleb Spare +Case Nelson +Chris Howey +Christoffer Buchholz +Daniel Wagner-Hall +Dave Cheney +Evan Phoenix +Francisco Souza +Hari haran +John C Barstow +Kelvin Fo +Ken-ichirou MATSUZAWA +Matt Layher +Nathan Youngman +Nickolai Zeldovich +Patrick +Paul Hammond +Pawel Knap +Pieter Droogendijk +Pursuit92 +Riku Voipio +Rob Figueiredo +Rodrigo Chiossi +Slawek Ligus +Soge Zhang +Tiffany Jernigan +Tilak Sharma +Tom Payne +Travis Cline +Tudor Golubenco +Vahe Khachikyan +Yukang +bronze1man +debrando +henrikedwards +é“å“¥ diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,317 @@ +# Changelog + +## v1.4.7 / 2018-01-09 + +* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) +* Tests: Fix missing verb on format string (thanks @rchiossi) +* Linux: Fix deadlock in Remove (thanks @aarondl) +* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne) +* Docs: Moved FAQ into the README (thanks @vahe) +* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich) +* Docs: replace references to OS X with macOS + +## v1.4.2 / 2016-10-10 + +* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) + +## v1.4.1 / 2016-10-04 + +* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack) + +## v1.4.0 / 2016-10-01 + +* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie) + +## v1.3.1 / 2016-06-28 + +* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc) + +## v1.3.0 / 2016-04-19 + +* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135) + +## v1.2.10 / 2016-03-02 + +* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj) + +## v1.2.9 / 2016-01-13 + +kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep) + +## v1.2.8 / 2015-12-17 + +* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test) +* inotify: fix race in test +* enable race detection for continuous integration (Linux, Mac, Windows) + +## v1.2.5 / 2015-10-17 + +* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki) +* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken) +* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie) +* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion) + +## v1.2.1 / 2015-10-14 + +* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx) + +## v1.2.0 / 2015-02-08 + +* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD) +* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD) +* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59) + +## v1.1.1 / 2015-02-05 + +* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD) + +## v1.1.0 / 2014-12-12 + +* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43) + * add low-level functions + * only need to store flags on directories + * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13) + * done can be an unbuffered channel + * remove calls to os.NewSyscallError +* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher) +* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48) +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## v1.0.4 / 2014-09-07 + +* kqueue: add dragonfly to the build tags. +* Rename source code files, rearrange code so exported APIs are at the top. +* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang) + +## v1.0.3 / 2014-08-19 + +* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36) + +## v1.0.2 / 2014-08-17 + +* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Fix] Make ./path and path equivalent. (thanks @zhsso) + +## v1.0.0 / 2014-08-15 + +* [API] Remove AddWatch on Windows, use Add. +* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30) +* Minor updates based on feedback from golint. + +## dev / 2014-07-09 + +* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify). +* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno) + +## dev / 2014-07-04 + +* kqueue: fix incorrect mutex used in Close() +* Update example to demonstrate usage of Op. + +## dev / 2014-06-28 + +* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4) +* Fix for String() method on Event (thanks Alex Brainman) +* Don't build on Plan 9 or Solaris (thanks @4ad) + +## dev / 2014-06-21 + +* Events channel of type Event rather than *Event. +* [internal] use syscall constants directly for inotify and kqueue. +* [internal] kqueue: rename events to kevents and fileEvent to event. + +## dev / 2014-06-19 + +* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally). +* [internal] remove cookie from Event struct (unused). +* [internal] Event struct has the same definition across every OS. +* [internal] remove internal watch and removeWatch methods. + +## dev / 2014-06-12 + +* [API] Renamed Watch() to Add() and RemoveWatch() to Remove(). +* [API] Pluralized channel names: Events and Errors. +* [API] Renamed FileEvent struct to Event. +* [API] Op constants replace methods like IsCreate(). + +## dev / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## dev / 2014-05-23 + +* [API] Remove current implementation of WatchFlags. + * current implementation doesn't take advantage of OS for efficiency + * provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes + * no tests for the current implementation + * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195) + +## v0.9.3 / 2014-12-31 + +* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51) + +## v0.9.2 / 2014-08-17 + +* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) + +## v0.9.1 / 2014-06-12 + +* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98) + +## v0.9.0 / 2014-01-17 + +* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany) +* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare) +* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library. + +## v0.8.12 / 2013-11-13 + +* [API] Remove FD_SET and friends from Linux adapter + +## v0.8.11 / 2013-11-02 + +* [Doc] Add Changelog [#72][] (thanks @nathany) +* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) + +## v0.8.10 / 2013-10-19 + +* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott) +* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer) +* [Doc] specify OS-specific limits in README (thanks @debrando) + +## v0.8.9 / 2013-09-08 + +* [Doc] Contributing (thanks @nathany) +* [Doc] update package path in example code [#63][] (thanks @paulhammond) +* [Doc] GoCI badge in README (Linux only) [#60][] +* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany) + +## v0.8.8 / 2013-06-17 + +* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie) + +## v0.8.7 / 2013-06-03 + +* [API] Make syscall flags internal +* [Fix] inotify: ignore event changes +* [Fix] race in symlink test [#45][] (reported by @srid) +* [Fix] tests on Windows +* lower case error messages + +## v0.8.6 / 2013-05-23 + +* kqueue: Use EVT_ONLY flag on Darwin +* [Doc] Update README with full example + +## v0.8.5 / 2013-05-09 + +* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg) + +## v0.8.4 / 2013-04-07 + +* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz) + +## v0.8.3 / 2013-03-13 + +* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin) +* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin) + +## v0.8.2 / 2013-02-07 + +* [Doc] add Authors +* [Fix] fix data races for map access [#29][] (thanks @fsouza) + +## v0.8.1 / 2013-01-09 + +* [Fix] Windows path separators +* [Doc] BSD License + +## v0.8.0 / 2012-11-09 + +* kqueue: directory watching improvements (thanks @vmirage) +* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto) +* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr) + +## v0.7.4 / 2012-10-09 + +* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji) +* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig) +* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig) +* [Fix] kqueue: modify after recreation of file + +## v0.7.3 / 2012-09-27 + +* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage) +* [Fix] kqueue: no longer get duplicate CREATE events + +## v0.7.2 / 2012-09-01 + +* kqueue: events for created directories + +## v0.7.1 / 2012-07-14 + +* [Fix] for renaming files + +## v0.7.0 / 2012-07-02 + +* [Feature] FSNotify flags +* [Fix] inotify: Added file name back to event path + +## v0.6.0 / 2012-06-06 + +* kqueue: watch files after directory created (thanks @tmc) + +## v0.5.1 / 2012-05-22 + +* [Fix] inotify: remove all watches before Close() + +## v0.5.0 / 2012-05-03 + +* [API] kqueue: return errors during watch instead of sending over channel +* kqueue: match symlink behavior on Linux +* inotify: add `DELETE_SELF` (requested by @taralx) +* [Fix] kqueue: handle EINTR (reported by @robfig) +* [Doc] Godoc example [#1][] (thanks @davecheney) + +## v0.4.0 / 2012-03-30 + +* Go 1 released: build with go tool +* [Feature] Windows support using winfsnotify +* Windows does not have attribute change notifications +* Roll attribute notifications into IsModify + +## v0.3.0 / 2012-02-19 + +* kqueue: add files when watch directory + +## v0.2.0 / 2011-12-30 + +* update to latest Go weekly code + +## v0.1.0 / 2011-10-19 + +* kqueue: add watch on file creation to match inotify +* kqueue: create file event +* inotify: ignore `IN_IGNORED` events +* event String() +* linux: common FileEvent functions +* initial commit + +[#79]: https://github.com/howeyc/fsnotify/pull/79 +[#77]: https://github.com/howeyc/fsnotify/pull/77 +[#72]: https://github.com/howeyc/fsnotify/issues/72 +[#71]: https://github.com/howeyc/fsnotify/issues/71 +[#70]: https://github.com/howeyc/fsnotify/issues/70 +[#63]: https://github.com/howeyc/fsnotify/issues/63 +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#60]: https://github.com/howeyc/fsnotify/issues/60 +[#59]: https://github.com/howeyc/fsnotify/issues/59 +[#49]: https://github.com/howeyc/fsnotify/issues/49 +[#45]: https://github.com/howeyc/fsnotify/issues/45 +[#40]: https://github.com/howeyc/fsnotify/issues/40 +[#36]: https://github.com/howeyc/fsnotify/issues/36 +[#33]: https://github.com/howeyc/fsnotify/issues/33 +[#29]: https://github.com/howeyc/fsnotify/issues/29 +[#25]: https://github.com/howeyc/fsnotify/issues/25 +[#24]: https://github.com/howeyc/fsnotify/issues/24 +[#21]: https://github.com/howeyc/fsnotify/issues/21 diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,77 @@ +# Contributing + +## Issues + +* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues). +* Please indicate the platform you are using fsnotify on. +* A code example to reproduce the problem is appreciated. + +## Pull Requests + +### Contributor License Agreement + +fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual). + +Please indicate that you have signed the CLA in your pull request. + +### How fsnotify is Developed + +* Development is done on feature branches. +* Tests are run on BSD, Linux, macOS and Windows. +* Pull requests are reviewed and [applied to master][am] using [hub][]. + * Maintainers may modify or squash commits rather than asking contributors to. +* To issue a new release, the maintainers will: + * Update the CHANGELOG + * Tag a version, which will become available through gopkg.in. + +### How to Fork + +For smooth sailing, always use the original import path. Installing with `go get` makes this easy. + +1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Ensure everything works and the tests pass (see below) +4. Commit your changes (`git commit -am 'Add some feature'`) + +Contribute upstream: + +1. Fork fsnotify on GitHub +2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`) +3. Push to the branch (`git push fork my-new-feature`) +4. Create a new Pull Request on GitHub + +This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/). + +### Testing + +fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows. + +Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. + +To aid in cross-platform testing there is a Vagrantfile for Linux and BSD. + +* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/) +* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder. +* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password) +* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`. +* When you're done, you will want to halt or destroy the Vagrant boxes. + +Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory. + +Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). + +### Maintainers + +Help maintaining fsnotify is welcome. To be a maintainer: + +* Submit a pull request and sign the CLA as above. +* You must be able to run the test suite on Mac, Windows, Linux and BSD. + +To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][]. + +All code changes should be internal pull requests. + +Releases are tagged using [Semantic Versioning](http://semver.org/). + +[hub]: https://github.com/github/hub +[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.editorconfig containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.editorconfig --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.editorconfig 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.editorconfig 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +root = true + +[*.go] +indent_style = tab +indent_size = 4 +insert_final_newline = true + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/fen.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/fen.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/fen.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/fen.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris + +package fsnotify + +import ( + "errors" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/fsnotify.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/fsnotify.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/fsnotify.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/fsnotify.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,68 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9 + +// Package fsnotify provides a platform-independent interface for file system notifications. +package fsnotify + +import ( + "bytes" + "errors" + "fmt" +) + +// Event represents a single file system notification. +type Event struct { + Name string // Relative path to the file or directory. + Op Op // File operation that triggered the event. +} + +// Op describes a set of file operations. +type Op uint32 + +// These are the generalized file operations that can trigger a notification. +const ( + Create Op = 1 << iota + Write + Remove + Rename + Chmod +) + +func (op Op) String() string { + // Use a buffer for efficient string concatenation + var buffer bytes.Buffer + + if op&Create == Create { + buffer.WriteString("|CREATE") + } + if op&Remove == Remove { + buffer.WriteString("|REMOVE") + } + if op&Write == Write { + buffer.WriteString("|WRITE") + } + if op&Rename == Rename { + buffer.WriteString("|RENAME") + } + if op&Chmod == Chmod { + buffer.WriteString("|CHMOD") + } + if buffer.Len() == 0 { + return "" + } + return buffer.String()[1:] // Strip leading pipe +} + +// String returns a string representation of the event in the form +// "file: REMOVE|WRITE|..." +func (e Event) String() string { + return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) +} + +// Common errors that can be reported by a watcher +var ( + ErrEventOverflow = errors.New("fsnotify queue overflow") +) diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.gitattributes containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.gitattributes --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.gitattributes 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.gitattributes 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1 @@ +go.sum linguist-generated diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.gitignore containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.gitignore --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.gitignore 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,6 @@ +# Setup a Global .gitignore for OS and editor generated files: +# https://help.github.com/articles/ignoring-files +# git config --global core.excludesfile ~/.gitignore_global + +.vagrant +*.sublime-project diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/go.mod containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/go.mod --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/go.mod 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,5 @@ +module github.com/fsnotify/fsnotify + +go 1.13 + +require golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/go.sum containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/go.sum --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/go.sum 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/inotify.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/inotify.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/inotify.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/inotify.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,337 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package fsnotify + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + mu sync.Mutex // Map access + fd int + poller *fdPoller + watches map[string]*watch // Map of inotify watches (key: path) + paths map[int]string // Map of watched paths (key: watch descriptor) + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + doneResp chan struct{} // Channel to respond to Close +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + // Create inotify fd + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) + if fd == -1 { + return nil, errno + } + // Create epoll + poller, err := newFdPoller(fd) + if err != nil { + unix.Close(fd) + return nil, err + } + w := &Watcher{ + fd: fd, + poller: poller, + watches: make(map[string]*watch), + paths: make(map[int]string), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + doneResp: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + if w.isClosed() { + return nil + } + + // Send 'close' signal to goroutine, and set the Watcher to closed. + close(w.done) + + // Wake up goroutine + w.poller.wake() + + // Wait for goroutine to close + <-w.doneResp + + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + name = filepath.Clean(name) + if w.isClosed() { + return errors.New("inotify instance already closed") + } + + const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | + unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | + unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF + + var flags uint32 = agnosticEvents + + w.mu.Lock() + defer w.mu.Unlock() + watchEntry := w.watches[name] + if watchEntry != nil { + flags |= watchEntry.flags | unix.IN_MASK_ADD + } + wd, errno := unix.InotifyAddWatch(w.fd, name, flags) + if wd == -1 { + return errno + } + + if watchEntry == nil { + w.watches[name] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = name + } else { + watchEntry.wd = uint32(wd) + watchEntry.flags = flags + } + + return nil +} + +// Remove stops watching the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + + // Fetch the watch. + w.mu.Lock() + defer w.mu.Unlock() + watch, ok := w.watches[name] + + // Remove it from inotify. + if !ok { + return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) + } + + // We successfully removed the watch if InotifyRmWatch doesn't return an + // error, we need to clean up our internal state to ensure it matches + // inotify's kernel state. + delete(w.paths, int(watch.wd)) + delete(w.watches, name) + + // inotify_rm_watch will return EINVAL if the file has been deleted; + // the inotify will already have been removed. + // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously + // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE + // so that EINVAL means that the wd is being rm_watch()ed or its file removed + // by another thread and we have not received IN_IGNORE event. + success, errno := unix.InotifyRmWatch(w.fd, watch.wd) + if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case. + // the only two possible errors are: + // EBADF, which happens when w.fd is not a valid file descriptor of any kind. + // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. + // Watch descriptors are invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. + return errno + } + + return nil +} + +type watch struct { + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Events channel +func (w *Watcher) readEvents() { + var ( + buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + n int // Number of bytes read with read() + errno error // Syscall errno + ok bool // For poller.wait + ) + + defer close(w.doneResp) + defer close(w.Errors) + defer close(w.Events) + defer unix.Close(w.fd) + defer w.poller.close() + + for { + // See if we have been closed. + if w.isClosed() { + return + } + + ok, errno = w.poller.wait() + if errno != nil { + select { + case w.Errors <- errno: + case <-w.done: + return + } + continue + } + + if !ok { + continue + } + + n, errno = unix.Read(w.fd, buf[:]) + // If a signal interrupted execution, see if we've been asked to close, and try again. + // http://man7.org/linux/man-pages/man7/signal.7.html : + // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" + if errno == unix.EINTR { + continue + } + + // unix.Read might have been woken up by Close. If so, we're done. + if w.isClosed() { + return + } + + if n < unix.SizeofInotifyEvent { + var err error + if n == 0 { + // If EOF is received. This should really never happen. + err = io.EOF + } else if n < 0 { + // If an error occurred while reading. + err = errno + } else { + // Read was too short. + err = errors.New("notify: short read in readEvents()") + } + select { + case w.Errors <- err: + case <-w.done: + return + } + continue + } + + var offset uint32 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-unix.SizeofInotifyEvent) { + // Point "raw" to the event in the buffer + raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + + mask := uint32(raw.Mask) + nameLen := uint32(raw.Len) + + if mask&unix.IN_Q_OVERFLOW != 0 { + select { + case w.Errors <- ErrEventOverflow: + case <-w.done: + return + } + } + + // If the event happened to the watched directory or the watched file, the kernel + // doesn't append the filename to the event, but we would like to always fill the + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + w.mu.Lock() + name, ok := w.paths[int(raw.Wd)] + // IN_DELETE_SELF occurs when the file/directory being watched is removed. + // This is a sign to clean up the maps, otherwise we are no longer in sync + // with the inotify kernel state which has already deleted the watch + // automatically. + if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + delete(w.paths, int(raw.Wd)) + delete(w.watches, name) + } + w.mu.Unlock() + + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) + // The filename is padded with NULL bytes. TrimRight() gets rid of those. + name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + event := newEvent(name, mask) + + // Send the events that are not ignored on the events channel + if !event.ignoreLinux(mask) { + select { + case w.Events <- event: + case <-w.done: + return + } + } + + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + nameLen + } + } +} + +// Certain types of events can be "ignored" and not sent over the Events +// channel. Such as events marked ignore by the kernel, or MODIFY events +// against files that do not exist. +func (e *Event) ignoreLinux(mask uint32) bool { + // Ignore anything the inotify API says to ignore + if mask&unix.IN_IGNORED == unix.IN_IGNORED { + return true + } + + // If the event is not a DELETE or RENAME, the file must exist. + // Otherwise the event is ignored. + // *Note*: this was put in place because it was seen that a MODIFY + // event was sent after the DELETE. This ignores that MODIFY and + // assumes a DELETE will come or has come if the file doesn't exist. + if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { + _, statErr := os.Lstat(e.Name) + return os.IsNotExist(statErr) + } + return false +} + +// newEvent returns an platform-independent Event based on an inotify mask. +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { + e.Op |= Create + } + if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { + e.Op |= Remove + } + if mask&unix.IN_MODIFY == unix.IN_MODIFY { + e.Op |= Write + } + if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { + e.Op |= Rename + } + if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { + e.Op |= Chmod + } + return e +} diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/inotify_poller.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/inotify_poller.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/inotify_poller.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/inotify_poller.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,187 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package fsnotify + +import ( + "errors" + + "golang.org/x/sys/unix" +) + +type fdPoller struct { + fd int // File descriptor (as returned by the inotify_init() syscall) + epfd int // Epoll file descriptor + pipe [2]int // Pipe for waking up +} + +func emptyPoller(fd int) *fdPoller { + poller := new(fdPoller) + poller.fd = fd + poller.epfd = -1 + poller.pipe[0] = -1 + poller.pipe[1] = -1 + return poller +} + +// Create a new inotify poller. +// This creates an inotify handler, and an epoll handler. +func newFdPoller(fd int) (*fdPoller, error) { + var errno error + poller := emptyPoller(fd) + defer func() { + if errno != nil { + poller.close() + } + }() + poller.fd = fd + + // Create epoll fd + poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC) + if poller.epfd == -1 { + return nil, errno + } + // Create pipe; pipe[0] is the read end, pipe[1] the write end. + errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC) + if errno != nil { + return nil, errno + } + + // Register inotify fd with epoll + event := unix.EpollEvent{ + Fd: int32(poller.fd), + Events: unix.EPOLLIN, + } + errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) + if errno != nil { + return nil, errno + } + + // Register pipe fd with epoll + event = unix.EpollEvent{ + Fd: int32(poller.pipe[0]), + Events: unix.EPOLLIN, + } + errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) + if errno != nil { + return nil, errno + } + + return poller, nil +} + +// Wait using epoll. +// Returns true if something is ready to be read, +// false if there is not. +func (poller *fdPoller) wait() (bool, error) { + // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. + // I don't know whether epoll_wait returns the number of events returned, + // or the total number of events ready. + // I decided to catch both by making the buffer one larger than the maximum. + events := make([]unix.EpollEvent, 7) + for { + n, errno := unix.EpollWait(poller.epfd, events, -1) + if n == -1 { + if errno == unix.EINTR { + continue + } + return false, errno + } + if n == 0 { + // If there are no events, try again. + continue + } + if n > 6 { + // This should never happen. More events were returned than should be possible. + return false, errors.New("epoll_wait returned more events than I know what to do with") + } + ready := events[:n] + epollhup := false + epollerr := false + epollin := false + for _, event := range ready { + if event.Fd == int32(poller.fd) { + if event.Events&unix.EPOLLHUP != 0 { + // This should not happen, but if it does, treat it as a wakeup. + epollhup = true + } + if event.Events&unix.EPOLLERR != 0 { + // If an error is waiting on the file descriptor, we should pretend + // something is ready to read, and let unix.Read pick up the error. + epollerr = true + } + if event.Events&unix.EPOLLIN != 0 { + // There is data to read. + epollin = true + } + } + if event.Fd == int32(poller.pipe[0]) { + if event.Events&unix.EPOLLHUP != 0 { + // Write pipe descriptor was closed, by us. This means we're closing down the + // watcher, and we should wake up. + } + if event.Events&unix.EPOLLERR != 0 { + // If an error is waiting on the pipe file descriptor. + // This is an absolute mystery, and should never ever happen. + return false, errors.New("Error on the pipe descriptor.") + } + if event.Events&unix.EPOLLIN != 0 { + // This is a regular wakeup, so we have to clear the buffer. + err := poller.clearWake() + if err != nil { + return false, err + } + } + } + } + + if epollhup || epollerr || epollin { + return true, nil + } + return false, nil + } +} + +// Close the write end of the poller. +func (poller *fdPoller) wake() error { + buf := make([]byte, 1) + n, errno := unix.Write(poller.pipe[1], buf) + if n == -1 { + if errno == unix.EAGAIN { + // Buffer is full, poller will wake. + return nil + } + return errno + } + return nil +} + +func (poller *fdPoller) clearWake() error { + // You have to be woken up a LOT in order to get to 100! + buf := make([]byte, 100) + n, errno := unix.Read(poller.pipe[0], buf) + if n == -1 { + if errno == unix.EAGAIN { + // Buffer is empty, someone else cleared our wake. + return nil + } + return errno + } + return nil +} + +// Close all poller file descriptors, but not the one passed to it. +func (poller *fdPoller) close() { + if poller.pipe[1] != -1 { + unix.Close(poller.pipe[1]) + } + if poller.pipe[0] != -1 { + unix.Close(poller.pipe[0]) + } + if poller.epfd != -1 { + unix.Close(poller.epfd) + } +} diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/kqueue.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/kqueue.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/kqueue.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/kqueue.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,521 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly darwin + +package fsnotify + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + "time" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + + kq int // File descriptor (as returned by the kqueue() syscall). + + mu sync.Mutex // Protects access to watcher data + watches map[string]int // Map of watched file descriptors (key: path). + externalWatches map[string]bool // Map of watches added by user of the library. + dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue. + paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events. + fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events). + isClosed bool // Set to true when Close() is first called +} + +type pathInfo struct { + name string + isDir bool +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + kq, err := kqueue() + if err != nil { + return nil, err + } + + w := &Watcher{ + kq: kq, + watches: make(map[string]int), + dirFlags: make(map[string]uint32), + paths: make(map[int]pathInfo), + fileExists: make(map[string]bool), + externalWatches: make(map[string]bool), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + + // copy paths to remove while locked + var pathsToRemove = make([]string, 0, len(w.watches)) + for name := range w.watches { + pathsToRemove = append(pathsToRemove, name) + } + w.mu.Unlock() + // unlock before calling Remove, which also locks + + for _, name := range pathsToRemove { + w.Remove(name) + } + + // send a "quit" message to the reader goroutine + close(w.done) + + return nil +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + w.mu.Lock() + w.externalWatches[name] = true + w.mu.Unlock() + _, err := w.addWatch(name, noteAllEvents) + return err +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + w.mu.Lock() + watchfd, ok := w.watches[name] + w.mu.Unlock() + if !ok { + return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) + } + + const registerRemove = unix.EV_DELETE + if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { + return err + } + + unix.Close(watchfd) + + w.mu.Lock() + isDir := w.paths[watchfd].isDir + delete(w.watches, name) + delete(w.paths, watchfd) + delete(w.dirFlags, name) + w.mu.Unlock() + + // Find all watched paths that are in this directory that are not external. + if isDir { + var pathsToRemove []string + w.mu.Lock() + for _, path := range w.paths { + wdir, _ := filepath.Split(path.name) + if filepath.Clean(wdir) == name { + if !w.externalWatches[path.name] { + pathsToRemove = append(pathsToRemove, path.name) + } + } + } + w.mu.Unlock() + for _, name := range pathsToRemove { + // Since these are internal, not much sense in propagating error + // to the user, as that will just confuse them with an error about + // a path they did not explicitly watch themselves. + w.Remove(name) + } + } + + return nil +} + +// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) +const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME + +// keventWaitTime to block on each read from kevent +var keventWaitTime = durationToTimespec(100 * time.Millisecond) + +// addWatch adds name to the watched file set. +// The flags are interpreted as described in kevent(2). +// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. +func (w *Watcher) addWatch(name string, flags uint32) (string, error) { + var isDir bool + // Make ./name and name equivalent + name = filepath.Clean(name) + + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return "", errors.New("kevent instance already closed") + } + watchfd, alreadyWatching := w.watches[name] + // We already have a watch, but we can still override flags. + if alreadyWatching { + isDir = w.paths[watchfd].isDir + } + w.mu.Unlock() + + if !alreadyWatching { + fi, err := os.Lstat(name) + if err != nil { + return "", err + } + + // Don't watch sockets. + if fi.Mode()&os.ModeSocket == os.ModeSocket { + return "", nil + } + + // Don't watch named pipes. + if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { + return "", nil + } + + // Follow Symlinks + // Unfortunately, Linux can add bogus symlinks to watch list without + // issue, and Windows can't do symlinks period (AFAIK). To maintain + // consistency, we will act like everything is fine. There will simply + // be no file events for broken symlinks. + // Hence the returns of nil on errors. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + name, err = filepath.EvalSymlinks(name) + if err != nil { + return "", nil + } + + w.mu.Lock() + _, alreadyWatching = w.watches[name] + w.mu.Unlock() + + if alreadyWatching { + return name, nil + } + + fi, err = os.Lstat(name) + if err != nil { + return "", nil + } + } + + watchfd, err = unix.Open(name, openMode, 0700) + if watchfd == -1 { + return "", err + } + + isDir = fi.IsDir() + } + + const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE + if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { + unix.Close(watchfd) + return "", err + } + + if !alreadyWatching { + w.mu.Lock() + w.watches[name] = watchfd + w.paths[watchfd] = pathInfo{name: name, isDir: isDir} + w.mu.Unlock() + } + + if isDir { + // Watch the directory if it has not been watched before, + // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) + w.mu.Lock() + + watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && + (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) + // Store flags so this watch can be updated later + w.dirFlags[name] = flags + w.mu.Unlock() + + if watchDir { + if err := w.watchDirectoryFiles(name); err != nil { + return "", err + } + } + } + return name, nil +} + +// readEvents reads from kqueue and converts the received kevents into +// Event values that it sends down the Events channel. +func (w *Watcher) readEvents() { + eventBuffer := make([]unix.Kevent_t, 10) + +loop: + for { + // See if there is a message on the "done" channel + select { + case <-w.done: + break loop + default: + } + + // Get new events + kevents, err := read(w.kq, eventBuffer, &keventWaitTime) + // EINTR is okay, the syscall was interrupted before timeout expired. + if err != nil && err != unix.EINTR { + select { + case w.Errors <- err: + case <-w.done: + break loop + } + continue + } + + // Flush the events we received to the Events channel + for len(kevents) > 0 { + kevent := &kevents[0] + watchfd := int(kevent.Ident) + mask := uint32(kevent.Fflags) + w.mu.Lock() + path := w.paths[watchfd] + w.mu.Unlock() + event := newEvent(path.name, mask) + + if path.isDir && !(event.Op&Remove == Remove) { + // Double check to make sure the directory exists. This can happen when + // we do a rm -fr on a recursively watched folders and we receive a + // modification event first but the folder has been deleted and later + // receive the delete event + if _, err := os.Lstat(event.Name); os.IsNotExist(err) { + // mark is as delete event + event.Op |= Remove + } + } + + if event.Op&Rename == Rename || event.Op&Remove == Remove { + w.Remove(event.Name) + w.mu.Lock() + delete(w.fileExists, event.Name) + w.mu.Unlock() + } + + if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { + w.sendDirectoryChangeEvents(event.Name) + } else { + // Send the event on the Events channel. + select { + case w.Events <- event: + case <-w.done: + break loop + } + } + + if event.Op&Remove == Remove { + // Look for a file that may have overwritten this. + // For example, mv f1 f2 will delete f2, then create f2. + if path.isDir { + fileDir := filepath.Clean(event.Name) + w.mu.Lock() + _, found := w.watches[fileDir] + w.mu.Unlock() + if found { + // make sure the directory exists before we watch for changes. When we + // do a recursive watch and perform rm -fr, the parent directory might + // have gone missing, ignore the missing directory and let the + // upcoming delete event remove the watch from the parent directory. + if _, err := os.Lstat(fileDir); err == nil { + w.sendDirectoryChangeEvents(fileDir) + } + } + } else { + filePath := filepath.Clean(event.Name) + if fileInfo, err := os.Lstat(filePath); err == nil { + w.sendFileCreatedEventIfNew(filePath, fileInfo) + } + } + } + + // Move to next event + kevents = kevents[1:] + } + } + + // cleanup + err := unix.Close(w.kq) + if err != nil { + // only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors. + select { + case w.Errors <- err: + default: + } + } + close(w.Events) + close(w.Errors) +} + +// newEvent returns an platform-independent Event based on kqueue Fflags. +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { + e.Op |= Remove + } + if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { + e.Op |= Write + } + if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { + e.Op |= Rename + } + if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { + e.Op |= Chmod + } + return e +} + +func newCreateEvent(name string) Event { + return Event{Name: name, Op: Create} +} + +// watchDirectoryFiles to mimic inotify when adding a watch on a directory +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + return err + } + + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = true + w.mu.Unlock() + } + + return nil +} + +// sendDirectoryEvents searches the directory for newly created files +// and sends them over the event channel. This functionality is to have +// the BSD version of fsnotify match Linux inotify which provides a +// create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + select { + case w.Errors <- err: + case <-w.done: + return + } + } + + // Search for new files + for _, fileInfo := range files { + filePath := filepath.Join(dirPath, fileInfo.Name()) + err := w.sendFileCreatedEventIfNew(filePath, fileInfo) + + if err != nil { + return + } + } +} + +// sendFileCreatedEvent sends a create event if the file isn't already being tracked. +func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { + w.mu.Lock() + _, doesExist := w.fileExists[filePath] + w.mu.Unlock() + if !doesExist { + // Send create event + select { + case w.Events <- newCreateEvent(filePath): + case <-w.done: + return + } + } + + // like watchDirectoryFiles (but without doing another ReadDir) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = true + w.mu.Unlock() + + return nil +} + +func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { + if fileInfo.IsDir() { + // mimic Linux providing delete events for subdirectories + // but preserve the flags used if currently watching subdirectory + w.mu.Lock() + flags := w.dirFlags[name] + w.mu.Unlock() + + flags |= unix.NOTE_DELETE | unix.NOTE_RENAME + return w.addWatch(name, flags) + } + + // watch file to mimic Linux inotify + return w.addWatch(name, noteAllEvents) +} + +// kqueue creates a new kernel event queue and returns a descriptor. +func kqueue() (kq int, err error) { + kq, err = unix.Kqueue() + if kq == -1 { + return kq, err + } + return kq, nil +} + +// register events with the queue +func register(kq int, fds []int, flags int, fflags uint32) error { + changes := make([]unix.Kevent_t, len(fds)) + + for i, fd := range fds { + // SetKevent converts int to the platform-specific types: + unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) + changes[i].Fflags = fflags + } + + // register the events + success, err := unix.Kevent(kq, changes, nil, nil) + if success == -1 { + return err + } + return nil +} + +// read retrieves pending events, or waits until an event occurs. +// A timeout of nil blocks indefinitely, while 0 polls the queue. +func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) { + n, err := unix.Kevent(kq, nil, events, timeout) + if err != nil { + return nil, err + } + return events[0:n], nil +} + +// durationToTimespec prepares a timeout value +func durationToTimespec(d time.Duration) unix.Timespec { + return unix.NsecToTimespec(d.Nanoseconds()) +} diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/LICENSE containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/LICENSE --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/LICENSE 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,28 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2012-2019 fsnotify Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,11 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "golang.org/x/sys/unix" + +const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,12 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package fsnotify + +import "golang.org/x/sys/unix" + +// note: this constant is not defined on BSD +const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/README.md containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/README.md --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/README.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/README.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,130 @@ +# File system notifications for Go + +[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) + +fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running: + +```console +go get -u golang.org/x/sys/... +``` + +Cross platform: Windows, Linux, BSD and macOS. + +| Adapter | OS | Status | +| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| inotify | Linux 2.6.27 or later, Android\* | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) | +| kqueue | BSD, macOS, iOS\* | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) | +| ReadDirectoryChangesW | Windows | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) | +| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | +| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) | +| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) | +| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | +| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | + +\* Android and iOS are untested. + +Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. + +## API stability + +fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). + +All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number. + +Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`. + +## Usage + +```go +package main + +import ( + "log" + + "github.com/fsnotify/fsnotify" +) + +func main() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + done := make(chan bool) + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + log.Println("event:", event) + if event.Op&fsnotify.Write == fsnotify.Write { + log.Println("modified file:", event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("error:", err) + } + } + }() + + err = watcher.Add("/tmp/foo") + if err != nil { + log.Fatal(err) + } + <-done +} +``` + +## Contributing + +Please refer to [CONTRIBUTING][] before opening an issue or pull request. + +## Example + +See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). + +## FAQ + +**When a file is moved to another directory is it still being watched?** + +No (it shouldn't be, unless you are watching where it was moved to). + +**When I watch a directory, are all subdirectories watched as well?** + +No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). + +**Do I have to watch the Error and Event channels in a separate goroutine?** + +As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) + +**Why am I receiving multiple events for the same file on OS X?** + +Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). + +**How many files can be watched at once?** + +There are OS-specific limits as to how many watches can be created: +* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. +* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. + +**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?** + +fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications. + +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#18]: https://github.com/fsnotify/fsnotify/issues/18 +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#7]: https://github.com/howeyc/fsnotify/issues/7 + +[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md + +## Related Projects + +* [notify](https://github.com/rjeczalik/notify) +* [fsevents](https://github.com/fsnotify/fsevents) + diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.travis.yml containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.travis.yml --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/.travis.yml 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,36 @@ +sudo: false +language: go + +go: + - "stable" + - "1.11.x" + - "1.10.x" + - "1.9.x" + +matrix: + include: + - go: "stable" + env: GOLINT=true + allow_failures: + - go: tip + fast_finish: true + + +before_install: + - if [ ! -z "${GOLINT}" ]; then go get -u golang.org/x/lint/golint; fi + +script: + - go test --race ./... + +after_script: + - test -z "$(gofmt -s -l -w . | tee /dev/stderr)" + - if [ ! -z "${GOLINT}" ]; then echo running golint; golint --set_exit_status ./...; else echo skipping golint; fi + - go vet ./... + +os: + - linux + - osx + - windows + +notifications: + email: false diff -Nru containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/windows.go containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/windows.go --- containerd-1.2.6/vendor/github.com/fsnotify/fsnotify/windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/fsnotify/fsnotify/windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,561 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error + isClosed bool // Set to true when Close() is first called + mu sync.Mutex // Map access + port syscall.Handle // Handle to completion port + watches watchMap // Map of watches (key: i-number) + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error +} + +// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. +func NewWatcher() (*Watcher, error) { + port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) + if e != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", e) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + input: make(chan *input, 1), + Events: make(chan Event, 50), + Errors: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + return w, nil +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + if w.isClosed { + return nil + } + w.isClosed = true + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// Add starts watching the named file or directory (non-recursively). +func (w *Watcher) Add(name string) error { + if w.isClosed { + return errors.New("watcher already closed") + } + in := &input{ + op: opAddWatch, + path: filepath.Clean(name), + flags: sysFSALLEVENTS, + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Remove stops watching the the named file or directory (non-recursively). +func (w *Watcher) Remove(name string) error { + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(name), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +const ( + // Options for AddWatch + sysFSONESHOT = 0x80000000 + sysFSONLYDIR = 0x1000000 + + // Events + sysFSACCESS = 0x1 + sysFSALLEVENTS = 0xfff + sysFSATTRIB = 0x4 + sysFSCLOSE = 0x18 + sysFSCREATE = 0x100 + sysFSDELETE = 0x200 + sysFSDELETESELF = 0x400 + sysFSMODIFY = 0x2 + sysFSMOVE = 0xc0 + sysFSMOVEDFROM = 0x40 + sysFSMOVEDTO = 0x80 + sysFSMOVESELF = 0x800 + + // Special events + sysFSIGNORED = 0x8000 + sysFSQOVERFLOW = 0x4000 +) + +func newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { + e.Op |= Create + } + if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { + e.Op |= Remove + } + if mask&sysFSMODIFY == sysFSMODIFY { + e.Op |= Write + } + if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { + e.Op |= Rename + } + if mask&sysFSATTRIB == sysFSATTRIB { + e.Op |= Chmod + } + return e +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + reply chan error +} + +type inode struct { + handle syscall.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov syscall.Overlapped + ino *inode // i-number + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf [4096]byte +} + +type indexMap map[uint64]*watch +type watchMap map[uint32]indexMap + +func (w *Watcher) wakeupReader() error { + e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if e != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", e) + } + return nil +} + +func getDir(pathname string) (dir string, err error) { + attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) + if e != nil { + return "", os.NewSyscallError("GetFileAttributes", e) + } + if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func getIno(path string) (ino *inode, err error) { + h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), + syscall.FILE_LIST_DIRECTORY, + syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, + nil, syscall.OPEN_EXISTING, + syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) + if e != nil { + return nil, os.NewSyscallError("CreateFile", e) + } + var fi syscall.ByHandleFileInformation + if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { + syscall.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", e) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + if flags&sysFSONLYDIR != 0 && pathname != dir { + return nil + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { + syscall.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", e) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + syscall.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + if err = w.startRead(watchEntry); err != nil { + return err + } + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + dir, err := getDir(pathname) + if err != nil { + return err + } + ino, err := getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + if watch == nil { + return fmt.Errorf("can't remove non-existent watch for: %s", pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + if e := syscall.CancelIo(watch.ino.handle); e != nil { + w.Errors <- os.NewSyscallError("CancelIo", e) + w.deleteWatch(watch) + } + mask := toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= toWindowsFlags(m) + } + if mask == 0 { + if e := syscall.CloseHandle(watch.ino.handle); e != nil { + w.Errors <- os.NewSyscallError("CloseHandle", e) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], + uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + if e != nil { + err := os.NewSyscallError("ReadDirectoryChanges", e) + if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) { + if watch.mask&sysFSONESHOT != 0 { + watch.mask = 0 + } + } + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Events channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n, key uint32 + ov *syscall.Overlapped + ) + runtime.LockOSThread() + + for { + e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) + watch := (*watch)(unsafe.Pointer(ov)) + + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + var err error + if e := syscall.CloseHandle(w.port); e != nil { + err = os.NewSyscallError("CloseHandle", e) + } + close(w.Events) + close(w.Errors) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags)) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch e { + case syscall.ERROR_MORE_DATA: + if watch == nil { + w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case syscall.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case syscall.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e) + continue + case nil: + } + + var offset uint32 + for { + if n == 0 { + w.Events <- newEvent("", sysFSQOVERFLOW) + w.Errors <- errors.New("short read in readEvents()") + break + } + + // Point "raw" to the event in the buffer + raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName)) + name := syscall.UTF16ToString(buf[:raw.FileNameLength/2]) + fullname := filepath.Join(watch.path, name) + + var mask uint64 + switch raw.Action { + case syscall.FILE_ACTION_REMOVED: + mask = sysFSDELETESELF + case syscall.FILE_ACTION_MODIFIED: + mask = sysFSMODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sysFSMOVESELF + } + } + + sendNameEvent := func() { + if w.sendEvent(fullname, watch.names[name]&mask) { + if watch.names[name]&sysFSONESHOT != 0 { + delete(watch.names, name) + } + } + } + if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == syscall.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { + if watch.mask&sysFSONESHOT != 0 { + watch.mask = 0 + } + } + if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { + fullname = filepath.Join(watch.path, watch.rename) + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") + break + } + } + + if err := w.startRead(watch); err != nil { + w.Errors <- err + } + } +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + event := newEvent(name, uint32(mask)) + select { + case ch := <-w.quit: + w.quit <- ch + case w.Events <- event: + } + return true +} + +func toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sysFSACCESS != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS + } + if mask&sysFSMODIFY != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&sysFSATTRIB != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES + } + if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { + m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func toFSnotifyFlags(action uint32) uint64 { + switch action { + case syscall.FILE_ACTION_ADDED: + return sysFSCREATE + case syscall.FILE_ACTION_REMOVED: + return sysFSDELETE + case syscall.FILE_ACTION_MODIFIED: + return sysFSMODIFY + case syscall.FILE_ACTION_RENAMED_OLD_NAME: + return sysFSMOVEDFROM + case syscall.FILE_ACTION_RENAMED_NEW_NAME: + return sysFSMOVEDTO + } + return 0 +} diff -Nru containerd-1.2.6/vendor/github.com/ghodss/yaml/fields.go containerd-1.5.9/vendor/github.com/ghodss/yaml/fields.go --- containerd-1.2.6/vendor/github.com/ghodss/yaml/fields.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/ghodss/yaml/fields.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,501 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package yaml - -import ( - "bytes" - "encoding" - "encoding/json" - "reflect" - "sort" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// if it encounters an Unmarshaler, indirect stops and returns that. -// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - v = e - continue - } - } - - if v.Kind() != reflect.Ptr { - break - } - - if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { - break - } - if v.IsNil() { - if v.CanSet() { - v.Set(reflect.New(v.Type().Elem())) - } else { - v = reflect.New(v.Type().Elem()) - } - } - if v.Type().NumMethod() > 0 { - if u, ok := v.Interface().(json.Unmarshaler); ok { - return u, nil, reflect.Value{} - } - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, reflect.Value{} - } - } - v = v.Elem() - } - return nil, nil, v -} - -// A field represents a single field found in a struct. -type field struct { - name string - nameBytes []byte // []byte(name) - equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent - - tag bool - index []int - typ reflect.Type - omitEmpty bool - quoted bool -} - -func fillField(f field) field { - f.nameBytes = []byte(f.name) - f.equalFold = foldFunc(f.nameBytes) - return f -} - -// byName sorts field by name, breaking ties with depth, -// then breaking ties with "name came from json tag", then -// breaking ties with index sequence. -type byName []field - -func (x byName) Len() int { return len(x) } - -func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byName) Less(i, j int) bool { - if x[i].name != x[j].name { - return x[i].name < x[j].name - } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) - } - if x[i].tag != x[j].tag { - return x[i].tag - } - return byIndex(x).Less(i, j) -} - -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { - for k, xik := range x[i].index { - if k >= len(x[j].index) { - return false - } - if xik != x[j].index[k] { - return xik < x[j].index[k] - } - } - return len(x[i].index) < len(x[j].index) -} - -// typeFields returns a list of fields that JSON should recognize for the given type. -// The algorithm is breadth-first search over the set of structs to include - the top struct -// and then any reachable anonymous structs. -func typeFields(t reflect.Type) []field { - // Anonymous fields to explore at the current level and the next. - current := []field{} - next := []field{{typ: t}} - - // Count of queued names for current level and the next. - count := map[reflect.Type]int{} - nextCount := map[reflect.Type]int{} - - // Types already visited at an earlier level. - visited := map[reflect.Type]bool{} - - // Fields found. - var fields []field - - for len(next) > 0 { - current, next = next, current[:0] - count, nextCount = nextCount, map[reflect.Type]int{} - - for _, f := range current { - if visited[f.typ] { - continue - } - visited[f.typ] = true - - // Scan f.typ for fields to include. - for i := 0; i < f.typ.NumField(); i++ { - sf := f.typ.Field(i) - if sf.PkgPath != "" { // unexported - continue - } - tag := sf.Tag.Get("json") - if tag == "-" { - continue - } - name, opts := parseTag(tag) - if !isValidTag(name) { - name = "" - } - index := make([]int, len(f.index)+1) - copy(index, f.index) - index[len(f.index)] = i - - ft := sf.Type - if ft.Name() == "" && ft.Kind() == reflect.Ptr { - // Follow pointer. - ft = ft.Elem() - } - - // Record found field and index sequence. - if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { - tagged := name != "" - if name == "" { - name = sf.Name - } - fields = append(fields, fillField(field{ - name: name, - tag: tagged, - index: index, - typ: ft, - omitEmpty: opts.Contains("omitempty"), - quoted: opts.Contains("string"), - })) - if count[f.typ] > 1 { - // If there were multiple instances, add a second, - // so that the annihilation code will see a duplicate. - // It only cares about the distinction between 1 or 2, - // so don't bother generating any more copies. - fields = append(fields, fields[len(fields)-1]) - } - continue - } - - // Record new anonymous struct to explore in next round. - nextCount[ft]++ - if nextCount[ft] == 1 { - next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) - } - } - } - } - - sort.Sort(byName(fields)) - - // Delete all fields that are hidden by the Go rules for embedded fields, - // except that fields with JSON tags are promoted. - - // The fields are sorted in primary order of name, secondary order - // of field index length. Loop over names; for each name, delete - // hidden fields by choosing the one dominant field that survives. - out := fields[:0] - for advance, i := 0, 0; i < len(fields); i += advance { - // One iteration per name. - // Find the sequence of fields with the name of this first field. - fi := fields[i] - name := fi.name - for advance = 1; i+advance < len(fields); advance++ { - fj := fields[i+advance] - if fj.name != name { - break - } - } - if advance == 1 { // Only one field with this name - out = append(out, fi) - continue - } - dominant, ok := dominantField(fields[i : i+advance]) - if ok { - out = append(out, dominant) - } - } - - fields = out - sort.Sort(byIndex(fields)) - - return fields -} - -// dominantField looks through the fields, all of which are known to -// have the same name, to find the single field that dominates the -// others using Go's embedding rules, modified by the presence of -// JSON tags. If there are multiple top-level fields, the boolean -// will be false: This condition is an error in Go and we skip all -// the fields. -func dominantField(fields []field) (field, bool) { - // The fields are sorted in increasing index-length order. The winner - // must therefore be one with the shortest index length. Drop all - // longer entries, which is easy: just truncate the slice. - length := len(fields[0].index) - tagged := -1 // Index of first tagged field. - for i, f := range fields { - if len(f.index) > length { - fields = fields[:i] - break - } - if f.tag { - if tagged >= 0 { - // Multiple tagged fields at the same level: conflict. - // Return no field. - return field{}, false - } - tagged = i - } - } - if tagged >= 0 { - return fields[tagged], true - } - // All remaining fields have the same length. If there's more than one, - // we have a conflict (two fields named "X" at the same level) and we - // return no field. - if len(fields) > 1 { - return field{}, false - } - return fields[0], true -} - -var fieldCache struct { - sync.RWMutex - m map[reflect.Type][]field -} - -// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) []field { - fieldCache.RLock() - f := fieldCache.m[t] - fieldCache.RUnlock() - if f != nil { - return f - } - - // Compute fields without lock. - // Might duplicate effort but won't hold other computations back. - f = typeFields(t) - if f == nil { - f = []field{} - } - - fieldCache.Lock() - if fieldCache.m == nil { - fieldCache.m = map[reflect.Type][]field{} - } - fieldCache.m[t] = f - fieldCache.Unlock() - return f -} - -func isValidTag(s string) bool { - if s == "" { - return false - } - for _, c := range s { - switch { - case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): - // Backslash and quote chars are reserved, but - // otherwise any punctuation chars are allowed - // in a tag name. - default: - if !unicode.IsLetter(c) && !unicode.IsDigit(c) { - return false - } - } - } - return true -} - -const ( - caseMask = ^byte(0x20) // Mask to ignore case in ASCII. - kelvin = '\u212a' - smallLongEss = '\u017f' -) - -// foldFunc returns one of four different case folding equivalence -// functions, from most general (and slow) to fastest: -// -// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 -// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') -// 3) asciiEqualFold, no special, but includes non-letters (including _) -// 4) simpleLetterEqualFold, no specials, no non-letters. -// -// The letters S and K are special because they map to 3 runes, not just 2: -// * S maps to s and to U+017F 'Å¿' Latin small letter long s -// * k maps to K and to U+212A 'K' Kelvin sign -// See http://play.golang.org/p/tTxjOc0OGo -// -// The returned function is specialized for matching against s and -// should only be given s. It's not curried for performance reasons. -func foldFunc(s []byte) func(s, t []byte) bool { - nonLetter := false - special := false // special letter - for _, b := range s { - if b >= utf8.RuneSelf { - return bytes.EqualFold - } - upper := b & caseMask - if upper < 'A' || upper > 'Z' { - nonLetter = true - } else if upper == 'K' || upper == 'S' { - // See above for why these letters are special. - special = true - } - } - if special { - return equalFoldRight - } - if nonLetter { - return asciiEqualFold - } - return simpleLetterEqualFold -} - -// equalFoldRight is a specialization of bytes.EqualFold when s is -// known to be all ASCII (including punctuation), but contains an 's', -// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. -// See comments on foldFunc. -func equalFoldRight(s, t []byte) bool { - for _, sb := range s { - if len(t) == 0 { - return false - } - tb := t[0] - if tb < utf8.RuneSelf { - if sb != tb { - sbUpper := sb & caseMask - if 'A' <= sbUpper && sbUpper <= 'Z' { - if sbUpper != tb&caseMask { - return false - } - } else { - return false - } - } - t = t[1:] - continue - } - // sb is ASCII and t is not. t must be either kelvin - // sign or long s; sb must be s, S, k, or K. - tr, size := utf8.DecodeRune(t) - switch sb { - case 's', 'S': - if tr != smallLongEss { - return false - } - case 'k', 'K': - if tr != kelvin { - return false - } - default: - return false - } - t = t[size:] - - } - if len(t) > 0 { - return false - } - return true -} - -// asciiEqualFold is a specialization of bytes.EqualFold for use when -// s is all ASCII (but may contain non-letters) and contains no -// special-folding letters. -// See comments on foldFunc. -func asciiEqualFold(s, t []byte) bool { - if len(s) != len(t) { - return false - } - for i, sb := range s { - tb := t[i] - if sb == tb { - continue - } - if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { - if sb&caseMask != tb&caseMask { - return false - } - } else { - return false - } - } - return true -} - -// simpleLetterEqualFold is a specialization of bytes.EqualFold for -// use when s is all ASCII letters (no underscores, etc) and also -// doesn't contain 'k', 'K', 's', or 'S'. -// See comments on foldFunc. -func simpleLetterEqualFold(s, t []byte) bool { - if len(s) != len(t) { - return false - } - for i, b := range s { - if b&caseMask != t[i]&caseMask { - return false - } - } - return true -} - -// tagOptions is the string following a comma in a struct field's "json" -// tag, or the empty string. It does not include the leading comma. -type tagOptions string - -// parseTag splits a struct field's json tag into its name and -// comma-separated options. -func parseTag(tag string) (string, tagOptions) { - if idx := strings.Index(tag, ","); idx != -1 { - return tag[:idx], tagOptions(tag[idx+1:]) - } - return tag, tagOptions("") -} - -// Contains reports whether a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (o tagOptions) Contains(optionName string) bool { - if len(o) == 0 { - return false - } - s := string(o) - for s != "" { - var next string - i := strings.Index(s, ",") - if i >= 0 { - s, next = s[:i], s[i+1:] - } - if s == optionName { - return true - } - s = next - } - return false -} diff -Nru containerd-1.2.6/vendor/github.com/ghodss/yaml/LICENSE containerd-1.5.9/vendor/github.com/ghodss/yaml/LICENSE --- containerd-1.2.6/vendor/github.com/ghodss/yaml/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/ghodss/yaml/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Sam Ghods - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru containerd-1.2.6/vendor/github.com/ghodss/yaml/README.md containerd-1.5.9/vendor/github.com/ghodss/yaml/README.md --- containerd-1.2.6/vendor/github.com/ghodss/yaml/README.md 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/ghodss/yaml/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,121 +0,0 @@ -# YAML marshaling and unmarshaling support for Go - -[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) - -## Introduction - -A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. - -In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). - -## Compatibility - -This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). - -## Caveats - -**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: - -``` -BAD: - exampleKey: !!binary gIGC - -GOOD: - exampleKey: gIGC -... and decode the base64 data in your code. -``` - -**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. - -## Installation and usage - -To install, run: - -``` -$ go get github.com/ghodss/yaml -``` - -And import using: - -``` -import "github.com/ghodss/yaml" -``` - -Usage is very similar to the JSON library: - -```go -package main - -import ( - "fmt" - - "github.com/ghodss/yaml" -) - -type Person struct { - Name string `json:"name"` // Affects YAML field names too. - Age int `json:"age"` -} - -func main() { - // Marshal a Person struct to YAML. - p := Person{"John", 30} - y, err := yaml.Marshal(p) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Println(string(y)) - /* Output: - age: 30 - name: John - */ - - // Unmarshal the YAML back into a Person struct. - var p2 Person - err = yaml.Unmarshal(y, &p2) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Println(p2) - /* Output: - {John 30} - */ -} -``` - -`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: - -```go -package main - -import ( - "fmt" - - "github.com/ghodss/yaml" -) - -func main() { - j := []byte(`{"name": "John", "age": 30}`) - y, err := yaml.JSONToYAML(j) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Println(string(y)) - /* Output: - name: John - age: 30 - */ - j2, err := yaml.YAMLToJSON(y) - if err != nil { - fmt.Printf("err: %v\n", err) - return - } - fmt.Println(string(j2)) - /* Output: - {"age":30,"name":"John"} - */ -} -``` diff -Nru containerd-1.2.6/vendor/github.com/ghodss/yaml/yaml.go containerd-1.5.9/vendor/github.com/ghodss/yaml/yaml.go --- containerd-1.2.6/vendor/github.com/ghodss/yaml/yaml.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/ghodss/yaml/yaml.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,277 +0,0 @@ -package yaml - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" - "strconv" - - "gopkg.in/yaml.v2" -) - -// Marshals the object into JSON then converts JSON to YAML and returns the -// YAML. -func Marshal(o interface{}) ([]byte, error) { - j, err := json.Marshal(o) - if err != nil { - return nil, fmt.Errorf("error marshaling into JSON: %v", err) - } - - y, err := JSONToYAML(j) - if err != nil { - return nil, fmt.Errorf("error converting JSON to YAML: %v", err) - } - - return y, nil -} - -// Converts YAML to JSON then uses JSON to unmarshal into an object. -func Unmarshal(y []byte, o interface{}) error { - vo := reflect.ValueOf(o) - j, err := yamlToJSON(y, &vo) - if err != nil { - return fmt.Errorf("error converting YAML to JSON: %v", err) - } - - err = json.Unmarshal(j, o) - if err != nil { - return fmt.Errorf("error unmarshaling JSON: %v", err) - } - - return nil -} - -// Convert JSON to YAML. -func JSONToYAML(j []byte) ([]byte, error) { - // Convert the JSON to an object. - var jsonObj interface{} - // We are using yaml.Unmarshal here (instead of json.Unmarshal) because the - // Go JSON library doesn't try to pick the right number type (int, float, - // etc.) when unmarshalling to interface{}, it just picks float64 - // universally. go-yaml does go through the effort of picking the right - // number type, so we can preserve number type throughout this process. - err := yaml.Unmarshal(j, &jsonObj) - if err != nil { - return nil, err - } - - // Marshal this object into YAML. - return yaml.Marshal(jsonObj) -} - -// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through -// this method should be a no-op. -// -// Things YAML can do that are not supported by JSON: -// * In YAML you can have binary and null keys in your maps. These are invalid -// in JSON. (int and float keys are converted to strings.) -// * Binary data in YAML with the !!binary tag is not supported. If you want to -// use binary data with this library, encode the data as base64 as usual but do -// not use the !!binary tag in your YAML. This will ensure the original base64 -// encoded data makes it all the way through to the JSON. -func YAMLToJSON(y []byte) ([]byte, error) { - return yamlToJSON(y, nil) -} - -func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) { - // Convert the YAML to an object. - var yamlObj interface{} - err := yaml.Unmarshal(y, &yamlObj) - if err != nil { - return nil, err - } - - // YAML objects are not completely compatible with JSON objects (e.g. you - // can have non-string keys in YAML). So, convert the YAML-compatible object - // to a JSON-compatible object, failing with an error if irrecoverable - // incompatibilties happen along the way. - jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget) - if err != nil { - return nil, err - } - - // Convert this object to JSON and return the data. - return json.Marshal(jsonObj) -} - -func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) { - var err error - - // Resolve jsonTarget to a concrete value (i.e. not a pointer or an - // interface). We pass decodingNull as false because we're not actually - // decoding into the value, we're just checking if the ultimate target is a - // string. - if jsonTarget != nil { - ju, tu, pv := indirect(*jsonTarget, false) - // We have a JSON or Text Umarshaler at this level, so we can't be trying - // to decode into a string. - if ju != nil || tu != nil { - jsonTarget = nil - } else { - jsonTarget = &pv - } - } - - // If yamlObj is a number or a boolean, check if jsonTarget is a string - - // if so, coerce. Else return normal. - // If yamlObj is a map or array, find the field that each key is - // unmarshaling to, and when you recurse pass the reflect.Value for that - // field back into this function. - switch typedYAMLObj := yamlObj.(type) { - case map[interface{}]interface{}: - // JSON does not support arbitrary keys in a map, so we must convert - // these keys to strings. - // - // From my reading of go-yaml v2 (specifically the resolve function), - // keys can only have the types string, int, int64, float64, binary - // (unsupported), or null (unsupported). - strMap := make(map[string]interface{}) - for k, v := range typedYAMLObj { - // Resolve the key to a string first. - var keyString string - switch typedKey := k.(type) { - case string: - keyString = typedKey - case int: - keyString = strconv.Itoa(typedKey) - case int64: - // go-yaml will only return an int64 as a key if the system - // architecture is 32-bit and the key's value is between 32-bit - // and 64-bit. Otherwise the key type will simply be int. - keyString = strconv.FormatInt(typedKey, 10) - case float64: - // Stolen from go-yaml to use the same conversion to string as - // the go-yaml library uses to convert float to string when - // Marshaling. - s := strconv.FormatFloat(typedKey, 'g', -1, 32) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - keyString = s - case bool: - if typedKey { - keyString = "true" - } else { - keyString = "false" - } - default: - return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v", - reflect.TypeOf(k), k, v) - } - - // jsonTarget should be a struct or a map. If it's a struct, find - // the field it's going to map to and pass its reflect.Value. If - // it's a map, find the element type of the map and pass the - // reflect.Value created from that type. If it's neither, just pass - // nil - JSON conversion will error for us if it's a real issue. - if jsonTarget != nil { - t := *jsonTarget - if t.Kind() == reflect.Struct { - keyBytes := []byte(keyString) - // Find the field that the JSON library would use. - var f *field - fields := cachedTypeFields(t.Type()) - for i := range fields { - ff := &fields[i] - if bytes.Equal(ff.nameBytes, keyBytes) { - f = ff - break - } - // Do case-insensitive comparison. - if f == nil && ff.equalFold(ff.nameBytes, keyBytes) { - f = ff - } - } - if f != nil { - // Find the reflect.Value of the most preferential - // struct field. - jtf := t.Field(f.index[0]) - strMap[keyString], err = convertToJSONableObject(v, &jtf) - if err != nil { - return nil, err - } - continue - } - } else if t.Kind() == reflect.Map { - // Create a zero value of the map's element type to use as - // the JSON target. - jtv := reflect.Zero(t.Type().Elem()) - strMap[keyString], err = convertToJSONableObject(v, &jtv) - if err != nil { - return nil, err - } - continue - } - } - strMap[keyString], err = convertToJSONableObject(v, nil) - if err != nil { - return nil, err - } - } - return strMap, nil - case []interface{}: - // We need to recurse into arrays in case there are any - // map[interface{}]interface{}'s inside and to convert any - // numbers to strings. - - // If jsonTarget is a slice (which it really should be), find the - // thing it's going to map to. If it's not a slice, just pass nil - // - JSON conversion will error for us if it's a real issue. - var jsonSliceElemValue *reflect.Value - if jsonTarget != nil { - t := *jsonTarget - if t.Kind() == reflect.Slice { - // By default slices point to nil, but we need a reflect.Value - // pointing to a value of the slice type, so we create one here. - ev := reflect.Indirect(reflect.New(t.Type().Elem())) - jsonSliceElemValue = &ev - } - } - - // Make and use a new array. - arr := make([]interface{}, len(typedYAMLObj)) - for i, v := range typedYAMLObj { - arr[i], err = convertToJSONableObject(v, jsonSliceElemValue) - if err != nil { - return nil, err - } - } - return arr, nil - default: - // If the target type is a string and the YAML type is a number, - // convert the YAML type to a string. - if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String { - // Based on my reading of go-yaml, it may return int, int64, - // float64, or uint64. - var s string - switch typedVal := typedYAMLObj.(type) { - case int: - s = strconv.FormatInt(int64(typedVal), 10) - case int64: - s = strconv.FormatInt(typedVal, 10) - case float64: - s = strconv.FormatFloat(typedVal, 'g', -1, 32) - case uint64: - s = strconv.FormatUint(typedVal, 10) - case bool: - if typedVal { - s = "true" - } else { - s = "false" - } - } - if len(s) > 0 { - yamlObj = interface{}(s) - } - } - return yamlObj, nil - } - - return nil, nil -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/auth_external.go containerd-1.5.9/vendor/github.com/godbus/dbus/auth_external.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/auth_external.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/auth_external.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -package dbus - -import ( - "encoding/hex" -) - -// AuthExternal returns an Auth that authenticates as the given user with the -// EXTERNAL mechanism. -func AuthExternal(user string) Auth { - return authExternal{user} -} - -// AuthExternal implements the EXTERNAL authentication mechanism. -type authExternal struct { - user string -} - -func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) { - b := make([]byte, 2*len(a.user)) - hex.Encode(b, []byte(a.user)) - return []byte("EXTERNAL"), b, AuthOk -} - -func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) { - return nil, AuthError -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/auth.go containerd-1.5.9/vendor/github.com/godbus/dbus/auth.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/auth.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/auth.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,253 +0,0 @@ -package dbus - -import ( - "bufio" - "bytes" - "errors" - "io" - "os" - "strconv" -) - -// AuthStatus represents the Status of an authentication mechanism. -type AuthStatus byte - -const ( - // AuthOk signals that authentication is finished; the next command - // from the server should be an OK. - AuthOk AuthStatus = iota - - // AuthContinue signals that additional data is needed; the next command - // from the server should be a DATA. - AuthContinue - - // AuthError signals an error; the server sent invalid data or some - // other unexpected thing happened and the current authentication - // process should be aborted. - AuthError -) - -type authState byte - -const ( - waitingForData authState = iota - waitingForOk - waitingForReject -) - -// Auth defines the behaviour of an authentication mechanism. -type Auth interface { - // Return the name of the mechnism, the argument to the first AUTH command - // and the next status. - FirstData() (name, resp []byte, status AuthStatus) - - // Process the given DATA command, and return the argument to the DATA - // command and the next status. If len(resp) == 0, no DATA command is sent. - HandleData(data []byte) (resp []byte, status AuthStatus) -} - -// Auth authenticates the connection, trying the given list of authentication -// mechanisms (in that order). If nil is passed, the EXTERNAL and -// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private -// connections, this method must be called before sending any messages to the -// bus. Auth must not be called on shared connections. -func (conn *Conn) Auth(methods []Auth) error { - if methods == nil { - uid := strconv.Itoa(os.Getuid()) - methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} - } - in := bufio.NewReader(conn.transport) - err := conn.transport.SendNullByte() - if err != nil { - return err - } - err = authWriteLine(conn.transport, []byte("AUTH")) - if err != nil { - return err - } - s, err := authReadLine(in) - if err != nil { - return err - } - if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) { - return errors.New("dbus: authentication protocol error") - } - s = s[1:] - for _, v := range s { - for _, m := range methods { - if name, data, status := m.FirstData(); bytes.Equal(v, name) { - var ok bool - err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data) - if err != nil { - return err - } - switch status { - case AuthOk: - err, ok = conn.tryAuth(m, waitingForOk, in) - case AuthContinue: - err, ok = conn.tryAuth(m, waitingForData, in) - default: - panic("dbus: invalid authentication status") - } - if err != nil { - return err - } - if ok { - if conn.transport.SupportsUnixFDs() { - err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD")) - if err != nil { - return err - } - line, err := authReadLine(in) - if err != nil { - return err - } - switch { - case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")): - conn.EnableUnixFDs() - conn.unixFD = true - case bytes.Equal(line[0], []byte("ERROR")): - default: - return errors.New("dbus: authentication protocol error") - } - } - err = authWriteLine(conn.transport, []byte("BEGIN")) - if err != nil { - return err - } - go conn.inWorker() - go conn.outWorker() - return nil - } - } - } - } - return errors.New("dbus: authentication failed") -} - -// tryAuth tries to authenticate with m as the mechanism, using state as the -// initial authState and in for reading input. It returns (nil, true) on -// success, (nil, false) on a REJECTED and (someErr, false) if some other -// error occured. -func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) { - for { - s, err := authReadLine(in) - if err != nil { - return err, false - } - switch { - case state == waitingForData && string(s[0]) == "DATA": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - continue - } - data, status := m.HandleData(s[1]) - switch status { - case AuthOk, AuthContinue: - if len(data) != 0 { - err = authWriteLine(conn.transport, []byte("DATA"), data) - if err != nil { - return err, false - } - } - if status == AuthOk { - state = waitingForOk - } - case AuthError: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - } - case state == waitingForData && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForData && string(s[0]) == "ERROR": - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - case state == waitingForData && string(s[0]) == "OK": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - } - conn.uuid = string(s[1]) - return nil, true - case state == waitingForData: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - case state == waitingForOk && string(s[0]) == "OK": - if len(s) != 2 { - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - } - conn.uuid = string(s[1]) - return nil, true - case state == waitingForOk && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForOk && (string(s[0]) == "DATA" || - string(s[0]) == "ERROR"): - - err = authWriteLine(conn.transport, []byte("CANCEL")) - if err != nil { - return err, false - } - state = waitingForReject - case state == waitingForOk: - err = authWriteLine(conn.transport, []byte("ERROR")) - if err != nil { - return err, false - } - case state == waitingForReject && string(s[0]) == "REJECTED": - return nil, false - case state == waitingForReject: - return errors.New("dbus: authentication protocol error"), false - default: - panic("dbus: invalid auth state") - } - } -} - -// authReadLine reads a line and separates it into its fields. -func authReadLine(in *bufio.Reader) ([][]byte, error) { - data, err := in.ReadBytes('\n') - if err != nil { - return nil, err - } - data = bytes.TrimSuffix(data, []byte("\r\n")) - return bytes.Split(data, []byte{' '}), nil -} - -// authWriteLine writes the given line in the authentication protocol format -// (elements of data separated by a " " and terminated by "\r\n"). -func authWriteLine(out io.Writer, data ...[]byte) error { - buf := make([]byte, 0) - for i, v := range data { - buf = append(buf, v...) - if i != len(data)-1 { - buf = append(buf, ' ') - } - } - buf = append(buf, '\r') - buf = append(buf, '\n') - n, err := out.Write(buf) - if err != nil { - return err - } - if n != len(buf) { - return io.ErrUnexpectedEOF - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/auth_sha1.go containerd-1.5.9/vendor/github.com/godbus/dbus/auth_sha1.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/auth_sha1.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/auth_sha1.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -package dbus - -import ( - "bufio" - "bytes" - "crypto/rand" - "crypto/sha1" - "encoding/hex" - "os" -) - -// AuthCookieSha1 returns an Auth that authenticates as the given user with the -// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home -// directory of the user. -func AuthCookieSha1(user, home string) Auth { - return authCookieSha1{user, home} -} - -type authCookieSha1 struct { - user, home string -} - -func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) { - b := make([]byte, 2*len(a.user)) - hex.Encode(b, []byte(a.user)) - return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue -} - -func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) { - challenge := make([]byte, len(data)/2) - _, err := hex.Decode(challenge, data) - if err != nil { - return nil, AuthError - } - b := bytes.Split(challenge, []byte{' '}) - if len(b) != 3 { - return nil, AuthError - } - context := b[0] - id := b[1] - svchallenge := b[2] - cookie := a.getCookie(context, id) - if cookie == nil { - return nil, AuthError - } - clchallenge := a.generateChallenge() - if clchallenge == nil { - return nil, AuthError - } - hash := sha1.New() - hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'})) - hexhash := make([]byte, 2*hash.Size()) - hex.Encode(hexhash, hash.Sum(nil)) - data = append(clchallenge, ' ') - data = append(data, hexhash...) - resp := make([]byte, 2*len(data)) - hex.Encode(resp, data) - return resp, AuthOk -} - -// getCookie searches for the cookie identified by id in context and returns -// the cookie content or nil. (Since HandleData can't return a specific error, -// but only whether an error occured, this function also doesn't bother to -// return an error.) -func (a authCookieSha1) getCookie(context, id []byte) []byte { - file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context)) - if err != nil { - return nil - } - defer file.Close() - rd := bufio.NewReader(file) - for { - line, err := rd.ReadBytes('\n') - if err != nil { - return nil - } - line = line[:len(line)-1] - b := bytes.Split(line, []byte{' '}) - if len(b) != 3 { - return nil - } - if bytes.Equal(b[0], id) { - return b[2] - } - } -} - -// generateChallenge returns a random, hex-encoded challenge, or nil on error -// (see above). -func (a authCookieSha1) generateChallenge() []byte { - b := make([]byte, 16) - n, err := rand.Read(b) - if err != nil { - return nil - } - if n != 16 { - return nil - } - enc := make([]byte, 32) - hex.Encode(enc, b) - return enc -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/call.go containerd-1.5.9/vendor/github.com/godbus/dbus/call.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/call.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/call.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -package dbus - -import ( - "errors" -) - -// Call represents a pending or completed method call. -type Call struct { - Destination string - Path ObjectPath - Method string - Args []interface{} - - // Strobes when the call is complete. - Done chan *Call - - // After completion, the error status. If this is non-nil, it may be an - // error message from the peer (with Error as its type) or some other error. - Err error - - // Holds the response once the call is done. - Body []interface{} -} - -var errSignature = errors.New("dbus: mismatched signature") - -// Store stores the body of the reply into the provided pointers. It returns -// an error if the signatures of the body and retvalues don't match, or if -// the error status is not nil. -func (c *Call) Store(retvalues ...interface{}) error { - if c.Err != nil { - return c.Err - } - - return Store(c.Body, retvalues...) -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/conn_darwin.go containerd-1.5.9/vendor/github.com/godbus/dbus/conn_darwin.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/conn_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/conn_darwin.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -package dbus - -import ( - "errors" - "os/exec" -) - -func sessionBusPlatform() (*Conn, error) { - cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET") - b, err := cmd.CombinedOutput() - - if err != nil { - return nil, err - } - - if len(b) == 0 { - return nil, errors.New("dbus: couldn't determine address of session bus") - } - - return Dial("unix:path=" + string(b[:len(b)-1])) -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/conn.go containerd-1.5.9/vendor/github.com/godbus/dbus/conn.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/conn.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/conn.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,625 +0,0 @@ -package dbus - -import ( - "errors" - "io" - "os" - "reflect" - "strings" - "sync" -) - -const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" - -var ( - systemBus *Conn - systemBusLck sync.Mutex - sessionBus *Conn - sessionBusLck sync.Mutex -) - -// ErrClosed is the error returned by calls on a closed connection. -var ErrClosed = errors.New("dbus: connection closed by user") - -// Conn represents a connection to a message bus (usually, the system or -// session bus). -// -// Connections are either shared or private. Shared connections -// are shared between calls to the functions that return them. As a result, -// the methods Close, Auth and Hello must not be called on them. -// -// Multiple goroutines may invoke methods on a connection simultaneously. -type Conn struct { - transport - - busObj BusObject - unixFD bool - uuid string - - names []string - namesLck sync.RWMutex - - serialLck sync.Mutex - nextSerial uint32 - serialUsed map[uint32]bool - - calls map[uint32]*Call - callsLck sync.RWMutex - - handlers map[ObjectPath]map[string]exportWithMapping - handlersLck sync.RWMutex - - out chan *Message - closed bool - outLck sync.RWMutex - - signals []chan<- *Signal - signalsLck sync.Mutex - - eavesdropped chan<- *Message - eavesdroppedLck sync.Mutex -} - -// SessionBus returns a shared connection to the session bus, connecting to it -// if not already done. -func SessionBus() (conn *Conn, err error) { - sessionBusLck.Lock() - defer sessionBusLck.Unlock() - if sessionBus != nil { - return sessionBus, nil - } - defer func() { - if conn != nil { - sessionBus = conn - } - }() - conn, err = SessionBusPrivate() - if err != nil { - return - } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return - } - if err = conn.Hello(); err != nil { - conn.Close() - conn = nil - } - return -} - -// SessionBusPrivate returns a new private connection to the session bus. -func SessionBusPrivate() (*Conn, error) { - address := os.Getenv("DBUS_SESSION_BUS_ADDRESS") - if address != "" && address != "autolaunch:" { - return Dial(address) - } - - return sessionBusPlatform() -} - -// SystemBus returns a shared connection to the system bus, connecting to it if -// not already done. -func SystemBus() (conn *Conn, err error) { - systemBusLck.Lock() - defer systemBusLck.Unlock() - if systemBus != nil { - return systemBus, nil - } - defer func() { - if conn != nil { - systemBus = conn - } - }() - conn, err = SystemBusPrivate() - if err != nil { - return - } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return - } - if err = conn.Hello(); err != nil { - conn.Close() - conn = nil - } - return -} - -// SystemBusPrivate returns a new private connection to the system bus. -func SystemBusPrivate() (*Conn, error) { - address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") - if address != "" { - return Dial(address) - } - return Dial(defaultSystemBusAddress) -} - -// Dial establishes a new private connection to the message bus specified by address. -func Dial(address string) (*Conn, error) { - tr, err := getTransport(address) - if err != nil { - return nil, err - } - return newConn(tr) -} - -// NewConn creates a new private *Conn from an already established connection. -func NewConn(conn io.ReadWriteCloser) (*Conn, error) { - return newConn(genericTransport{conn}) -} - -// newConn creates a new *Conn from a transport. -func newConn(tr transport) (*Conn, error) { - conn := new(Conn) - conn.transport = tr - conn.calls = make(map[uint32]*Call) - conn.out = make(chan *Message, 10) - conn.handlers = make(map[ObjectPath]map[string]exportWithMapping) - conn.nextSerial = 1 - conn.serialUsed = map[uint32]bool{0: true} - conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") - return conn, nil -} - -// BusObject returns the object owned by the bus daemon which handles -// administrative requests. -func (conn *Conn) BusObject() BusObject { - return conn.busObj -} - -// Close closes the connection. Any blocked operations will return with errors -// and the channels passed to Eavesdrop and Signal are closed. This method must -// not be called on shared connections. -func (conn *Conn) Close() error { - conn.outLck.Lock() - if conn.closed { - // inWorker calls Close on read error, the read error may - // be caused by another caller calling Close to shutdown the - // dbus connection, a double-close scenario we prevent here. - conn.outLck.Unlock() - return nil - } - close(conn.out) - conn.closed = true - conn.outLck.Unlock() - conn.signalsLck.Lock() - for _, ch := range conn.signals { - close(ch) - } - conn.signalsLck.Unlock() - conn.eavesdroppedLck.Lock() - if conn.eavesdropped != nil { - close(conn.eavesdropped) - } - conn.eavesdroppedLck.Unlock() - return conn.transport.Close() -} - -// Eavesdrop causes conn to send all incoming messages to the given channel -// without further processing. Method replies, errors and signals will not be -// sent to the appropiate channels and method calls will not be handled. If nil -// is passed, the normal behaviour is restored. -// -// The caller has to make sure that ch is sufficiently buffered; -// if a message arrives when a write to ch is not possible, the message is -// discarded. -func (conn *Conn) Eavesdrop(ch chan<- *Message) { - conn.eavesdroppedLck.Lock() - conn.eavesdropped = ch - conn.eavesdroppedLck.Unlock() -} - -// getSerial returns an unused serial. -func (conn *Conn) getSerial() uint32 { - conn.serialLck.Lock() - defer conn.serialLck.Unlock() - n := conn.nextSerial - for conn.serialUsed[n] { - n++ - } - conn.serialUsed[n] = true - conn.nextSerial = n + 1 - return n -} - -// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be -// called after authentication, but before sending any other messages to the -// bus. Hello must not be called for shared connections. -func (conn *Conn) Hello() error { - var s string - err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s) - if err != nil { - return err - } - conn.namesLck.Lock() - conn.names = make([]string, 1) - conn.names[0] = s - conn.namesLck.Unlock() - return nil -} - -// inWorker runs in an own goroutine, reading incoming messages from the -// transport and dispatching them appropiately. -func (conn *Conn) inWorker() { - for { - msg, err := conn.ReadMessage() - if err == nil { - conn.eavesdroppedLck.Lock() - if conn.eavesdropped != nil { - select { - case conn.eavesdropped <- msg: - default: - } - conn.eavesdroppedLck.Unlock() - continue - } - conn.eavesdroppedLck.Unlock() - dest, _ := msg.Headers[FieldDestination].value.(string) - found := false - if dest == "" { - found = true - } else { - conn.namesLck.RLock() - if len(conn.names) == 0 { - found = true - } - for _, v := range conn.names { - if dest == v { - found = true - break - } - } - conn.namesLck.RUnlock() - } - if !found { - // Eavesdropped a message, but no channel for it is registered. - // Ignore it. - continue - } - switch msg.Type { - case TypeMethodReply, TypeError: - serial := msg.Headers[FieldReplySerial].value.(uint32) - conn.callsLck.Lock() - if c, ok := conn.calls[serial]; ok { - if msg.Type == TypeError { - name, _ := msg.Headers[FieldErrorName].value.(string) - c.Err = Error{name, msg.Body} - } else { - c.Body = msg.Body - } - c.Done <- c - conn.serialLck.Lock() - delete(conn.serialUsed, serial) - conn.serialLck.Unlock() - delete(conn.calls, serial) - } - conn.callsLck.Unlock() - case TypeSignal: - iface := msg.Headers[FieldInterface].value.(string) - member := msg.Headers[FieldMember].value.(string) - // as per http://dbus.freedesktop.org/doc/dbus-specification.html , - // sender is optional for signals. - sender, _ := msg.Headers[FieldSender].value.(string) - if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { - if member == "NameLost" { - // If we lost the name on the bus, remove it from our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the lost name") - } - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - conn.names = append(conn.names[:i], - conn.names[i+1:]...) - } - } - conn.namesLck.Unlock() - } else if member == "NameAcquired" { - // If we acquired the name on the bus, add it to our - // tracking list. - name, ok := msg.Body[0].(string) - if !ok { - panic("Unable to read the acquired name") - } - conn.namesLck.Lock() - conn.names = append(conn.names, name) - conn.namesLck.Unlock() - } - } - signal := &Signal{ - Sender: sender, - Path: msg.Headers[FieldPath].value.(ObjectPath), - Name: iface + "." + member, - Body: msg.Body, - } - conn.signalsLck.Lock() - for _, ch := range conn.signals { - ch <- signal - } - conn.signalsLck.Unlock() - case TypeMethodCall: - go conn.handleCall(msg) - } - } else if _, ok := err.(InvalidMessageError); !ok { - // Some read error occured (usually EOF); we can't really do - // anything but to shut down all stuff and returns errors to all - // pending replies. - conn.Close() - conn.callsLck.RLock() - for _, v := range conn.calls { - v.Err = err - v.Done <- v - } - conn.callsLck.RUnlock() - return - } - // invalid messages are ignored - } -} - -// Names returns the list of all names that are currently owned by this -// connection. The slice is always at least one element long, the first element -// being the unique name of the connection. -func (conn *Conn) Names() []string { - conn.namesLck.RLock() - // copy the slice so it can't be modified - s := make([]string, len(conn.names)) - copy(s, conn.names) - conn.namesLck.RUnlock() - return s -} - -// Object returns the object identified by the given destination name and path. -func (conn *Conn) Object(dest string, path ObjectPath) BusObject { - return &Object{conn, dest, path} -} - -// outWorker runs in an own goroutine, encoding and sending messages that are -// sent to conn.out. -func (conn *Conn) outWorker() { - for msg := range conn.out { - err := conn.SendMessage(msg) - conn.callsLck.RLock() - if err != nil { - if c := conn.calls[msg.serial]; c != nil { - c.Err = err - c.Done <- c - } - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } else if msg.Type != TypeMethodCall { - conn.serialLck.Lock() - delete(conn.serialUsed, msg.serial) - conn.serialLck.Unlock() - } - conn.callsLck.RUnlock() - } -} - -// Send sends the given message to the message bus. You usually don't need to -// use this; use the higher-level equivalents (Call / Go, Emit and Export) -// instead. If msg is a method call and NoReplyExpected is not set, a non-nil -// call is returned and the same value is sent to ch (which must be buffered) -// once the call is complete. Otherwise, ch is ignored and a Call structure is -// returned of which only the Err member is valid. -func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { - var call *Call - - msg.serial = conn.getSerial() - if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 5) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Conn).Send") - } - call = new(Call) - call.Destination, _ = msg.Headers[FieldDestination].value.(string) - call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) - iface, _ := msg.Headers[FieldInterface].value.(string) - member, _ := msg.Headers[FieldMember].value.(string) - call.Method = iface + "." + member - call.Args = msg.Body - call.Done = ch - conn.callsLck.Lock() - conn.calls[msg.serial] = call - conn.callsLck.Unlock() - conn.outLck.RLock() - if conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - conn.out <- msg - } - conn.outLck.RUnlock() - } else { - conn.outLck.RLock() - if conn.closed { - call = &Call{Err: ErrClosed} - } else { - conn.out <- msg - call = &Call{Err: nil} - } - conn.outLck.RUnlock() - } - return call -} - -// sendError creates an error message corresponding to the parameters and sends -// it to conn.out. -func (conn *Conn) sendError(e Error, dest string, serial uint32) { - msg := new(Message) - msg.Type = TypeError - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - if dest != "" { - msg.Headers[FieldDestination] = MakeVariant(dest) - } - msg.Headers[FieldErrorName] = MakeVariant(e.Name) - msg.Headers[FieldReplySerial] = MakeVariant(serial) - msg.Body = e.Body - if len(e.Body) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() -} - -// sendReply creates a method reply message corresponding to the parameters and -// sends it to conn.out. -func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { - msg := new(Message) - msg.Type = TypeMethodReply - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - if dest != "" { - msg.Headers[FieldDestination] = MakeVariant(dest) - } - msg.Headers[FieldReplySerial] = MakeVariant(serial) - msg.Body = values - if len(values) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- msg - } - conn.outLck.RUnlock() -} - -// Signal registers the given channel to be passed all received signal messages. -// The caller has to make sure that ch is sufficiently buffered; if a message -// arrives when a write to c is not possible, it is discarded. -// -// Multiple of these channels can be registered at the same time. Passing a -// channel that already is registered will remove it from the list of the -// registered channels. -// -// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a -// channel for eavesdropped messages, this channel receives all signals, and -// none of the channels passed to Signal will receive any signals. -func (conn *Conn) Signal(ch chan<- *Signal) { - conn.signalsLck.Lock() - conn.signals = append(conn.signals, ch) - conn.signalsLck.Unlock() -} - -// SupportsUnixFDs returns whether the underlying transport supports passing of -// unix file descriptors. If this is false, method calls containing unix file -// descriptors will return an error and emitted signals containing them will -// not be sent. -func (conn *Conn) SupportsUnixFDs() bool { - return conn.unixFD -} - -// Error represents a D-Bus message of type Error. -type Error struct { - Name string - Body []interface{} -} - -func NewError(name string, body []interface{}) *Error { - return &Error{name, body} -} - -func (e Error) Error() string { - if len(e.Body) >= 1 { - s, ok := e.Body[0].(string) - if ok { - return s - } - } - return e.Name -} - -// Signal represents a D-Bus message of type Signal. The name member is given in -// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. -type Signal struct { - Sender string - Path ObjectPath - Name string - Body []interface{} -} - -// transport is a D-Bus transport. -type transport interface { - // Read and Write raw data (for example, for the authentication protocol). - io.ReadWriteCloser - - // Send the initial null byte used for the EXTERNAL mechanism. - SendNullByte() error - - // Returns whether this transport supports passing Unix FDs. - SupportsUnixFDs() bool - - // Signal the transport that Unix FD passing is enabled for this connection. - EnableUnixFDs() - - // Read / send a message, handling things like Unix FDs. - ReadMessage() (*Message, error) - SendMessage(*Message) error -} - -var ( - transports = make(map[string]func(string) (transport, error)) -) - -func getTransport(address string) (transport, error) { - var err error - var t transport - - addresses := strings.Split(address, ";") - for _, v := range addresses { - i := strings.IndexRune(v, ':') - if i == -1 { - err = errors.New("dbus: invalid bus address (no transport)") - continue - } - f := transports[v[:i]] - if f == nil { - err = errors.New("dbus: invalid bus address (invalid or unsupported transport)") - continue - } - t, err = f(v[i+1:]) - if err == nil { - return t, nil - } - } - return nil, err -} - -// dereferenceAll returns a slice that, assuming that vs is a slice of pointers -// of arbitrary types, containes the values that are obtained from dereferencing -// all elements in vs. -func dereferenceAll(vs []interface{}) []interface{} { - for i := range vs { - v := reflect.ValueOf(vs[i]) - v = v.Elem() - vs[i] = v.Interface() - } - return vs -} - -// getKey gets a key from a the list of keys. Returns "" on error / not found... -func getKey(s, key string) string { - i := strings.Index(s, key) - if i == -1 { - return "" - } - if i+len(key)+1 >= len(s) || s[i+len(key)] != '=' { - return "" - } - j := strings.Index(s, ",") - if j == -1 { - j = len(s) - } - return s[i+len(key)+1 : j] -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/conn_other.go containerd-1.5.9/vendor/github.com/godbus/dbus/conn_other.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/conn_other.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/conn_other.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -// +build !darwin - -package dbus - -import ( - "bytes" - "errors" - "os/exec" -) - -func sessionBusPlatform() (*Conn, error) { - cmd := exec.Command("dbus-launch") - b, err := cmd.CombinedOutput() - - if err != nil { - return nil, err - } - - i := bytes.IndexByte(b, '=') - j := bytes.IndexByte(b, '\n') - - if i == -1 || j == -1 { - return nil, errors.New("dbus: couldn't determine address of session bus") - } - - return Dial(string(b[i+1 : j])) -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/dbus.go containerd-1.5.9/vendor/github.com/godbus/dbus/dbus.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/dbus.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/dbus.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -package dbus - -import ( - "errors" - "reflect" - "strings" -) - -var ( - byteType = reflect.TypeOf(byte(0)) - boolType = reflect.TypeOf(false) - uint8Type = reflect.TypeOf(uint8(0)) - int16Type = reflect.TypeOf(int16(0)) - uint16Type = reflect.TypeOf(uint16(0)) - int32Type = reflect.TypeOf(int32(0)) - uint32Type = reflect.TypeOf(uint32(0)) - int64Type = reflect.TypeOf(int64(0)) - uint64Type = reflect.TypeOf(uint64(0)) - float64Type = reflect.TypeOf(float64(0)) - stringType = reflect.TypeOf("") - signatureType = reflect.TypeOf(Signature{""}) - objectPathType = reflect.TypeOf(ObjectPath("")) - variantType = reflect.TypeOf(Variant{Signature{""}, nil}) - interfacesType = reflect.TypeOf([]interface{}{}) - unixFDType = reflect.TypeOf(UnixFD(0)) - unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) -) - -// An InvalidTypeError signals that a value which cannot be represented in the -// D-Bus wire format was passed to a function. -type InvalidTypeError struct { - Type reflect.Type -} - -func (e InvalidTypeError) Error() string { - return "dbus: invalid type " + e.Type.String() -} - -// Store copies the values contained in src to dest, which must be a slice of -// pointers. It converts slices of interfaces from src to corresponding structs -// in dest. An error is returned if the lengths of src and dest or the types of -// their elements don't match. -func Store(src []interface{}, dest ...interface{}) error { - if len(src) != len(dest) { - return errors.New("dbus.Store: length mismatch") - } - - for i := range src { - if err := store(src[i], dest[i]); err != nil { - return err - } - } - return nil -} - -func store(src, dest interface{}) error { - if reflect.TypeOf(dest).Elem() == reflect.TypeOf(src) { - reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src)) - return nil - } else if hasStruct(dest) { - rv := reflect.ValueOf(dest).Elem() - switch rv.Kind() { - case reflect.Struct: - vs, ok := src.([]interface{}) - if !ok { - return errors.New("dbus.Store: type mismatch") - } - t := rv.Type() - ndest := make([]interface{}, 0, rv.NumField()) - for i := 0; i < rv.NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - ndest = append(ndest, rv.Field(i).Addr().Interface()) - } - } - if len(vs) != len(ndest) { - return errors.New("dbus.Store: type mismatch") - } - err := Store(vs, ndest...) - if err != nil { - return errors.New("dbus.Store: type mismatch") - } - case reflect.Slice: - sv := reflect.ValueOf(src) - if sv.Kind() != reflect.Slice { - return errors.New("dbus.Store: type mismatch") - } - rv.Set(reflect.MakeSlice(rv.Type(), sv.Len(), sv.Len())) - for i := 0; i < sv.Len(); i++ { - if err := store(sv.Index(i).Interface(), rv.Index(i).Addr().Interface()); err != nil { - return err - } - } - case reflect.Map: - sv := reflect.ValueOf(src) - if sv.Kind() != reflect.Map { - return errors.New("dbus.Store: type mismatch") - } - keys := sv.MapKeys() - rv.Set(reflect.MakeMap(sv.Type())) - for _, key := range keys { - v := reflect.New(sv.Type().Elem()) - if err := store(v, sv.MapIndex(key).Interface()); err != nil { - return err - } - rv.SetMapIndex(key, v.Elem()) - } - default: - return errors.New("dbus.Store: type mismatch") - } - return nil - } else { - return errors.New("dbus.Store: type mismatch") - } -} - -func hasStruct(v interface{}) bool { - t := reflect.TypeOf(v) - for { - switch t.Kind() { - case reflect.Struct: - return true - case reflect.Slice, reflect.Ptr, reflect.Map: - t = t.Elem() - default: - return false - } - } -} - -// An ObjectPath is an object path as defined by the D-Bus spec. -type ObjectPath string - -// IsValid returns whether the object path is valid. -func (o ObjectPath) IsValid() bool { - s := string(o) - if len(s) == 0 { - return false - } - if s[0] != '/' { - return false - } - if s[len(s)-1] == '/' && len(s) != 1 { - return false - } - // probably not used, but technically possible - if s == "/" { - return true - } - split := strings.Split(s[1:], "/") - for _, v := range split { - if len(v) == 0 { - return false - } - for _, c := range v { - if !isMemberChar(c) { - return false - } - } - } - return true -} - -// A UnixFD is a Unix file descriptor sent over the wire. See the package-level -// documentation for more information about Unix file descriptor passsing. -type UnixFD int32 - -// A UnixFDIndex is the representation of a Unix file descriptor in a message. -type UnixFDIndex uint32 - -// alignment returns the alignment of values of type t. -func alignment(t reflect.Type) int { - switch t { - case variantType: - return 1 - case objectPathType: - return 4 - case signatureType: - return 1 - case interfacesType: // sometimes used for structs - return 8 - } - switch t.Kind() { - case reflect.Uint8: - return 1 - case reflect.Uint16, reflect.Int16: - return 2 - case reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map: - return 4 - case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct: - return 8 - case reflect.Ptr: - return alignment(t.Elem()) - } - return 1 -} - -// isKeyType returns whether t is a valid type for a D-Bus dict. -func isKeyType(t reflect.Type) bool { - switch t.Kind() { - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, - reflect.String: - - return true - } - return false -} - -// isValidInterface returns whether s is a valid name for an interface. -func isValidInterface(s string) bool { - if len(s) == 0 || len(s) > 255 || s[0] == '.' { - return false - } - elem := strings.Split(s, ".") - if len(elem) < 2 { - return false - } - for _, v := range elem { - if len(v) == 0 { - return false - } - if v[0] >= '0' && v[0] <= '9' { - return false - } - for _, c := range v { - if !isMemberChar(c) { - return false - } - } - } - return true -} - -// isValidMember returns whether s is a valid name for a member. -func isValidMember(s string) bool { - if len(s) == 0 || len(s) > 255 { - return false - } - i := strings.Index(s, ".") - if i != -1 { - return false - } - if s[0] >= '0' && s[0] <= '9' { - return false - } - for _, c := range s { - if !isMemberChar(c) { - return false - } - } - return true -} - -func isMemberChar(c rune) bool { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || c == '_' -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/decoder.go containerd-1.5.9/vendor/github.com/godbus/dbus/decoder.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/decoder.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/decoder.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -package dbus - -import ( - "encoding/binary" - "io" - "reflect" -) - -type decoder struct { - in io.Reader - order binary.ByteOrder - pos int -} - -// newDecoder returns a new decoder that reads values from in. The input is -// expected to be in the given byte order. -func newDecoder(in io.Reader, order binary.ByteOrder) *decoder { - dec := new(decoder) - dec.in = in - dec.order = order - return dec -} - -// align aligns the input to the given boundary and panics on error. -func (dec *decoder) align(n int) { - if dec.pos%n != 0 { - newpos := (dec.pos + n - 1) & ^(n - 1) - empty := make([]byte, newpos-dec.pos) - if _, err := io.ReadFull(dec.in, empty); err != nil { - panic(err) - } - dec.pos = newpos - } -} - -// Calls binary.Read(dec.in, dec.order, v) and panics on read errors. -func (dec *decoder) binread(v interface{}) { - if err := binary.Read(dec.in, dec.order, v); err != nil { - panic(err) - } -} - -func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) { - defer func() { - var ok bool - v := recover() - if err, ok = v.(error); ok { - if err == io.EOF || err == io.ErrUnexpectedEOF { - err = FormatError("unexpected EOF") - } - } - }() - vs = make([]interface{}, 0) - s := sig.str - for s != "" { - err, rem := validSingle(s, 0) - if err != nil { - return nil, err - } - v := dec.decode(s[:len(s)-len(rem)], 0) - vs = append(vs, v) - s = rem - } - return vs, nil -} - -func (dec *decoder) decode(s string, depth int) interface{} { - dec.align(alignment(typeFor(s))) - switch s[0] { - case 'y': - var b [1]byte - if _, err := dec.in.Read(b[:]); err != nil { - panic(err) - } - dec.pos++ - return b[0] - case 'b': - i := dec.decode("u", depth).(uint32) - switch { - case i == 0: - return false - case i == 1: - return true - default: - panic(FormatError("invalid value for boolean")) - } - case 'n': - var i int16 - dec.binread(&i) - dec.pos += 2 - return i - case 'i': - var i int32 - dec.binread(&i) - dec.pos += 4 - return i - case 'x': - var i int64 - dec.binread(&i) - dec.pos += 8 - return i - case 'q': - var i uint16 - dec.binread(&i) - dec.pos += 2 - return i - case 'u': - var i uint32 - dec.binread(&i) - dec.pos += 4 - return i - case 't': - var i uint64 - dec.binread(&i) - dec.pos += 8 - return i - case 'd': - var f float64 - dec.binread(&f) - dec.pos += 8 - return f - case 's': - length := dec.decode("u", depth).(uint32) - b := make([]byte, int(length)+1) - if _, err := io.ReadFull(dec.in, b); err != nil { - panic(err) - } - dec.pos += int(length) + 1 - return string(b[:len(b)-1]) - case 'o': - return ObjectPath(dec.decode("s", depth).(string)) - case 'g': - length := dec.decode("y", depth).(byte) - b := make([]byte, int(length)+1) - if _, err := io.ReadFull(dec.in, b); err != nil { - panic(err) - } - dec.pos += int(length) + 1 - sig, err := ParseSignature(string(b[:len(b)-1])) - if err != nil { - panic(err) - } - return sig - case 'v': - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - var variant Variant - sig := dec.decode("g", depth).(Signature) - if len(sig.str) == 0 { - panic(FormatError("variant signature is empty")) - } - err, rem := validSingle(sig.str, 0) - if err != nil { - panic(err) - } - if rem != "" { - panic(FormatError("variant signature has multiple types")) - } - variant.sig = sig - variant.value = dec.decode(sig.str, depth+1) - return variant - case 'h': - return UnixFDIndex(dec.decode("u", depth).(uint32)) - case 'a': - if len(s) > 1 && s[1] == '{' { - ksig := s[2:3] - vsig := s[3 : len(s)-1] - v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig))) - if depth >= 63 { - panic(FormatError("input exceeds container depth limit")) - } - length := dec.decode("u", depth).(uint32) - // Even for empty maps, the correct padding must be included - dec.align(8) - spos := dec.pos - for dec.pos < spos+int(length) { - dec.align(8) - if !isKeyType(v.Type().Key()) { - panic(InvalidTypeError{v.Type()}) - } - kv := dec.decode(ksig, depth+2) - vv := dec.decode(vsig, depth+2) - v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv)) - } - return v.Interface() - } - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - length := dec.decode("u", depth).(uint32) - v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) - // Even for empty arrays, the correct padding must be included - dec.align(alignment(typeFor(s[1:]))) - spos := dec.pos - for dec.pos < spos+int(length) { - ev := dec.decode(s[1:], depth+1) - v = reflect.Append(v, reflect.ValueOf(ev)) - } - return v.Interface() - case '(': - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - dec.align(8) - v := make([]interface{}, 0) - s = s[1 : len(s)-1] - for s != "" { - err, rem := validSingle(s, 0) - if err != nil { - panic(err) - } - ev := dec.decode(s[:len(s)-len(rem)], depth+1) - v = append(v, ev) - s = rem - } - return v - default: - panic(SignatureError{Sig: s}) - } -} - -// A FormatError is an error in the wire format. -type FormatError string - -func (e FormatError) Error() string { - return "dbus: wire format error: " + string(e) -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/doc.go containerd-1.5.9/vendor/github.com/godbus/dbus/doc.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/doc.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/doc.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* -Package dbus implements bindings to the D-Bus message bus system. - -To use the message bus API, you first need to connect to a bus (usually the -session or system bus). The acquired connection then can be used to call methods -on remote objects and emit or receive signals. Using the Export method, you can -arrange D-Bus methods calls to be directly translated to method calls on a Go -value. - -Conversion Rules - -For outgoing messages, Go types are automatically converted to the -corresponding D-Bus types. The following types are directly encoded as their -respective D-Bus equivalents: - - Go type | D-Bus type - ------------+----------- - byte | BYTE - bool | BOOLEAN - int16 | INT16 - uint16 | UINT16 - int32 | INT32 - uint32 | UINT32 - int64 | INT64 - uint64 | UINT64 - float64 | DOUBLE - string | STRING - ObjectPath | OBJECT_PATH - Signature | SIGNATURE - Variant | VARIANT - UnixFDIndex | UNIX_FD - -Slices and arrays encode as ARRAYs of their element type. - -Maps encode as DICTs, provided that their key type can be used as a key for -a DICT. - -Structs other than Variant and Signature encode as a STRUCT containing their -exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will -be skipped. - -Pointers encode as the value they're pointed to. - -Trying to encode any other type or a slice, map or struct containing an -unsupported type will result in an InvalidTypeError. - -For incoming messages, the inverse of these rules are used, with the exception -of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces -containing the struct fields in the correct order. The Store function can be -used to convert such values to Go structs. - -Unix FD passing - -Handling Unix file descriptors deserves special mention. To use them, you should -first check that they are supported on a connection by calling SupportsUnixFDs. -If it returns true, all method of Connection will translate messages containing -UnixFD's to messages that are accompanied by the given file descriptors with the -UnixFD values being substituted by the correct indices. Similarily, the indices -of incoming messages are automatically resolved. It shouldn't be necessary to use -UnixFDIndex. - -*/ -package dbus diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/encoder.go containerd-1.5.9/vendor/github.com/godbus/dbus/encoder.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/encoder.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/encoder.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -package dbus - -import ( - "bytes" - "encoding/binary" - "io" - "reflect" -) - -// An encoder encodes values to the D-Bus wire format. -type encoder struct { - out io.Writer - order binary.ByteOrder - pos int -} - -// NewEncoder returns a new encoder that writes to out in the given byte order. -func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { - return newEncoderAtOffset(out, 0, order) -} - -// newEncoderAtOffset returns a new encoder that writes to out in the given -// byte order. Specify the offset to initialize pos for proper alignment -// computation. -func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { - enc := new(encoder) - enc.out = out - enc.order = order - enc.pos = offset - return enc -} - -// Aligns the next output to be on a multiple of n. Panics on write errors. -func (enc *encoder) align(n int) { - pad := enc.padding(0, n) - if pad > 0 { - empty := make([]byte, pad) - if _, err := enc.out.Write(empty); err != nil { - panic(err) - } - enc.pos += pad - } -} - -// pad returns the number of bytes of padding, based on current position and additional offset. -// and alignment. -func (enc *encoder) padding(offset, algn int) int { - abs := enc.pos + offset - if abs%algn != 0 { - newabs := (abs + algn - 1) & ^(algn - 1) - return newabs - abs - } - return 0 -} - -// Calls binary.Write(enc.out, enc.order, v) and panics on write errors. -func (enc *encoder) binwrite(v interface{}) { - if err := binary.Write(enc.out, enc.order, v); err != nil { - panic(err) - } -} - -// Encode encodes the given values to the underyling reader. All written values -// are aligned properly as required by the D-Bus spec. -func (enc *encoder) Encode(vs ...interface{}) (err error) { - defer func() { - err, _ = recover().(error) - }() - for _, v := range vs { - enc.encode(reflect.ValueOf(v), 0) - } - return nil -} - -// encode encodes the given value to the writer and panics on error. depth holds -// the depth of the container nesting. -func (enc *encoder) encode(v reflect.Value, depth int) { - enc.align(alignment(v.Type())) - switch v.Kind() { - case reflect.Uint8: - var b [1]byte - b[0] = byte(v.Uint()) - if _, err := enc.out.Write(b[:]); err != nil { - panic(err) - } - enc.pos++ - case reflect.Bool: - if v.Bool() { - enc.encode(reflect.ValueOf(uint32(1)), depth) - } else { - enc.encode(reflect.ValueOf(uint32(0)), depth) - } - case reflect.Int16: - enc.binwrite(int16(v.Int())) - enc.pos += 2 - case reflect.Uint16: - enc.binwrite(uint16(v.Uint())) - enc.pos += 2 - case reflect.Int32: - enc.binwrite(int32(v.Int())) - enc.pos += 4 - case reflect.Uint32: - enc.binwrite(uint32(v.Uint())) - enc.pos += 4 - case reflect.Int64: - enc.binwrite(v.Int()) - enc.pos += 8 - case reflect.Uint64: - enc.binwrite(v.Uint()) - enc.pos += 8 - case reflect.Float64: - enc.binwrite(v.Float()) - enc.pos += 8 - case reflect.String: - enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth) - b := make([]byte, v.Len()+1) - copy(b, v.String()) - b[len(b)-1] = 0 - n, err := enc.out.Write(b) - if err != nil { - panic(err) - } - enc.pos += n - case reflect.Ptr: - enc.encode(v.Elem(), depth) - case reflect.Slice, reflect.Array: - if depth >= 64 { - panic(FormatError("input exceeds container depth limit")) - } - // Lookahead offset: 4 bytes for uint32 length (with alignment), - // plus alignment for elements. - n := enc.padding(0, 4) + 4 - offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) - - var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) - - for i := 0; i < v.Len(); i++ { - bufenc.encode(v.Index(i), depth+1) - } - enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) - length := buf.Len() - enc.align(alignment(v.Type().Elem())) - if _, err := buf.WriteTo(enc.out); err != nil { - panic(err) - } - enc.pos += length - case reflect.Struct: - if depth >= 64 && v.Type() != signatureType { - panic(FormatError("input exceeds container depth limit")) - } - switch t := v.Type(); t { - case signatureType: - str := v.Field(0) - enc.encode(reflect.ValueOf(byte(str.Len())), depth+1) - b := make([]byte, str.Len()+1) - copy(b, str.String()) - b[len(b)-1] = 0 - n, err := enc.out.Write(b) - if err != nil { - panic(err) - } - enc.pos += n - case variantType: - variant := v.Interface().(Variant) - enc.encode(reflect.ValueOf(variant.sig), depth+1) - enc.encode(reflect.ValueOf(variant.value), depth+1) - default: - for i := 0; i < v.Type().NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - enc.encode(v.Field(i), depth+1) - } - } - } - case reflect.Map: - // Maps are arrays of structures, so they actually increase the depth by - // 2. - if depth >= 63 { - panic(FormatError("input exceeds container depth limit")) - } - if !isKeyType(v.Type().Key()) { - panic(InvalidTypeError{v.Type()}) - } - keys := v.MapKeys() - // Lookahead offset: 4 bytes for uint32 length (with alignment), - // plus 8-byte alignment - n := enc.padding(0, 4) + 4 - offset := enc.pos + n + enc.padding(n, 8) - - var buf bytes.Buffer - bufenc := newEncoderAtOffset(&buf, offset, enc.order) - for _, k := range keys { - bufenc.align(8) - bufenc.encode(k, depth+2) - bufenc.encode(v.MapIndex(k), depth+2) - } - enc.encode(reflect.ValueOf(uint32(buf.Len())), depth) - length := buf.Len() - enc.align(8) - if _, err := buf.WriteTo(enc.out); err != nil { - panic(err) - } - enc.pos += length - default: - panic(InvalidTypeError{v.Type()}) - } -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/export.go containerd-1.5.9/vendor/github.com/godbus/dbus/export.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/export.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/export.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,411 +0,0 @@ -package dbus - -import ( - "errors" - "fmt" - "reflect" - "strings" -) - -var ( - errmsgInvalidArg = Error{ - "org.freedesktop.DBus.Error.InvalidArgs", - []interface{}{"Invalid type / number of args"}, - } - errmsgNoObject = Error{ - "org.freedesktop.DBus.Error.NoSuchObject", - []interface{}{"No such object"}, - } - errmsgUnknownMethod = Error{ - "org.freedesktop.DBus.Error.UnknownMethod", - []interface{}{"Unknown / invalid method"}, - } -) - -// exportWithMapping represents an exported struct along with a method name -// mapping to allow for exporting lower-case methods, etc. -type exportWithMapping struct { - export interface{} - - // Method name mapping; key -> struct method, value -> dbus method. - mapping map[string]string - - // Whether or not this export is for the entire subtree - includeSubtree bool -} - -// Sender is a type which can be used in exported methods to receive the message -// sender. -type Sender string - -func exportedMethod(export exportWithMapping, name string) reflect.Value { - if export.export == nil { - return reflect.Value{} - } - - // If a mapping was included in the export, check the map to see if we - // should be looking for a different method in the export. - if export.mapping != nil { - for key, value := range export.mapping { - if value == name { - name = key - break - } - - // Catch the case where a method is aliased but the client is calling - // the original, e.g. the "Foo" method was exported mapped to - // "foo," and dbus client called the original "Foo." - if key == name { - return reflect.Value{} - } - } - } - - value := reflect.ValueOf(export.export) - m := value.MethodByName(name) - - // Catch the case of attempting to call an unexported method - method, ok := value.Type().MethodByName(name) - - if !m.IsValid() || !ok || method.PkgPath != "" { - return reflect.Value{} - } - t := m.Type() - if t.NumOut() == 0 || - t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) { - - return reflect.Value{} - } - return m -} - -// searchHandlers will look through all registered handlers looking for one -// to handle the given path. If a verbatim one isn't found, it will check for -// a subtree registration for the path as well. -func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) { - conn.handlersLck.RLock() - defer conn.handlersLck.RUnlock() - - handlers, ok := conn.handlers[path] - if ok { - return handlers, ok - } - - // If handlers weren't found for this exact path, look for a matching subtree - // registration - handlers = make(map[string]exportWithMapping) - path = path[:strings.LastIndex(string(path), "/")] - for len(path) > 0 { - var subtreeHandlers map[string]exportWithMapping - subtreeHandlers, ok = conn.handlers[path] - if ok { - for iface, handler := range subtreeHandlers { - // Only include this handler if it registered for the subtree - if handler.includeSubtree { - handlers[iface] = handler - } - } - - break - } - - path = path[:strings.LastIndex(string(path), "/")] - } - - return handlers, ok -} - -// handleCall handles the given method call (i.e. looks if it's one of the -// pre-implemented ones and searches for a corresponding handler if not). -func (conn *Conn) handleCall(msg *Message) { - name := msg.Headers[FieldMember].value.(string) - path := msg.Headers[FieldPath].value.(ObjectPath) - ifaceName, hasIface := msg.Headers[FieldInterface].value.(string) - sender, hasSender := msg.Headers[FieldSender].value.(string) - serial := msg.serial - if ifaceName == "org.freedesktop.DBus.Peer" { - switch name { - case "Ping": - conn.sendReply(sender, serial) - case "GetMachineId": - conn.sendReply(sender, serial, conn.uuid) - default: - conn.sendError(errmsgUnknownMethod, sender, serial) - } - return - } - if len(name) == 0 { - conn.sendError(errmsgUnknownMethod, sender, serial) - } - - // Find the exported handler (if any) for this path - handlers, ok := conn.searchHandlers(path) - if !ok { - conn.sendError(errmsgNoObject, sender, serial) - return - } - - var m reflect.Value - if hasIface { - iface := handlers[ifaceName] - m = exportedMethod(iface, name) - } else { - for _, v := range handlers { - m = exportedMethod(v, name) - if m.IsValid() { - break - } - } - } - - if !m.IsValid() { - conn.sendError(errmsgUnknownMethod, sender, serial) - return - } - - t := m.Type() - vs := msg.Body - pointers := make([]interface{}, t.NumIn()) - decode := make([]interface{}, 0, len(vs)) - for i := 0; i < t.NumIn(); i++ { - tp := t.In(i) - val := reflect.New(tp) - pointers[i] = val.Interface() - if tp == reflect.TypeOf((*Sender)(nil)).Elem() { - val.Elem().SetString(sender) - } else if tp == reflect.TypeOf((*Message)(nil)).Elem() { - val.Elem().Set(reflect.ValueOf(*msg)) - } else { - decode = append(decode, pointers[i]) - } - } - - if len(decode) != len(vs) { - conn.sendError(errmsgInvalidArg, sender, serial) - return - } - - if err := Store(vs, decode...); err != nil { - conn.sendError(errmsgInvalidArg, sender, serial) - return - } - - // Extract parameters - params := make([]reflect.Value, len(pointers)) - for i := 0; i < len(pointers); i++ { - params[i] = reflect.ValueOf(pointers[i]).Elem() - } - - // Call method - ret := m.Call(params) - if em := ret[t.NumOut()-1].Interface().(*Error); em != nil { - conn.sendError(*em, sender, serial) - return - } - - if msg.Flags&FlagNoReplyExpected == 0 { - reply := new(Message) - reply.Type = TypeMethodReply - reply.serial = conn.getSerial() - reply.Headers = make(map[HeaderField]Variant) - if hasSender { - reply.Headers[FieldDestination] = msg.Headers[FieldSender] - } - reply.Headers[FieldReplySerial] = MakeVariant(msg.serial) - reply.Body = make([]interface{}, len(ret)-1) - for i := 0; i < len(ret)-1; i++ { - reply.Body[i] = ret[i].Interface() - } - if len(ret) != 1 { - reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) - } - conn.outLck.RLock() - if !conn.closed { - conn.out <- reply - } - conn.outLck.RUnlock() - } -} - -// Emit emits the given signal on the message bus. The name parameter must be -// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost". -func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error { - if !path.IsValid() { - return errors.New("dbus: invalid object path") - } - i := strings.LastIndex(name, ".") - if i == -1 { - return errors.New("dbus: invalid method name") - } - iface := name[:i] - member := name[i+1:] - if !isValidMember(member) { - return errors.New("dbus: invalid method name") - } - if !isValidInterface(iface) { - return errors.New("dbus: invalid interface name") - } - msg := new(Message) - msg.Type = TypeSignal - msg.serial = conn.getSerial() - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldInterface] = MakeVariant(iface) - msg.Headers[FieldMember] = MakeVariant(member) - msg.Headers[FieldPath] = MakeVariant(path) - msg.Body = values - if len(values) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) - } - conn.outLck.RLock() - defer conn.outLck.RUnlock() - if conn.closed { - return ErrClosed - } - conn.out <- msg - return nil -} - -// Export registers the given value to be exported as an object on the -// message bus. -// -// If a method call on the given path and interface is received, an exported -// method with the same name is called with v as the receiver if the -// parameters match and the last return value is of type *Error. If this -// *Error is not nil, it is sent back to the caller as an error. -// Otherwise, a method reply is sent with the other return values as its body. -// -// Any parameters with the special type Sender are set to the sender of the -// dbus message when the method is called. Parameters of this type do not -// contribute to the dbus signature of the method (i.e. the method is exposed -// as if the parameters of type Sender were not there). -// -// Similarly, any parameters with the type Message are set to the raw message -// received on the bus. Again, parameters of this type do not contribute to the -// dbus signature of the method. -// -// Every method call is executed in a new goroutine, so the method may be called -// in multiple goroutines at once. -// -// Method calls on the interface org.freedesktop.DBus.Peer will be automatically -// handled for every object. -// -// Passing nil as the first parameter will cause conn to cease handling calls on -// the given combination of path and interface. -// -// Export returns an error if path is not a valid path name. -func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { - return conn.ExportWithMap(v, nil, path, iface) -} - -// ExportWithMap works exactly like Export but provides the ability to remap -// method names (e.g. export a lower-case method). -// -// The keys in the map are the real method names (exported on the struct), and -// the values are the method names to be exported on DBus. -func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { - return conn.exportWithMap(v, mapping, path, iface, false) -} - -// ExportSubtree works exactly like Export but registers the given value for -// an entire subtree rather under the root path provided. -// -// In order to make this useful, one parameter in each of the value's exported -// methods should be a Message, in which case it will contain the raw message -// (allowing one to get access to the path that caused the method to be called). -// -// Note that more specific export paths take precedence over less specific. For -// example, a method call using the ObjectPath /foo/bar/baz will call a method -// exported on /foo/bar before a method exported on /foo. -func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error { - return conn.ExportSubtreeWithMap(v, nil, path, iface) -} - -// ExportSubtreeWithMap works exactly like ExportSubtree but provides the -// ability to remap method names (e.g. export a lower-case method). -// -// The keys in the map are the real method names (exported on the struct), and -// the values are the method names to be exported on DBus. -func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { - return conn.exportWithMap(v, mapping, path, iface, true) -} - -// exportWithMap is the worker function for all exports/registrations. -func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error { - if !path.IsValid() { - return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) - } - - conn.handlersLck.Lock() - defer conn.handlersLck.Unlock() - - // Remove a previous export if the interface is nil - if v == nil { - if _, ok := conn.handlers[path]; ok { - delete(conn.handlers[path], iface) - if len(conn.handlers[path]) == 0 { - delete(conn.handlers, path) - } - } - - return nil - } - - // If this is the first handler for this path, make a new map to hold all - // handlers for this path. - if _, ok := conn.handlers[path]; !ok { - conn.handlers[path] = make(map[string]exportWithMapping) - } - - // Finally, save this handler - conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree} - - return nil -} - -// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response. -func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) { - var r uint32 - err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r) - if err != nil { - return 0, err - } - return ReleaseNameReply(r), nil -} - -// RequestName calls org.freedesktop.DBus.RequestName and awaits a response. -func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) { - var r uint32 - err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r) - if err != nil { - return 0, err - } - return RequestNameReply(r), nil -} - -// ReleaseNameReply is the reply to a ReleaseName call. -type ReleaseNameReply uint32 - -const ( - ReleaseNameReplyReleased ReleaseNameReply = 1 + iota - ReleaseNameReplyNonExistent - ReleaseNameReplyNotOwner -) - -// RequestNameFlags represents the possible flags for a RequestName call. -type RequestNameFlags uint32 - -const ( - NameFlagAllowReplacement RequestNameFlags = 1 << iota - NameFlagReplaceExisting - NameFlagDoNotQueue -) - -// RequestNameReply is the reply to a RequestName call. -type RequestNameReply uint32 - -const ( - RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota - RequestNameReplyInQueue - RequestNameReplyExists - RequestNameReplyAlreadyOwner -) diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/homedir_dynamic.go containerd-1.5.9/vendor/github.com/godbus/dbus/homedir_dynamic.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/homedir_dynamic.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/homedir_dynamic.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -// +build !static_build - -package dbus - -import ( - "os/user" -) - -func lookupHomeDir() string { - u, err := user.Current() - if err != nil { - return "/" - } - return u.HomeDir -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/homedir.go containerd-1.5.9/vendor/github.com/godbus/dbus/homedir.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/homedir.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/homedir.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -package dbus - -import ( - "os" - "sync" -) - -var ( - homeDir string - homeDirLock sync.Mutex -) - -func getHomeDir() string { - homeDirLock.Lock() - defer homeDirLock.Unlock() - - if homeDir != "" { - return homeDir - } - - homeDir = os.Getenv("HOME") - if homeDir != "" { - return homeDir - } - - homeDir = lookupHomeDir() - return homeDir -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/homedir_static.go containerd-1.5.9/vendor/github.com/godbus/dbus/homedir_static.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/homedir_static.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/homedir_static.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -// +build static_build - -package dbus - -import ( - "bufio" - "os" - "strconv" - "strings" -) - -func lookupHomeDir() string { - myUid := os.Getuid() - - f, err := os.Open("/etc/passwd") - if err != nil { - return "/" - } - defer f.Close() - - s := bufio.NewScanner(f) - - for s.Scan() { - if err := s.Err(); err != nil { - break - } - - line := strings.TrimSpace(s.Text()) - if line == "" { - continue - } - - parts := strings.Split(line, ":") - - if len(parts) >= 6 { - uid, err := strconv.Atoi(parts[2]) - if err == nil && uid == myUid { - return parts[5] - } - } - } - - // Default to / if we can't get a better value - return "/" -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/LICENSE containerd-1.5.9/vendor/github.com/godbus/dbus/LICENSE --- containerd-1.2.6/vendor/github.com/godbus/dbus/LICENSE 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -Copyright (c) 2013, Georg Reinke (), Google -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/message.go containerd-1.5.9/vendor/github.com/godbus/dbus/message.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/message.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/message.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,346 +0,0 @@ -package dbus - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "reflect" - "strconv" -) - -const protoVersion byte = 1 - -// Flags represents the possible flags of a D-Bus message. -type Flags byte - -const ( - // FlagNoReplyExpected signals that the message is not expected to generate - // a reply. If this flag is set on outgoing messages, any possible reply - // will be discarded. - FlagNoReplyExpected Flags = 1 << iota - // FlagNoAutoStart signals that the message bus should not automatically - // start an application when handling this message. - FlagNoAutoStart -) - -// Type represents the possible types of a D-Bus message. -type Type byte - -const ( - TypeMethodCall Type = 1 + iota - TypeMethodReply - TypeError - TypeSignal - typeMax -) - -func (t Type) String() string { - switch t { - case TypeMethodCall: - return "method call" - case TypeMethodReply: - return "reply" - case TypeError: - return "error" - case TypeSignal: - return "signal" - } - return "invalid" -} - -// HeaderField represents the possible byte codes for the headers -// of a D-Bus message. -type HeaderField byte - -const ( - FieldPath HeaderField = 1 + iota - FieldInterface - FieldMember - FieldErrorName - FieldReplySerial - FieldDestination - FieldSender - FieldSignature - FieldUnixFDs - fieldMax -) - -// An InvalidMessageError describes the reason why a D-Bus message is regarded as -// invalid. -type InvalidMessageError string - -func (e InvalidMessageError) Error() string { - return "dbus: invalid message: " + string(e) -} - -// fieldType are the types of the various header fields. -var fieldTypes = [fieldMax]reflect.Type{ - FieldPath: objectPathType, - FieldInterface: stringType, - FieldMember: stringType, - FieldErrorName: stringType, - FieldReplySerial: uint32Type, - FieldDestination: stringType, - FieldSender: stringType, - FieldSignature: signatureType, - FieldUnixFDs: uint32Type, -} - -// requiredFields lists the header fields that are required by the different -// message types. -var requiredFields = [typeMax][]HeaderField{ - TypeMethodCall: {FieldPath, FieldMember}, - TypeMethodReply: {FieldReplySerial}, - TypeError: {FieldErrorName, FieldReplySerial}, - TypeSignal: {FieldPath, FieldInterface, FieldMember}, -} - -// Message represents a single D-Bus message. -type Message struct { - Type - Flags - Headers map[HeaderField]Variant - Body []interface{} - - serial uint32 -} - -type header struct { - Field byte - Variant -} - -// DecodeMessage tries to decode a single message in the D-Bus wire format -// from the given reader. The byte order is figured out from the first byte. -// The possibly returned error can be an error of the underlying reader, an -// InvalidMessageError or a FormatError. -func DecodeMessage(rd io.Reader) (msg *Message, err error) { - var order binary.ByteOrder - var hlength, length uint32 - var typ, flags, proto byte - var headers []header - - b := make([]byte, 1) - _, err = rd.Read(b) - if err != nil { - return - } - switch b[0] { - case 'l': - order = binary.LittleEndian - case 'B': - order = binary.BigEndian - default: - return nil, InvalidMessageError("invalid byte order") - } - - dec := newDecoder(rd, order) - dec.pos = 1 - - msg = new(Message) - vs, err := dec.Decode(Signature{"yyyuu"}) - if err != nil { - return nil, err - } - if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil { - return nil, err - } - msg.Type = Type(typ) - msg.Flags = Flags(flags) - - // get the header length separately because we need it later - b = make([]byte, 4) - _, err = io.ReadFull(rd, b) - if err != nil { - return nil, err - } - binary.Read(bytes.NewBuffer(b), order, &hlength) - if hlength+length+16 > 1<<27 { - return nil, InvalidMessageError("message is too long") - } - dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order) - dec.pos = 12 - vs, err = dec.Decode(Signature{"a(yv)"}) - if err != nil { - return nil, err - } - if err = Store(vs, &headers); err != nil { - return nil, err - } - - msg.Headers = make(map[HeaderField]Variant) - for _, v := range headers { - msg.Headers[HeaderField(v.Field)] = v.Variant - } - - dec.align(8) - body := make([]byte, int(length)) - if length != 0 { - _, err := io.ReadFull(rd, body) - if err != nil { - return nil, err - } - } - - if err = msg.IsValid(); err != nil { - return nil, err - } - sig, _ := msg.Headers[FieldSignature].value.(Signature) - if sig.str != "" { - buf := bytes.NewBuffer(body) - dec = newDecoder(buf, order) - vs, err := dec.Decode(sig) - if err != nil { - return nil, err - } - msg.Body = vs - } - - return -} - -// EncodeTo encodes and sends a message to the given writer. The byte order must -// be either binary.LittleEndian or binary.BigEndian. If the message is not -// valid or an error occurs when writing, an error is returned. -func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error { - if err := msg.IsValid(); err != nil { - return err - } - var vs [7]interface{} - switch order { - case binary.LittleEndian: - vs[0] = byte('l') - case binary.BigEndian: - vs[0] = byte('B') - default: - return errors.New("dbus: invalid byte order") - } - body := new(bytes.Buffer) - enc := newEncoder(body, order) - if len(msg.Body) != 0 { - enc.Encode(msg.Body...) - } - vs[1] = msg.Type - vs[2] = msg.Flags - vs[3] = protoVersion - vs[4] = uint32(len(body.Bytes())) - vs[5] = msg.serial - headers := make([]header, 0, len(msg.Headers)) - for k, v := range msg.Headers { - headers = append(headers, header{byte(k), v}) - } - vs[6] = headers - var buf bytes.Buffer - enc = newEncoder(&buf, order) - enc.Encode(vs[:]...) - enc.align(8) - body.WriteTo(&buf) - if buf.Len() > 1<<27 { - return InvalidMessageError("message is too long") - } - if _, err := buf.WriteTo(out); err != nil { - return err - } - return nil -} - -// IsValid checks whether msg is a valid message and returns an -// InvalidMessageError if it is not. -func (msg *Message) IsValid() error { - if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected) != 0 { - return InvalidMessageError("invalid flags") - } - if msg.Type == 0 || msg.Type >= typeMax { - return InvalidMessageError("invalid message type") - } - for k, v := range msg.Headers { - if k == 0 || k >= fieldMax { - return InvalidMessageError("invalid header") - } - if reflect.TypeOf(v.value) != fieldTypes[k] { - return InvalidMessageError("invalid type of header field") - } - } - for _, v := range requiredFields[msg.Type] { - if _, ok := msg.Headers[v]; !ok { - return InvalidMessageError("missing required header") - } - } - if path, ok := msg.Headers[FieldPath]; ok { - if !path.value.(ObjectPath).IsValid() { - return InvalidMessageError("invalid path name") - } - } - if iface, ok := msg.Headers[FieldInterface]; ok { - if !isValidInterface(iface.value.(string)) { - return InvalidMessageError("invalid interface name") - } - } - if member, ok := msg.Headers[FieldMember]; ok { - if !isValidMember(member.value.(string)) { - return InvalidMessageError("invalid member name") - } - } - if errname, ok := msg.Headers[FieldErrorName]; ok { - if !isValidInterface(errname.value.(string)) { - return InvalidMessageError("invalid error name") - } - } - if len(msg.Body) != 0 { - if _, ok := msg.Headers[FieldSignature]; !ok { - return InvalidMessageError("missing signature") - } - } - return nil -} - -// Serial returns the message's serial number. The returned value is only valid -// for messages received by eavesdropping. -func (msg *Message) Serial() uint32 { - return msg.serial -} - -// String returns a string representation of a message similar to the format of -// dbus-monitor. -func (msg *Message) String() string { - if err := msg.IsValid(); err != nil { - return "" - } - s := msg.Type.String() - if v, ok := msg.Headers[FieldSender]; ok { - s += " from " + v.value.(string) - } - if v, ok := msg.Headers[FieldDestination]; ok { - s += " to " + v.value.(string) - } - s += " serial " + strconv.FormatUint(uint64(msg.serial), 10) - if v, ok := msg.Headers[FieldReplySerial]; ok { - s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10) - } - if v, ok := msg.Headers[FieldUnixFDs]; ok { - s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10) - } - if v, ok := msg.Headers[FieldPath]; ok { - s += " path " + string(v.value.(ObjectPath)) - } - if v, ok := msg.Headers[FieldInterface]; ok { - s += " interface " + v.value.(string) - } - if v, ok := msg.Headers[FieldErrorName]; ok { - s += " error " + v.value.(string) - } - if v, ok := msg.Headers[FieldMember]; ok { - s += " member " + v.value.(string) - } - if len(msg.Body) != 0 { - s += "\n" - } - for i, v := range msg.Body { - s += " " + MakeVariant(v).String() - if i != len(msg.Body)-1 { - s += "\n" - } - } - return s -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/object.go containerd-1.5.9/vendor/github.com/godbus/dbus/object.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/object.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/object.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -package dbus - -import ( - "errors" - "strings" -) - -// BusObject is the interface of a remote object on which methods can be -// invoked. -type BusObject interface { - Call(method string, flags Flags, args ...interface{}) *Call - Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call - GetProperty(p string) (Variant, error) - Destination() string - Path() ObjectPath -} - -// Object represents a remote object on which methods can be invoked. -type Object struct { - conn *Conn - dest string - path ObjectPath -} - -// Call calls a method with (*Object).Go and waits for its reply. -func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { - return <-o.Go(method, flags, make(chan *Call, 1), args...).Done -} - -// Go calls a method with the given arguments asynchronously. It returns a -// Call structure representing this method call. The passed channel will -// return the same value once the call is done. If ch is nil, a new channel -// will be allocated. Otherwise, ch has to be buffered or Go will panic. -// -// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure -// is returned of which only the Err member is valid. -// -// If the method parameter contains a dot ('.'), the part before the last dot -// specifies the interface on which the method is called. -func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { - iface := "" - i := strings.LastIndex(method, ".") - if i != -1 { - iface = method[:i] - } - method = method[i+1:] - msg := new(Message) - msg.Type = TypeMethodCall - msg.serial = o.conn.getSerial() - msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldPath] = MakeVariant(o.path) - msg.Headers[FieldDestination] = MakeVariant(o.dest) - msg.Headers[FieldMember] = MakeVariant(method) - if iface != "" { - msg.Headers[FieldInterface] = MakeVariant(iface) - } - msg.Body = args - if len(args) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) - } - if msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 10) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Object).Go") - } - call := &Call{ - Destination: o.dest, - Path: o.path, - Method: method, - Args: args, - Done: ch, - } - o.conn.callsLck.Lock() - o.conn.calls[msg.serial] = call - o.conn.callsLck.Unlock() - o.conn.outLck.RLock() - if o.conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - o.conn.out <- msg - } - o.conn.outLck.RUnlock() - return call - } - o.conn.outLck.RLock() - defer o.conn.outLck.RUnlock() - if o.conn.closed { - return &Call{Err: ErrClosed} - } - o.conn.out <- msg - return &Call{Err: nil} -} - -// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given -// object. The property name must be given in interface.member notation. -func (o *Object) GetProperty(p string) (Variant, error) { - idx := strings.LastIndex(p, ".") - if idx == -1 || idx+1 == len(p) { - return Variant{}, errors.New("dbus: invalid property " + p) - } - - iface := p[:idx] - prop := p[idx+1:] - - result := Variant{} - err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) - - if err != nil { - return Variant{}, err - } - - return result, nil -} - -// Destination returns the destination that calls on o are sent to. -func (o *Object) Destination() string { - return o.dest -} - -// Path returns the path that calls on o are sent to. -func (o *Object) Path() ObjectPath { - return o.path -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/README.markdown containerd-1.5.9/vendor/github.com/godbus/dbus/README.markdown --- containerd-1.2.6/vendor/github.com/godbus/dbus/README.markdown 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/README.markdown 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -dbus ----- - -dbus is a simple library that implements native Go client bindings for the -D-Bus message bus system. - -### Features - -* Complete native implementation of the D-Bus message protocol -* Go-like API (channels for signals / asynchronous method calls, Goroutine-safe connections) -* Subpackages that help with the introspection / property interfaces - -### Installation - -This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: - -``` -go get github.com/godbus/dbus -``` - -If you want to use the subpackages, you can install them the same way. - -### Usage - -The complete package documentation and some simple examples are available at -[godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the -[_examples](https://github.com/godbus/dbus/tree/master/_examples) directory -gives a short overview over the basic usage. - -#### Projects using godbus -- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. - -Please note that the API is considered unstable for now and may change without -further notice. - -### License - -go.dbus is available under the Simplified BSD License; see LICENSE for the full -text. - -Nearly all of the credit for this library goes to github.com/guelfey/go.dbus. diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/sig.go containerd-1.5.9/vendor/github.com/godbus/dbus/sig.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/sig.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/sig.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,257 +0,0 @@ -package dbus - -import ( - "fmt" - "reflect" - "strings" -) - -var sigToType = map[byte]reflect.Type{ - 'y': byteType, - 'b': boolType, - 'n': int16Type, - 'q': uint16Type, - 'i': int32Type, - 'u': uint32Type, - 'x': int64Type, - 't': uint64Type, - 'd': float64Type, - 's': stringType, - 'g': signatureType, - 'o': objectPathType, - 'v': variantType, - 'h': unixFDIndexType, -} - -// Signature represents a correct type signature as specified by the D-Bus -// specification. The zero value represents the empty signature, "". -type Signature struct { - str string -} - -// SignatureOf returns the concatenation of all the signatures of the given -// values. It panics if one of them is not representable in D-Bus. -func SignatureOf(vs ...interface{}) Signature { - var s string - for _, v := range vs { - s += getSignature(reflect.TypeOf(v)) - } - return Signature{s} -} - -// SignatureOfType returns the signature of the given type. It panics if the -// type is not representable in D-Bus. -func SignatureOfType(t reflect.Type) Signature { - return Signature{getSignature(t)} -} - -// getSignature returns the signature of the given type and panics on unknown types. -func getSignature(t reflect.Type) string { - // handle simple types first - switch t.Kind() { - case reflect.Uint8: - return "y" - case reflect.Bool: - return "b" - case reflect.Int16: - return "n" - case reflect.Uint16: - return "q" - case reflect.Int32: - if t == unixFDType { - return "h" - } - return "i" - case reflect.Uint32: - if t == unixFDIndexType { - return "h" - } - return "u" - case reflect.Int64: - return "x" - case reflect.Uint64: - return "t" - case reflect.Float64: - return "d" - case reflect.Ptr: - return getSignature(t.Elem()) - case reflect.String: - if t == objectPathType { - return "o" - } - return "s" - case reflect.Struct: - if t == variantType { - return "v" - } else if t == signatureType { - return "g" - } - var s string - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if field.PkgPath == "" && field.Tag.Get("dbus") != "-" { - s += getSignature(t.Field(i).Type) - } - } - return "(" + s + ")" - case reflect.Array, reflect.Slice: - return "a" + getSignature(t.Elem()) - case reflect.Map: - if !isKeyType(t.Key()) { - panic(InvalidTypeError{t}) - } - return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}" - } - panic(InvalidTypeError{t}) -} - -// ParseSignature returns the signature represented by this string, or a -// SignatureError if the string is not a valid signature. -func ParseSignature(s string) (sig Signature, err error) { - if len(s) == 0 { - return - } - if len(s) > 255 { - return Signature{""}, SignatureError{s, "too long"} - } - sig.str = s - for err == nil && len(s) != 0 { - err, s = validSingle(s, 0) - } - if err != nil { - sig = Signature{""} - } - - return -} - -// ParseSignatureMust behaves like ParseSignature, except that it panics if s -// is not valid. -func ParseSignatureMust(s string) Signature { - sig, err := ParseSignature(s) - if err != nil { - panic(err) - } - return sig -} - -// Empty retruns whether the signature is the empty signature. -func (s Signature) Empty() bool { - return s.str == "" -} - -// Single returns whether the signature represents a single, complete type. -func (s Signature) Single() bool { - err, r := validSingle(s.str, 0) - return err != nil && r == "" -} - -// String returns the signature's string representation. -func (s Signature) String() string { - return s.str -} - -// A SignatureError indicates that a signature passed to a function or received -// on a connection is not a valid signature. -type SignatureError struct { - Sig string - Reason string -} - -func (e SignatureError) Error() string { - return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason) -} - -// Try to read a single type from this string. If it was successfull, err is nil -// and rem is the remaining unparsed part. Otherwise, err is a non-nil -// SignatureError and rem is "". depth is the current recursion depth which may -// not be greater than 64 and should be given as 0 on the first call. -func validSingle(s string, depth int) (err error, rem string) { - if s == "" { - return SignatureError{Sig: s, Reason: "empty signature"}, "" - } - if depth > 64 { - return SignatureError{Sig: s, Reason: "container nesting too deep"}, "" - } - switch s[0] { - case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h': - return nil, s[1:] - case 'a': - if len(s) > 1 && s[1] == '{' { - i := findMatching(s[1:], '{', '}') - if i == -1 { - return SignatureError{Sig: s, Reason: "unmatched '{'"}, "" - } - i++ - rem = s[i+1:] - s = s[2:i] - if err, _ = validSingle(s[:1], depth+1); err != nil { - return err, "" - } - err, nr := validSingle(s[1:], depth+1) - if err != nil { - return err, "" - } - if nr != "" { - return SignatureError{Sig: s, Reason: "too many types in dict"}, "" - } - return nil, rem - } - return validSingle(s[1:], depth+1) - case '(': - i := findMatching(s, '(', ')') - if i == -1 { - return SignatureError{Sig: s, Reason: "unmatched ')'"}, "" - } - rem = s[i+1:] - s = s[1:i] - for err == nil && s != "" { - err, s = validSingle(s, depth+1) - } - if err != nil { - rem = "" - } - return - } - return SignatureError{Sig: s, Reason: "invalid type character"}, "" -} - -func findMatching(s string, left, right rune) int { - n := 0 - for i, v := range s { - if v == left { - n++ - } else if v == right { - n-- - } - if n == 0 { - return i - } - } - return -1 -} - -// typeFor returns the type of the given signature. It ignores any left over -// characters and panics if s doesn't start with a valid type signature. -func typeFor(s string) (t reflect.Type) { - err, _ := validSingle(s, 0) - if err != nil { - panic(err) - } - - if t, ok := sigToType[s[0]]; ok { - return t - } - switch s[0] { - case 'a': - if s[1] == '{' { - i := strings.LastIndex(s, "}") - t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i])) - } else { - t = reflect.SliceOf(typeFor(s[1:])) - } - case '(': - t = interfacesType - } - return -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/transport_darwin.go containerd-1.5.9/vendor/github.com/godbus/dbus/transport_darwin.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/transport_darwin.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/transport_darwin.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -package dbus - -func (t *unixTransport) SendNullByte() error { - _, err := t.Write([]byte{0}) - return err -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/transport_generic.go containerd-1.5.9/vendor/github.com/godbus/dbus/transport_generic.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/transport_generic.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/transport_generic.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -package dbus - -import ( - "encoding/binary" - "errors" - "io" -) - -type genericTransport struct { - io.ReadWriteCloser -} - -func (t genericTransport) SendNullByte() error { - _, err := t.Write([]byte{0}) - return err -} - -func (t genericTransport) SupportsUnixFDs() bool { - return false -} - -func (t genericTransport) EnableUnixFDs() {} - -func (t genericTransport) ReadMessage() (*Message, error) { - return DecodeMessage(t) -} - -func (t genericTransport) SendMessage(msg *Message) error { - for _, v := range msg.Body { - if _, ok := v.(UnixFD); ok { - return errors.New("dbus: unix fd passing not enabled") - } - } - return msg.EncodeTo(t, binary.LittleEndian) -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -// The UnixCredentials system call is currently only implemented on Linux -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// https://golang.org/s/go1.4-syscall -// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys - -// Local implementation of the UnixCredentials system call for DragonFly BSD - -package dbus - -/* -#include -*/ -import "C" - -import ( - "io" - "os" - "syscall" - "unsafe" -) - -// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go -// http://golang.org/src/pkg/syscall/ztypes_dragonfly_amd64.go -type Ucred struct { - Pid int32 - Uid uint32 - Gid uint32 -} - -// http://golang.org/src/pkg/syscall/types_linux.go -// http://golang.org/src/pkg/syscall/types_dragonfly.go -// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/ucred.h -const ( - SizeofUcred = C.sizeof_struct_ucred -) - -// http://golang.org/src/pkg/syscall/sockcmsg_unix.go -func cmsgAlignOf(salen int) int { - // From http://golang.org/src/pkg/syscall/sockcmsg_unix.go - //salign := sizeofPtr - // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels - // still require 32-bit aligned access to network subsystem. - //if darwin64Bit || dragonfly64Bit { - // salign = 4 - //} - salign := 4 - return (salen + salign - 1) & ^(salign - 1) -} - -// http://golang.org/src/pkg/syscall/sockcmsg_unix.go -func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer { - return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr))) -} - -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// UnixCredentials encodes credentials into a socket control message -// for sending to another process. This can be used for -// authentication. -func UnixCredentials(ucred *Ucred) []byte { - b := make([]byte, syscall.CmsgSpace(SizeofUcred)) - h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) - h.Level = syscall.SOL_SOCKET - h.Type = syscall.SCM_CREDS - h.SetLen(syscall.CmsgLen(SizeofUcred)) - *((*Ucred)(cmsgData(h))) = *ucred - return b -} - -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// ParseUnixCredentials decodes a socket control message that contains -// credentials in a Ucred structure. To receive such a message, the -// SO_PASSCRED option must be enabled on the socket. -func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) { - if m.Header.Level != syscall.SOL_SOCKET { - return nil, syscall.EINVAL - } - if m.Header.Type != syscall.SCM_CREDS { - return nil, syscall.EINVAL - } - ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) - return &ucred, nil -} - -func (t *unixTransport) SendNullByte() error { - ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} - b := UnixCredentials(ucred) - _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) - if err != nil { - return err - } - if oobn != len(b) { - return io.ErrShortWrite - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unixcred_linux.go containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unixcred_linux.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unixcred_linux.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unixcred_linux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -// The UnixCredentials system call is currently only implemented on Linux -// http://golang.org/src/pkg/syscall/sockcmsg_linux.go -// https://golang.org/s/go1.4-syscall -// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys - -package dbus - -import ( - "io" - "os" - "syscall" -) - -func (t *unixTransport) SendNullByte() error { - ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())} - b := syscall.UnixCredentials(ucred) - _, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil) - if err != nil { - return err - } - if oobn != len(b) { - return io.ErrShortWrite - } - return nil -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unix.go containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unix.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/transport_unix.go 2019-04-05 18:39:47.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/transport_unix.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -//+build !windows - -package dbus - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "net" - "syscall" -) - -type oobReader struct { - conn *net.UnixConn - oob []byte - buf [4096]byte -} - -func (o *oobReader) Read(b []byte) (n int, err error) { - n, oobn, flags, _, err := o.conn.ReadMsgUnix(b, o.buf[:]) - if err != nil { - return n, err - } - if flags&syscall.MSG_CTRUNC != 0 { - return n, errors.New("dbus: control data truncated (too many fds received)") - } - o.oob = append(o.oob, o.buf[:oobn]...) - return n, nil -} - -type unixTransport struct { - *net.UnixConn - hasUnixFDs bool -} - -func newUnixTransport(keys string) (transport, error) { - var err error - - t := new(unixTransport) - abstract := getKey(keys, "abstract") - path := getKey(keys, "path") - switch { - case abstract == "" && path == "": - return nil, errors.New("dbus: invalid address (neither path nor abstract set)") - case abstract != "" && path == "": - t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: "@" + abstract, Net: "unix"}) - if err != nil { - return nil, err - } - return t, nil - case abstract == "" && path != "": - t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: path, Net: "unix"}) - if err != nil { - return nil, err - } - return t, nil - default: - return nil, errors.New("dbus: invalid address (both path and abstract set)") - } -} - -func init() { - transports["unix"] = newUnixTransport -} - -func (t *unixTransport) EnableUnixFDs() { - t.hasUnixFDs = true -} - -func (t *unixTransport) ReadMessage() (*Message, error) { - var ( - blen, hlen uint32 - csheader [16]byte - headers []header - order binary.ByteOrder - unixfds uint32 - ) - // To be sure that all bytes of out-of-band data are read, we use a special - // reader that uses ReadUnix on the underlying connection instead of Read - // and gathers the out-of-band data in a buffer. - rd := &oobReader{conn: t.UnixConn} - // read the first 16 bytes (the part of the header that has a constant size), - // from which we can figure out the length of the rest of the message - if _, err := io.ReadFull(rd, csheader[:]); err != nil { - return nil, err - } - switch csheader[0] { - case 'l': - order = binary.LittleEndian - case 'B': - order = binary.BigEndian - default: - return nil, InvalidMessageError("invalid byte order") - } - // csheader[4:8] -> length of message body, csheader[12:16] -> length of - // header fields (without alignment) - binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen) - binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen) - if hlen%8 != 0 { - hlen += 8 - (hlen % 8) - } - - // decode headers and look for unix fds - headerdata := make([]byte, hlen+4) - copy(headerdata, csheader[12:]) - if _, err := io.ReadFull(t, headerdata[4:]); err != nil { - return nil, err - } - dec := newDecoder(bytes.NewBuffer(headerdata), order) - dec.pos = 12 - vs, err := dec.Decode(Signature{"a(yv)"}) - if err != nil { - return nil, err - } - Store(vs, &headers) - for _, v := range headers { - if v.Field == byte(FieldUnixFDs) { - unixfds, _ = v.Variant.value.(uint32) - } - } - all := make([]byte, 16+hlen+blen) - copy(all, csheader[:]) - copy(all[16:], headerdata[4:]) - if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { - return nil, err - } - if unixfds != 0 { - if !t.hasUnixFDs { - return nil, errors.New("dbus: got unix fds on unsupported transport") - } - // read the fds from the OOB data - scms, err := syscall.ParseSocketControlMessage(rd.oob) - if err != nil { - return nil, err - } - if len(scms) != 1 { - return nil, errors.New("dbus: received more than one socket control message") - } - fds, err := syscall.ParseUnixRights(&scms[0]) - if err != nil { - return nil, err - } - msg, err := DecodeMessage(bytes.NewBuffer(all)) - if err != nil { - return nil, err - } - // substitute the values in the message body (which are indices for the - // array receiver via OOB) with the actual values - for i, v := range msg.Body { - if j, ok := v.(UnixFDIndex); ok { - if uint32(j) >= unixfds { - return nil, InvalidMessageError("invalid index for unix fd") - } - msg.Body[i] = UnixFD(fds[j]) - } - } - return msg, nil - } - return DecodeMessage(bytes.NewBuffer(all)) -} - -func (t *unixTransport) SendMessage(msg *Message) error { - fds := make([]int, 0) - for i, v := range msg.Body { - if fd, ok := v.(UnixFD); ok { - msg.Body[i] = UnixFDIndex(len(fds)) - fds = append(fds, int(fd)) - } - } - if len(fds) != 0 { - if !t.hasUnixFDs { - return errors.New("dbus: unix fd passing not enabled") - } - msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds))) - oob := syscall.UnixRights(fds...) - buf := new(bytes.Buffer) - msg.EncodeTo(buf, binary.LittleEndian) - n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil) - if err != nil { - return err - } - if n != buf.Len() || oobn != len(oob) { - return io.ErrShortWrite - } - } else { - if err := msg.EncodeTo(t, binary.LittleEndian); err != nil { - return nil - } - } - return nil -} - -func (t *unixTransport) SupportsUnixFDs() bool { - return true -} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_anonymous.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_anonymous.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_anonymous.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_anonymous.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,16 @@ +package dbus + +// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism. +func AuthAnonymous() Auth { + return &authAnonymous{} +} + +type authAnonymous struct{} + +func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) { + return []byte("ANONYMOUS"), nil, AuthOk +} + +func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) { + return nil, AuthError +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_external.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_external.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_external.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_external.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,26 @@ +package dbus + +import ( + "encoding/hex" +) + +// AuthExternal returns an Auth that authenticates as the given user with the +// EXTERNAL mechanism. +func AuthExternal(user string) Auth { + return authExternal{user} +} + +// AuthExternal implements the EXTERNAL authentication mechanism. +type authExternal struct { + user string +} + +func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) { + b := make([]byte, 2*len(a.user)) + hex.Encode(b, []byte(a.user)) + return []byte("EXTERNAL"), b, AuthOk +} + +func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) { + return nil, AuthError +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,252 @@ +package dbus + +import ( + "bufio" + "bytes" + "errors" + "io" + "os" + "strconv" +) + +// AuthStatus represents the Status of an authentication mechanism. +type AuthStatus byte + +const ( + // AuthOk signals that authentication is finished; the next command + // from the server should be an OK. + AuthOk AuthStatus = iota + + // AuthContinue signals that additional data is needed; the next command + // from the server should be a DATA. + AuthContinue + + // AuthError signals an error; the server sent invalid data or some + // other unexpected thing happened and the current authentication + // process should be aborted. + AuthError +) + +type authState byte + +const ( + waitingForData authState = iota + waitingForOk + waitingForReject +) + +// Auth defines the behaviour of an authentication mechanism. +type Auth interface { + // Return the name of the mechanism, the argument to the first AUTH command + // and the next status. + FirstData() (name, resp []byte, status AuthStatus) + + // Process the given DATA command, and return the argument to the DATA + // command and the next status. If len(resp) == 0, no DATA command is sent. + HandleData(data []byte) (resp []byte, status AuthStatus) +} + +// Auth authenticates the connection, trying the given list of authentication +// mechanisms (in that order). If nil is passed, the EXTERNAL and +// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private +// connections, this method must be called before sending any messages to the +// bus. Auth must not be called on shared connections. +func (conn *Conn) Auth(methods []Auth) error { + if methods == nil { + uid := strconv.Itoa(os.Getuid()) + methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} + } + in := bufio.NewReader(conn.transport) + err := conn.transport.SendNullByte() + if err != nil { + return err + } + err = authWriteLine(conn.transport, []byte("AUTH")) + if err != nil { + return err + } + s, err := authReadLine(in) + if err != nil { + return err + } + if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) { + return errors.New("dbus: authentication protocol error") + } + s = s[1:] + for _, v := range s { + for _, m := range methods { + if name, data, status := m.FirstData(); bytes.Equal(v, name) { + var ok bool + err = authWriteLine(conn.transport, []byte("AUTH"), v, data) + if err != nil { + return err + } + switch status { + case AuthOk: + err, ok = conn.tryAuth(m, waitingForOk, in) + case AuthContinue: + err, ok = conn.tryAuth(m, waitingForData, in) + default: + panic("dbus: invalid authentication status") + } + if err != nil { + return err + } + if ok { + if conn.transport.SupportsUnixFDs() { + err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD")) + if err != nil { + return err + } + line, err := authReadLine(in) + if err != nil { + return err + } + switch { + case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")): + conn.EnableUnixFDs() + conn.unixFD = true + case bytes.Equal(line[0], []byte("ERROR")): + default: + return errors.New("dbus: authentication protocol error") + } + } + err = authWriteLine(conn.transport, []byte("BEGIN")) + if err != nil { + return err + } + go conn.inWorker() + return nil + } + } + } + } + return errors.New("dbus: authentication failed") +} + +// tryAuth tries to authenticate with m as the mechanism, using state as the +// initial authState and in for reading input. It returns (nil, true) on +// success, (nil, false) on a REJECTED and (someErr, false) if some other +// error occurred. +func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) { + for { + s, err := authReadLine(in) + if err != nil { + return err, false + } + switch { + case state == waitingForData && string(s[0]) == "DATA": + if len(s) != 2 { + err = authWriteLine(conn.transport, []byte("ERROR")) + if err != nil { + return err, false + } + continue + } + data, status := m.HandleData(s[1]) + switch status { + case AuthOk, AuthContinue: + if len(data) != 0 { + err = authWriteLine(conn.transport, []byte("DATA"), data) + if err != nil { + return err, false + } + } + if status == AuthOk { + state = waitingForOk + } + case AuthError: + err = authWriteLine(conn.transport, []byte("ERROR")) + if err != nil { + return err, false + } + } + case state == waitingForData && string(s[0]) == "REJECTED": + return nil, false + case state == waitingForData && string(s[0]) == "ERROR": + err = authWriteLine(conn.transport, []byte("CANCEL")) + if err != nil { + return err, false + } + state = waitingForReject + case state == waitingForData && string(s[0]) == "OK": + if len(s) != 2 { + err = authWriteLine(conn.transport, []byte("CANCEL")) + if err != nil { + return err, false + } + state = waitingForReject + } + conn.uuid = string(s[1]) + return nil, true + case state == waitingForData: + err = authWriteLine(conn.transport, []byte("ERROR")) + if err != nil { + return err, false + } + case state == waitingForOk && string(s[0]) == "OK": + if len(s) != 2 { + err = authWriteLine(conn.transport, []byte("CANCEL")) + if err != nil { + return err, false + } + state = waitingForReject + } + conn.uuid = string(s[1]) + return nil, true + case state == waitingForOk && string(s[0]) == "REJECTED": + return nil, false + case state == waitingForOk && (string(s[0]) == "DATA" || + string(s[0]) == "ERROR"): + + err = authWriteLine(conn.transport, []byte("CANCEL")) + if err != nil { + return err, false + } + state = waitingForReject + case state == waitingForOk: + err = authWriteLine(conn.transport, []byte("ERROR")) + if err != nil { + return err, false + } + case state == waitingForReject && string(s[0]) == "REJECTED": + return nil, false + case state == waitingForReject: + return errors.New("dbus: authentication protocol error"), false + default: + panic("dbus: invalid auth state") + } + } +} + +// authReadLine reads a line and separates it into its fields. +func authReadLine(in *bufio.Reader) ([][]byte, error) { + data, err := in.ReadBytes('\n') + if err != nil { + return nil, err + } + data = bytes.TrimSuffix(data, []byte("\r\n")) + return bytes.Split(data, []byte{' '}), nil +} + +// authWriteLine writes the given line in the authentication protocol format +// (elements of data separated by a " " and terminated by "\r\n"). +func authWriteLine(out io.Writer, data ...[]byte) error { + buf := make([]byte, 0) + for i, v := range data { + buf = append(buf, v...) + if i != len(data)-1 { + buf = append(buf, ' ') + } + } + buf = append(buf, '\r') + buf = append(buf, '\n') + n, err := out.Write(buf) + if err != nil { + return err + } + if n != len(buf) { + return io.ErrUnexpectedEOF + } + return nil +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_sha1.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_sha1.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/auth_sha1.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/auth_sha1.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,102 @@ +package dbus + +import ( + "bufio" + "bytes" + "crypto/rand" + "crypto/sha1" + "encoding/hex" + "os" +) + +// AuthCookieSha1 returns an Auth that authenticates as the given user with the +// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home +// directory of the user. +func AuthCookieSha1(user, home string) Auth { + return authCookieSha1{user, home} +} + +type authCookieSha1 struct { + user, home string +} + +func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) { + b := make([]byte, 2*len(a.user)) + hex.Encode(b, []byte(a.user)) + return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue +} + +func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) { + challenge := make([]byte, len(data)/2) + _, err := hex.Decode(challenge, data) + if err != nil { + return nil, AuthError + } + b := bytes.Split(challenge, []byte{' '}) + if len(b) != 3 { + return nil, AuthError + } + context := b[0] + id := b[1] + svchallenge := b[2] + cookie := a.getCookie(context, id) + if cookie == nil { + return nil, AuthError + } + clchallenge := a.generateChallenge() + if clchallenge == nil { + return nil, AuthError + } + hash := sha1.New() + hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'})) + hexhash := make([]byte, 2*hash.Size()) + hex.Encode(hexhash, hash.Sum(nil)) + data = append(clchallenge, ' ') + data = append(data, hexhash...) + resp := make([]byte, 2*len(data)) + hex.Encode(resp, data) + return resp, AuthOk +} + +// getCookie searches for the cookie identified by id in context and returns +// the cookie content or nil. (Since HandleData can't return a specific error, +// but only whether an error occurred, this function also doesn't bother to +// return an error.) +func (a authCookieSha1) getCookie(context, id []byte) []byte { + file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context)) + if err != nil { + return nil + } + defer file.Close() + rd := bufio.NewReader(file) + for { + line, err := rd.ReadBytes('\n') + if err != nil { + return nil + } + line = line[:len(line)-1] + b := bytes.Split(line, []byte{' '}) + if len(b) != 3 { + return nil + } + if bytes.Equal(b[0], id) { + return b[2] + } + } +} + +// generateChallenge returns a random, hex-encoded challenge, or nil on error +// (see above). +func (a authCookieSha1) generateChallenge() []byte { + b := make([]byte, 16) + n, err := rand.Read(b) + if err != nil { + return nil + } + if n != 16 { + return nil + } + enc := make([]byte, 32) + hex.Encode(enc, b) + return enc +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/call.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/call.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/call.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/call.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,69 @@ +package dbus + +import ( + "context" + "errors" +) + +var errSignature = errors.New("dbus: mismatched signature") + +// Call represents a pending or completed method call. +type Call struct { + Destination string + Path ObjectPath + Method string + Args []interface{} + + // Strobes when the call is complete. + Done chan *Call + + // After completion, the error status. If this is non-nil, it may be an + // error message from the peer (with Error as its type) or some other error. + Err error + + // Holds the response once the call is done. + Body []interface{} + + // ResponseSequence stores the sequence number of the DBus message containing + // the call response (or error). This can be compared to the sequence number + // of other call responses and signals on this connection to determine their + // relative ordering on the underlying DBus connection. + // For errors, ResponseSequence is populated only if the error came from a + // DBusMessage that was received or if there was an error receiving. In case of + // failure to make the call, ResponseSequence will be NoSequence. + ResponseSequence Sequence + + // tracks context and canceler + ctx context.Context + ctxCanceler context.CancelFunc +} + +func (c *Call) Context() context.Context { + if c.ctx == nil { + return context.Background() + } + + return c.ctx +} + +func (c *Call) ContextCancel() { + if c.ctxCanceler != nil { + c.ctxCanceler() + } +} + +// Store stores the body of the reply into the provided pointers. It returns +// an error if the signatures of the body and retvalues don't match, or if +// the error status is not nil. +func (c *Call) Store(retvalues ...interface{}) error { + if c.Err != nil { + return c.Err + } + + return Store(c.Body, retvalues...) +} + +func (c *Call) done() { + c.Done <- c + c.ContextCancel() +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_darwin.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_darwin.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_darwin.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_darwin.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,37 @@ +package dbus + +import ( + "errors" + "fmt" + "os" + "os/exec" +) + +const defaultSystemBusAddress = "unix:path=/opt/local/var/run/dbus/system_bus_socket" + +func getSessionBusPlatformAddress() (string, error) { + cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET") + b, err := cmd.CombinedOutput() + + if err != nil { + return "", err + } + + if len(b) == 0 { + return "", errors.New("dbus: couldn't determine address of session bus") + } + + return "unix:path=" + string(b[:len(b)-1]), nil +} + +func getSystemBusPlatformAddress() string { + address := os.Getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET") + if address != "" { + return fmt.Sprintf("unix:path=%s", address) + } + return defaultSystemBusAddress +} + +func tryDiscoverDbusSessionBusAddress() string { + return "" +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,959 @@ +package dbus + +import ( + "context" + "errors" + "io" + "os" + "strings" + "sync" +) + +var ( + systemBus *Conn + systemBusLck sync.Mutex + sessionBus *Conn + sessionBusLck sync.Mutex +) + +// ErrClosed is the error returned by calls on a closed connection. +var ErrClosed = errors.New("dbus: connection closed by user") + +// Conn represents a connection to a message bus (usually, the system or +// session bus). +// +// Connections are either shared or private. Shared connections +// are shared between calls to the functions that return them. As a result, +// the methods Close, Auth and Hello must not be called on them. +// +// Multiple goroutines may invoke methods on a connection simultaneously. +type Conn struct { + transport + + ctx context.Context + cancelCtx context.CancelFunc + + closeOnce sync.Once + closeErr error + + busObj BusObject + unixFD bool + uuid string + + handler Handler + signalHandler SignalHandler + serialGen SerialGenerator + inInt Interceptor + outInt Interceptor + auth []Auth + + names *nameTracker + calls *callTracker + outHandler *outputHandler + + eavesdropped chan<- *Message + eavesdroppedLck sync.Mutex +} + +// SessionBus returns a shared connection to the session bus, connecting to it +// if not already done. +func SessionBus() (conn *Conn, err error) { + sessionBusLck.Lock() + defer sessionBusLck.Unlock() + if sessionBus != nil && + sessionBus.Connected() { + return sessionBus, nil + } + defer func() { + if conn != nil { + sessionBus = conn + } + }() + conn, err = ConnectSessionBus() + return +} + +func getSessionBusAddress() (string, error) { + if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" { + return address, nil + + } else if address := tryDiscoverDbusSessionBusAddress(); address != "" { + os.Setenv("DBUS_SESSION_BUS_ADDRESS", address) + return address, nil + } + return getSessionBusPlatformAddress() +} + +// SessionBusPrivate returns a new private connection to the session bus. +func SessionBusPrivate(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress() + if err != nil { + return nil, err + } + + return Dial(address, opts...) +} + +// SessionBusPrivate returns a new private connection to the session bus. +// +// Deprecated: use SessionBusPrivate with options instead. +func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { + return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler)) +} + +// SystemBus returns a shared connection to the system bus, connecting to it if +// not already done. +func SystemBus() (conn *Conn, err error) { + systemBusLck.Lock() + defer systemBusLck.Unlock() + if systemBus != nil && + systemBus.Connected() { + return systemBus, nil + } + defer func() { + if conn != nil { + systemBus = conn + } + }() + conn, err = ConnectSystemBus() + return +} + +// ConnectSessionBus connects to the session bus. +func ConnectSessionBus(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress() + if err != nil { + return nil, err + } + return Connect(address, opts...) +} + +// ConnectSystemBus connects to the system bus. +func ConnectSystemBus(opts ...ConnOption) (*Conn, error) { + return Connect(getSystemBusPlatformAddress(), opts...) +} + +// Connect connects to the given address. +// +// Returned connection is ready to use and doesn't require calling +// Auth and Hello methods to make it usable. +func Connect(address string, opts ...ConnOption) (*Conn, error) { + conn, err := Dial(address, opts...) + if err != nil { + return nil, err + } + if err = conn.Auth(conn.auth); err != nil { + _ = conn.Close() + return nil, err + } + if err = conn.Hello(); err != nil { + _ = conn.Close() + return nil, err + } + return conn, nil +} + +// SystemBusPrivate returns a new private connection to the system bus. +// Note: this connection is not ready to use. One must perform Auth and Hello +// on the connection before it is useable. +func SystemBusPrivate(opts ...ConnOption) (*Conn, error) { + return Dial(getSystemBusPlatformAddress(), opts...) +} + +// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. +// +// Deprecated: use SystemBusPrivate with options instead. +func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { + return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler)) +} + +// Dial establishes a new private connection to the message bus specified by address. +func Dial(address string, opts ...ConnOption) (*Conn, error) { + tr, err := getTransport(address) + if err != nil { + return nil, err + } + return newConn(tr, opts...) +} + +// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. +// +// Deprecated: use Dial with options instead. +func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { + return Dial(address, WithSignalHandler(signalHandler)) +} + +// ConnOption is a connection option. +type ConnOption func(conn *Conn) error + +// WithHandler overrides the default handler. +func WithHandler(handler Handler) ConnOption { + return func(conn *Conn) error { + conn.handler = handler + return nil + } +} + +// WithSignalHandler overrides the default signal handler. +func WithSignalHandler(handler SignalHandler) ConnOption { + return func(conn *Conn) error { + conn.signalHandler = handler + return nil + } +} + +// WithSerialGenerator overrides the default signals generator. +func WithSerialGenerator(gen SerialGenerator) ConnOption { + return func(conn *Conn) error { + conn.serialGen = gen + return nil + } +} + +// WithAuth sets authentication methods for the auth conversation. +func WithAuth(methods ...Auth) ConnOption { + return func(conn *Conn) error { + conn.auth = methods + return nil + } +} + +// Interceptor intercepts incoming and outgoing messages. +type Interceptor func(msg *Message) + +// WithIncomingInterceptor sets the given interceptor for incoming messages. +func WithIncomingInterceptor(interceptor Interceptor) ConnOption { + return func(conn *Conn) error { + conn.inInt = interceptor + return nil + } +} + +// WithOutgoingInterceptor sets the given interceptor for outgoing messages. +func WithOutgoingInterceptor(interceptor Interceptor) ConnOption { + return func(conn *Conn) error { + conn.outInt = interceptor + return nil + } +} + +// WithContext overrides the default context for the connection. +func WithContext(ctx context.Context) ConnOption { + return func(conn *Conn) error { + conn.ctx = ctx + return nil + } +} + +// NewConn creates a new private *Conn from an already established connection. +func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) { + return newConn(genericTransport{conn}, opts...) +} + +// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. +// +// Deprecated: use NewConn with options instead. +func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { + return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler)) +} + +// newConn creates a new *Conn from a transport. +func newConn(tr transport, opts ...ConnOption) (*Conn, error) { + conn := new(Conn) + conn.transport = tr + for _, opt := range opts { + if err := opt(conn); err != nil { + return nil, err + } + } + if conn.ctx == nil { + conn.ctx = context.Background() + } + conn.ctx, conn.cancelCtx = context.WithCancel(conn.ctx) + go func() { + <-conn.ctx.Done() + conn.Close() + }() + + conn.calls = newCallTracker() + if conn.handler == nil { + conn.handler = NewDefaultHandler() + } + if conn.signalHandler == nil { + conn.signalHandler = NewDefaultSignalHandler() + } + if conn.serialGen == nil { + conn.serialGen = newSerialGenerator() + } + conn.outHandler = &outputHandler{conn: conn} + conn.names = newNameTracker() + conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") + return conn, nil +} + +// BusObject returns the object owned by the bus daemon which handles +// administrative requests. +func (conn *Conn) BusObject() BusObject { + return conn.busObj +} + +// Close closes the connection. Any blocked operations will return with errors +// and the channels passed to Eavesdrop and Signal are closed. This method must +// not be called on shared connections. +func (conn *Conn) Close() error { + conn.closeOnce.Do(func() { + conn.outHandler.close() + if term, ok := conn.signalHandler.(Terminator); ok { + term.Terminate() + } + + if term, ok := conn.handler.(Terminator); ok { + term.Terminate() + } + + conn.eavesdroppedLck.Lock() + if conn.eavesdropped != nil { + close(conn.eavesdropped) + } + conn.eavesdroppedLck.Unlock() + + conn.cancelCtx() + + conn.closeErr = conn.transport.Close() + }) + return conn.closeErr +} + +// Context returns the context associated with the connection. The +// context will be cancelled when the connection is closed. +func (conn *Conn) Context() context.Context { + return conn.ctx +} + +// Connected returns whether conn is connected +func (conn *Conn) Connected() bool { + return conn.ctx.Err() == nil +} + +// Eavesdrop causes conn to send all incoming messages to the given channel +// without further processing. Method replies, errors and signals will not be +// sent to the appropriate channels and method calls will not be handled. If nil +// is passed, the normal behaviour is restored. +// +// The caller has to make sure that ch is sufficiently buffered; +// if a message arrives when a write to ch is not possible, the message is +// discarded. +func (conn *Conn) Eavesdrop(ch chan<- *Message) { + conn.eavesdroppedLck.Lock() + conn.eavesdropped = ch + conn.eavesdroppedLck.Unlock() +} + +// getSerial returns an unused serial. +func (conn *Conn) getSerial() uint32 { + return conn.serialGen.GetSerial() +} + +// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be +// called after authentication, but before sending any other messages to the +// bus. Hello must not be called for shared connections. +func (conn *Conn) Hello() error { + var s string + err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s) + if err != nil { + return err + } + conn.names.acquireUniqueConnectionName(s) + return nil +} + +// inWorker runs in an own goroutine, reading incoming messages from the +// transport and dispatching them appropriately. +func (conn *Conn) inWorker() { + sequenceGen := newSequenceGenerator() + for { + msg, err := conn.ReadMessage() + if err != nil { + if _, ok := err.(InvalidMessageError); !ok { + // Some read error occurred (usually EOF); we can't really do + // anything but to shut down all stuff and returns errors to all + // pending replies. + conn.Close() + conn.calls.finalizeAllWithError(sequenceGen, err) + return + } + // invalid messages are ignored + continue + } + conn.eavesdroppedLck.Lock() + if conn.eavesdropped != nil { + select { + case conn.eavesdropped <- msg: + default: + } + conn.eavesdroppedLck.Unlock() + continue + } + conn.eavesdroppedLck.Unlock() + dest, _ := msg.Headers[FieldDestination].value.(string) + found := dest == "" || + !conn.names.uniqueNameIsKnown() || + conn.names.isKnownName(dest) + if !found { + // Eavesdropped a message, but no channel for it is registered. + // Ignore it. + continue + } + + if conn.inInt != nil { + conn.inInt(msg) + } + sequence := sequenceGen.next() + switch msg.Type { + case TypeError: + conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg)) + case TypeMethodReply: + conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg)) + case TypeSignal: + conn.handleSignal(sequence, msg) + case TypeMethodCall: + go conn.handleCall(msg) + } + + } +} + +func (conn *Conn) handleSignal(sequence Sequence, msg *Message) { + iface := msg.Headers[FieldInterface].value.(string) + member := msg.Headers[FieldMember].value.(string) + // as per http://dbus.freedesktop.org/doc/dbus-specification.html , + // sender is optional for signals. + sender, _ := msg.Headers[FieldSender].value.(string) + if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { + if member == "NameLost" { + // If we lost the name on the bus, remove it from our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the lost name") + } + conn.names.loseName(name) + } else if member == "NameAcquired" { + // If we acquired the name on the bus, add it to our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the acquired name") + } + conn.names.acquireName(name) + } + } + signal := &Signal{ + Sender: sender, + Path: msg.Headers[FieldPath].value.(ObjectPath), + Name: iface + "." + member, + Body: msg.Body, + Sequence: sequence, + } + conn.signalHandler.DeliverSignal(iface, member, signal) +} + +// Names returns the list of all names that are currently owned by this +// connection. The slice is always at least one element long, the first element +// being the unique name of the connection. +func (conn *Conn) Names() []string { + return conn.names.listKnownNames() +} + +// Object returns the object identified by the given destination name and path. +func (conn *Conn) Object(dest string, path ObjectPath) BusObject { + return &Object{conn, dest, path} +} + +func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { + if msg.serial == 0 { + msg.serial = conn.getSerial() + } + if conn.outInt != nil { + conn.outInt(msg) + } + err := conn.outHandler.sendAndIfClosed(msg, ifClosed) + conn.calls.handleSendError(msg, err) + if err != nil { + conn.serialGen.RetireSerial(msg.serial) + } else if msg.Type != TypeMethodCall { + conn.serialGen.RetireSerial(msg.serial) + } +} + +// Send sends the given message to the message bus. You usually don't need to +// use this; use the higher-level equivalents (Call / Go, Emit and Export) +// instead. If msg is a method call and NoReplyExpected is not set, a non-nil +// call is returned and the same value is sent to ch (which must be buffered) +// once the call is complete. Otherwise, ch is ignored and a Call structure is +// returned of which only the Err member is valid. +func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { + return conn.send(context.Background(), msg, ch) +} + +// SendWithContext acts like Send but takes a context +func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call { + return conn.send(ctx, msg, ch) +} + +func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call { + if ctx == nil { + panic("nil context") + } + if ch == nil { + ch = make(chan *Call, 1) + } else if cap(ch) == 0 { + panic("dbus: unbuffered channel passed to (*Conn).Send") + } + + var call *Call + ctx, canceler := context.WithCancel(ctx) + msg.serial = conn.getSerial() + if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { + call = new(Call) + call.Destination, _ = msg.Headers[FieldDestination].value.(string) + call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) + iface, _ := msg.Headers[FieldInterface].value.(string) + member, _ := msg.Headers[FieldMember].value.(string) + call.Method = iface + "." + member + call.Args = msg.Body + call.Done = ch + call.ctx = ctx + call.ctxCanceler = canceler + conn.calls.track(msg.serial, call) + go func() { + <-ctx.Done() + conn.calls.handleSendError(msg, ctx.Err()) + }() + conn.sendMessageAndIfClosed(msg, func() { + conn.calls.handleSendError(msg, ErrClosed) + canceler() + }) + } else { + canceler() + call = &Call{Err: nil, Done: ch} + ch <- call + conn.sendMessageAndIfClosed(msg, func() { + call = &Call{Err: ErrClosed} + }) + } + return call +} + +// sendError creates an error message corresponding to the parameters and sends +// it to conn.out. +func (conn *Conn) sendError(err error, dest string, serial uint32) { + var e *Error + switch em := err.(type) { + case Error: + e = &em + case *Error: + e = em + case DBusError: + name, body := em.DBusError() + e = NewError(name, body) + default: + e = MakeFailedError(err) + } + msg := new(Message) + msg.Type = TypeError + msg.Headers = make(map[HeaderField]Variant) + if dest != "" { + msg.Headers[FieldDestination] = MakeVariant(dest) + } + msg.Headers[FieldErrorName] = MakeVariant(e.Name) + msg.Headers[FieldReplySerial] = MakeVariant(serial) + msg.Body = e.Body + if len(e.Body) > 0 { + msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) + } + conn.sendMessageAndIfClosed(msg, nil) +} + +// sendReply creates a method reply message corresponding to the parameters and +// sends it to conn.out. +func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { + msg := new(Message) + msg.Type = TypeMethodReply + msg.Headers = make(map[HeaderField]Variant) + if dest != "" { + msg.Headers[FieldDestination] = MakeVariant(dest) + } + msg.Headers[FieldReplySerial] = MakeVariant(serial) + msg.Body = values + if len(values) > 0 { + msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) + } + conn.sendMessageAndIfClosed(msg, nil) +} + +// AddMatchSignal registers the given match rule to receive broadcast +// signals based on their contents. +func (conn *Conn) AddMatchSignal(options ...MatchOption) error { + return conn.AddMatchSignalContext(context.Background(), options...) +} + +// AddMatchSignalContext acts like AddMatchSignal but takes a context. +func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error { + options = append([]MatchOption{withMatchType("signal")}, options...) + return conn.busObj.CallWithContext( + ctx, + "org.freedesktop.DBus.AddMatch", 0, + formatMatchOptions(options), + ).Store() +} + +// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal. +func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error { + return conn.RemoveMatchSignalContext(context.Background(), options...) +} + +// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context. +func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error { + options = append([]MatchOption{withMatchType("signal")}, options...) + return conn.busObj.CallWithContext( + ctx, + "org.freedesktop.DBus.RemoveMatch", 0, + formatMatchOptions(options), + ).Store() +} + +// Signal registers the given channel to be passed all received signal messages. +// +// Multiple of these channels can be registered at the same time. +// +// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a +// channel for eavesdropped messages, this channel receives all signals, and +// none of the channels passed to Signal will receive any signals. +// +// Panics if the signal handler is not a `SignalRegistrar`. +func (conn *Conn) Signal(ch chan<- *Signal) { + handler, ok := conn.signalHandler.(SignalRegistrar) + if !ok { + panic("cannot use this method with a non SignalRegistrar handler") + } + handler.AddSignal(ch) +} + +// RemoveSignal removes the given channel from the list of the registered channels. +// +// Panics if the signal handler is not a `SignalRegistrar`. +func (conn *Conn) RemoveSignal(ch chan<- *Signal) { + handler, ok := conn.signalHandler.(SignalRegistrar) + if !ok { + panic("cannot use this method with a non SignalRegistrar handler") + } + handler.RemoveSignal(ch) +} + +// SupportsUnixFDs returns whether the underlying transport supports passing of +// unix file descriptors. If this is false, method calls containing unix file +// descriptors will return an error and emitted signals containing them will +// not be sent. +func (conn *Conn) SupportsUnixFDs() bool { + return conn.unixFD +} + +// Error represents a D-Bus message of type Error. +type Error struct { + Name string + Body []interface{} +} + +func NewError(name string, body []interface{}) *Error { + return &Error{name, body} +} + +func (e Error) Error() string { + if len(e.Body) >= 1 { + s, ok := e.Body[0].(string) + if ok { + return s + } + } + return e.Name +} + +// Signal represents a D-Bus message of type Signal. The name member is given in +// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. +type Signal struct { + Sender string + Path ObjectPath + Name string + Body []interface{} + Sequence Sequence +} + +// transport is a D-Bus transport. +type transport interface { + // Read and Write raw data (for example, for the authentication protocol). + io.ReadWriteCloser + + // Send the initial null byte used for the EXTERNAL mechanism. + SendNullByte() error + + // Returns whether this transport supports passing Unix FDs. + SupportsUnixFDs() bool + + // Signal the transport that Unix FD passing is enabled for this connection. + EnableUnixFDs() + + // Read / send a message, handling things like Unix FDs. + ReadMessage() (*Message, error) + SendMessage(*Message) error +} + +var ( + transports = make(map[string]func(string) (transport, error)) +) + +func getTransport(address string) (transport, error) { + var err error + var t transport + + addresses := strings.Split(address, ";") + for _, v := range addresses { + i := strings.IndexRune(v, ':') + if i == -1 { + err = errors.New("dbus: invalid bus address (no transport)") + continue + } + f := transports[v[:i]] + if f == nil { + err = errors.New("dbus: invalid bus address (invalid or unsupported transport)") + continue + } + t, err = f(v[i+1:]) + if err == nil { + return t, nil + } + } + return nil, err +} + +// getKey gets a key from a the list of keys. Returns "" on error / not found... +func getKey(s, key string) string { + for _, keyEqualsValue := range strings.Split(s, ",") { + keyValue := strings.SplitN(keyEqualsValue, "=", 2) + if len(keyValue) == 2 && keyValue[0] == key { + return keyValue[1] + } + } + return "" +} + +type outputHandler struct { + conn *Conn + sendLck sync.Mutex + closed struct { + isClosed bool + lck sync.RWMutex + } +} + +func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error { + h.closed.lck.RLock() + defer h.closed.lck.RUnlock() + if h.closed.isClosed { + if ifClosed != nil { + ifClosed() + } + return nil + } + h.sendLck.Lock() + defer h.sendLck.Unlock() + return h.conn.SendMessage(msg) +} + +func (h *outputHandler) close() { + h.closed.lck.Lock() + defer h.closed.lck.Unlock() + h.closed.isClosed = true +} + +type serialGenerator struct { + lck sync.Mutex + nextSerial uint32 + serialUsed map[uint32]bool +} + +func newSerialGenerator() *serialGenerator { + return &serialGenerator{ + serialUsed: map[uint32]bool{0: true}, + nextSerial: 1, + } +} + +func (gen *serialGenerator) GetSerial() uint32 { + gen.lck.Lock() + defer gen.lck.Unlock() + n := gen.nextSerial + for gen.serialUsed[n] { + n++ + } + gen.serialUsed[n] = true + gen.nextSerial = n + 1 + return n +} + +func (gen *serialGenerator) RetireSerial(serial uint32) { + gen.lck.Lock() + defer gen.lck.Unlock() + delete(gen.serialUsed, serial) +} + +type nameTracker struct { + lck sync.RWMutex + unique string + names map[string]struct{} +} + +func newNameTracker() *nameTracker { + return &nameTracker{names: map[string]struct{}{}} +} +func (tracker *nameTracker) acquireUniqueConnectionName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + tracker.unique = name +} +func (tracker *nameTracker) acquireName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + tracker.names[name] = struct{}{} +} +func (tracker *nameTracker) loseName(name string) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + delete(tracker.names, name) +} + +func (tracker *nameTracker) uniqueNameIsKnown() bool { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + return tracker.unique != "" +} +func (tracker *nameTracker) isKnownName(name string) bool { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + _, ok := tracker.names[name] + return ok || name == tracker.unique +} +func (tracker *nameTracker) listKnownNames() []string { + tracker.lck.RLock() + defer tracker.lck.RUnlock() + out := make([]string, 0, len(tracker.names)+1) + out = append(out, tracker.unique) + for k := range tracker.names { + out = append(out, k) + } + return out +} + +type callTracker struct { + calls map[uint32]*Call + lck sync.RWMutex +} + +func newCallTracker() *callTracker { + return &callTracker{calls: map[uint32]*Call{}} +} + +func (tracker *callTracker) track(sn uint32, call *Call) { + tracker.lck.Lock() + tracker.calls[sn] = call + tracker.lck.Unlock() +} + +func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 { + serial := msg.Headers[FieldReplySerial].value.(uint32) + tracker.lck.RLock() + _, ok := tracker.calls[serial] + tracker.lck.RUnlock() + if ok { + tracker.finalizeWithBody(serial, sequence, msg.Body) + } + return serial +} + +func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 { + serial := msg.Headers[FieldReplySerial].value.(uint32) + tracker.lck.RLock() + _, ok := tracker.calls[serial] + tracker.lck.RUnlock() + if ok { + name, _ := msg.Headers[FieldErrorName].value.(string) + tracker.finalizeWithError(serial, sequence, Error{name, msg.Body}) + } + return serial +} + +func (tracker *callTracker) handleSendError(msg *Message, err error) { + if err == nil { + return + } + tracker.lck.RLock() + _, ok := tracker.calls[msg.serial] + tracker.lck.RUnlock() + if ok { + tracker.finalizeWithError(msg.serial, NoSequence, err) + } +} + +// finalize was the only func that did not strobe Done +func (tracker *callTracker) finalize(sn uint32) { + tracker.lck.Lock() + defer tracker.lck.Unlock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + c.ContextCancel() + } +} + +func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) { + tracker.lck.Lock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + } + tracker.lck.Unlock() + if ok { + c.Body = body + c.ResponseSequence = sequence + c.done() + } +} + +func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) { + tracker.lck.Lock() + c, ok := tracker.calls[sn] + if ok { + delete(tracker.calls, sn) + } + tracker.lck.Unlock() + if ok { + c.Err = err + c.ResponseSequence = sequence + c.done() + } +} + +func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) { + tracker.lck.Lock() + closedCalls := make([]*Call, 0, len(tracker.calls)) + for sn := range tracker.calls { + closedCalls = append(closedCalls, tracker.calls[sn]) + } + tracker.calls = map[uint32]*Call{} + tracker.lck.Unlock() + for _, call := range closedCalls { + call.Err = err + call.ResponseSequence = sequenceGen.next() + call.done() + } +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_other.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_other.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_other.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_other.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,93 @@ +// +build !darwin + +package dbus + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "os/user" + "path" + "strings" +) + +var execCommand = exec.Command + +func getSessionBusPlatformAddress() (string, error) { + cmd := execCommand("dbus-launch") + b, err := cmd.CombinedOutput() + + if err != nil { + return "", err + } + + i := bytes.IndexByte(b, '=') + j := bytes.IndexByte(b, '\n') + + if i == -1 || j == -1 || i > j { + return "", errors.New("dbus: couldn't determine address of session bus") + } + + env, addr := string(b[0:i]), string(b[i+1:j]) + os.Setenv(env, addr) + + return addr, nil +} + +// tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session +// and return the value of its DBUS_SESSION_BUS_ADDRESS. +// It tries different techniques employed by different operating systems, +// returning the first valid address it finds, or an empty string. +// +// * /run/user//bus if this exists, it *is* the bus socket. present on +// Ubuntu 18.04 +// * /run/user//dbus-session: if this exists, it can be parsed for the bus +// address. present on Ubuntu 16.04 +// +// See https://dbus.freedesktop.org/doc/dbus-launch.1.html +func tryDiscoverDbusSessionBusAddress() string { + if runtimeDirectory, err := getRuntimeDirectory(); err == nil { + + if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) { + // if /run/user//bus exists, that file itself + // *is* the unix socket, so return its path + return fmt.Sprintf("unix:path=%s", runUserBusFile) + } + if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) { + // if /run/user//dbus-session exists, it's a + // text file // containing the address of the socket, e.g.: + // DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG + + if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil { + fileContent := string(f) + + prefix := "DBUS_SESSION_BUS_ADDRESS=" + + if strings.HasPrefix(fileContent, prefix) { + address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r") + return address + } + } + } + } + return "" +} + +func getRuntimeDirectory() (string, error) { + if currentUser, err := user.Current(); err != nil { + return "", err + } else { + return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil + } +} + +func fileExists(filename string) bool { + if _, err := os.Stat(filename); !os.IsNotExist(err) { + return true + } else { + return false + } +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_unix.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_unix.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_unix.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_unix.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,17 @@ +//+build !windows,!solaris,!darwin + +package dbus + +import ( + "os" +) + +const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket" + +func getSystemBusPlatformAddress() string { + address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") + if address != "" { + return address + } + return defaultSystemBusAddress +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_windows.go containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_windows.go --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/conn_windows.go 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/conn_windows.go 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,15 @@ +//+build windows + +package dbus + +import "os" + +const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434" + +func getSystemBusPlatformAddress() string { + address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") + if address != "" { + return address + } + return defaultSystemBusAddress +} diff -Nru containerd-1.2.6/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md containerd-1.5.9/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md --- containerd-1.2.6/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ containerd-1.5.9/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md 2022-01-05 17:30:58.000000000 +0000 @@ -0,0 +1,50 @@ +# How to Contribute + +## Getting Started + +- Fork the repository on GitHub +- Read the [README](README.markdown) for build and test instructions +- Play with the project, submit bugs, submit patches! + +## Contribution Flow + +This is a rough outline of what a contributor's workflow looks like: + +- Create a topic branch from where you want to base your work (usually master). +- Make commits of logical units. +- Make sure your commit messages are in the proper format (see below). +- Push your changes to a topic branch in your fork of the repository. +- Make sure the tests pass, and add any new tests as appropriate. +- Submit a pull request to the original repository. + +Thanks for your contributions! + +### Format of the Commit Message + +We follow a rough convention for commit messages that is designed to answer two +questions: what changed and why. The subject line should feature the what and +the body of the commit should describe the why. + +``` +scripts: add the test-cluster command + +this uses tmux to setup a test cluster that you can easily kill and +start for debugging. + +Fixes #38 +``` + +The format can be described more formally as follows: + +``` +: + + + +